diff --git a/.github/actions/build-jtreg/action.yml b/.github/actions/build-jtreg/action.yml new file mode 100644 index 0000000000000..3abfa260c1767 --- /dev/null +++ b/.github/actions/build-jtreg/action.yml @@ -0,0 +1,68 @@ +# +# 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. 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. +# + +name: 'Build JTReg' +description: 'Build JTReg' + +runs: + using: composite + steps: + - name: 'Get JTReg version configuration' + id: version + uses: ./.github/actions/config + with: + var: JTREG_VERSION + + - name: 'Check cache for already built JTReg' + id: get-cached + uses: actions/cache@v4 + with: + path: jtreg/installed + key: jtreg-${{ steps.version.outputs.value }} + + - name: 'Checkout the JTReg source' + uses: actions/checkout@v4 + with: + repository: openjdk/jtreg + ref: jtreg-${{ steps.version.outputs.value }} + path: jtreg/src + if: (steps.get-cached.outputs.cache-hit != 'true') + + - name: 'Build JTReg' + run: | + # Build JTReg and move files to the proper locations + bash make/build.sh --jdk "$JAVA_HOME_17_X64" + mkdir ../installed + mv build/images/jtreg/* ../installed + working-directory: jtreg/src + shell: bash + if: (steps.get-cached.outputs.cache-hit != 'true') + + - name: 'Upload JTReg artifact' + uses: actions/upload-artifact@v4 + with: + name: bundles-jtreg-${{ steps.version.outputs.value }} + path: jtreg/installed + retention-days: 1 diff --git a/.github/actions/get-jtreg/action.yml b/.github/actions/get-jtreg/action.yml index faedcc18807c0..78a3a4c9edddd 100644 --- a/.github/actions/get-jtreg/action.yml +++ b/.github/actions/get-jtreg/action.yml @@ -24,7 +24,7 @@ # name: 'Get JTReg' -description: 'Download JTReg from cache or source location' +description: 'Get JTReg' outputs: path: description: 'Path to the installed JTReg' @@ -39,36 +39,12 @@ runs: with: var: JTREG_VERSION - - name: 'Check cache for JTReg' - id: get-cached-jtreg - uses: actions/cache@v4 + - name: 'Download JTReg artifact' + id: download-jtreg + uses: actions/download-artifact@v4 with: + name: bundles-jtreg-${{ steps.version.outputs.value }} path: jtreg/installed - key: jtreg-${{ steps.version.outputs.value }} - - - name: 'Checkout the JTReg source' - uses: actions/checkout@v4 - with: - repository: openjdk/jtreg - ref: jtreg-${{ steps.version.outputs.value }} - path: jtreg/src - if: steps.get-cached-jtreg.outputs.cache-hit != 'true' - - - name: 'Build JTReg' - run: | - # If runner architecture is x64 set JAVA_HOME_17_X64 otherwise set to JAVA_HOME_17_arm64 - if [[ '${{ runner.arch }}' == 'X64' ]]; then - JDK="$JAVA_HOME_17_X64" - else - JDK="$JAVA_HOME_17_arm64" - fi - # Build JTReg and move files to the proper locations - bash make/build.sh --jdk "$JDK" - mkdir ../installed - mv build/images/jtreg/* ../installed - working-directory: jtreg/src - shell: bash - if: steps.get-cached-jtreg.outputs.cache-hit != 'true' - name: 'Export path to where JTReg is installed' id: path-name diff --git a/.github/scripts/gen-build-failure-report.sh b/.github/scripts/gen-build-failure-report.sh index fd3215fc7fe2d..2dda69a3f331b 100644 --- a/.github/scripts/gen-build-failure-report.sh +++ b/.github/scripts/gen-build-failure-report.sh @@ -24,12 +24,19 @@ # questions. # +# Import common utils +. .github/scripts/report-utils.sh + GITHUB_STEP_SUMMARY="$1" BUILD_DIR="$(ls -d build/*)" # Send signal to the do-build action that we failed touch "$BUILD_DIR/build-failure" +# Collect hs_errs for build-time crashes, e.g. javac, jmod, jlink, CDS. +# These usually land in make/ +hs_err_files=$(ls make/hs_err*.log 2> /dev/null || true) + ( echo '### :boom: Build failure summary' echo '' @@ -46,6 +53,20 @@ touch "$BUILD_DIR/build-failure" echo '' echo '' + for hs_err in $hs_err_files; do + echo "
View HotSpot error log: "$hs_err"" + echo '' + echo '```' + echo "$hs_err:" + echo '' + cat "$hs_err" + echo '```' + echo '
' + echo '' + done + echo '' echo ':arrow_right: To see the entire test log, click the job in the list to the left. To download logs, see the `failure-logs` [artifact above](#artifacts).' ) >> $GITHUB_STEP_SUMMARY + +truncate_summary diff --git a/.github/scripts/gen-test-results.sh b/.github/scripts/gen-test-results.sh index 9e85eef4dc08d..bdf3eb3b9cbc5 100644 --- a/.github/scripts/gen-test-results.sh +++ b/.github/scripts/gen-test-results.sh @@ -24,6 +24,9 @@ # questions. # +# Import common utils +. .github/scripts/report-utils.sh + GITHUB_STEP_SUMMARY="$1" test_suite_name=$(cat build/run-test-prebuilt/test-support/test-last-ids.txt) @@ -89,18 +92,6 @@ for test in $failures $errors; do fi done >> $GITHUB_STEP_SUMMARY -# With many failures, the summary can easily exceed 1024 kB, the limit set by Github -# Trim it down if so. -summary_size=$(wc -c < $GITHUB_STEP_SUMMARY) -if [[ $summary_size -gt 1000000 ]]; then - # Trim to below 1024 kB, and cut off after the last detail group - head -c 1000000 $GITHUB_STEP_SUMMARY | tac | sed -n -e '/<\/details>/,$ p' | tac > $GITHUB_STEP_SUMMARY.tmp - mv $GITHUB_STEP_SUMMARY.tmp $GITHUB_STEP_SUMMARY - ( - echo '' - echo ':x: **WARNING: Summary is too large and has been truncated.**' - echo '' - ) >> $GITHUB_STEP_SUMMARY -fi - echo ':arrow_right: To see the entire test log, click the job in the list to the left.' >> $GITHUB_STEP_SUMMARY + +truncate_summary diff --git a/.github/scripts/report-utils.sh b/.github/scripts/report-utils.sh new file mode 100644 index 0000000000000..da5b6c04b3cbe --- /dev/null +++ b/.github/scripts/report-utils.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# 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. +# + +function truncate_summary() { + # With large hs_errs, the summary can easily exceed 1024 kB, the limit set by Github + # Trim it down if so. + summary_size=$(wc -c < $GITHUB_STEP_SUMMARY) + if [[ $summary_size -gt 1000000 ]]; then + # Trim to below 1024 kB, and cut off after the last detail group + head -c 1000000 $GITHUB_STEP_SUMMARY | tac | sed -n -e '/<\/details>/,$ p' | tac > $GITHUB_STEP_SUMMARY.tmp + mv $GITHUB_STEP_SUMMARY.tmp $GITHUB_STEP_SUMMARY + ( + echo '' + echo ':x: **WARNING: Summary is too large and has been truncated.**' + echo '' + ) >> $GITHUB_STEP_SUMMARY + fi +} diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index 29750b485e4b4..8e97ff4439f67 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -84,7 +84,7 @@ jobs: - target-cpu: riscv64 gnu-arch: riscv64 debian-arch: riscv64 - debian-repository: https://snapshot.debian.org/archive/debian/20240228T034848Z/ + debian-repository: https://httpredir.debian.org/debian/ debian-version: sid tolerate-sysroot-errors: true @@ -131,6 +131,7 @@ jobs: id: create-sysroot run: > sudo debootstrap + --no-merged-usr --arch=${{ matrix.debian-arch }} --verbose --include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype-dev,libpng-dev @@ -151,6 +152,9 @@ jobs: rm -rf sysroot/usr/{sbin,bin,share} rm -rf sysroot/usr/lib/{apt,gcc,udev,systemd} rm -rf sysroot/usr/libexec/gcc + # /{bin,sbin,lib}/ are not symbolic links to /usr/{bin,sbin,lib}/ when debootstrap with --no-merged-usr + rm -rf sysroot/{sbin,bin} + rm -rf sysroot/lib/{udev,systemd} if: steps.create-sysroot.outcome == 'success' && steps.get-cached-sysroot.outputs.cache-hit != 'true' - name: 'Remove broken sysroot' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d5958853701ca..00f64d2aedf59 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -54,8 +54,8 @@ jobs: ### Determine platforms to include ### - select: - name: 'Select platforms' + prepare: + name: 'Prepare the run' runs-on: ubuntu-22.04 env: # List of platforms to exclude by default @@ -73,7 +73,19 @@ jobs: docs: ${{ steps.include.outputs.docs }} steps: - # This function must be inlined in main.yml, or we'd be forced to checkout the repo + - name: 'Checkout the scripts' + uses: actions/checkout@v4 + with: + sparse-checkout: | + .github + make/conf/github-actions.conf + + - name: 'Build JTReg' + id: jtreg + uses: ./.github/actions/build-jtreg + + # TODO: Now that we are checking out the repo scripts, we can put the following code + # into a separate file - name: 'Check what jobs to run' id: include run: | @@ -149,18 +161,18 @@ jobs: build-linux-x64: name: linux-x64 - needs: select + needs: prepare uses: ./.github/workflows/build-linux.yml with: platform: linux-x64 gcc-major-version: '10' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.linux-x64 == 'true' + if: needs.prepare.outputs.linux-x64 == 'true' build-linux-x86-hs: name: linux-x86-hs - needs: select + needs: prepare uses: ./.github/workflows/build-linux.yml with: platform: linux-x86 @@ -174,11 +186,11 @@ jobs: extra-conf-options: '--with-target-bits=32 --enable-fallback-linker --enable-libffi-bundling' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.linux-x86-hs == 'true' + if: needs.prepare.outputs.linux-x86-hs == 'true' build-linux-x64-hs-nopch: name: linux-x64-hs-nopch - needs: select + needs: prepare uses: ./.github/workflows/build-linux.yml with: platform: linux-x64 @@ -188,11 +200,11 @@ jobs: extra-conf-options: '--disable-precompiled-headers' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.linux-x64-variants == 'true' + if: needs.prepare.outputs.linux-x64-variants == 'true' build-linux-x64-hs-zero: name: linux-x64-hs-zero - needs: select + needs: prepare uses: ./.github/workflows/build-linux.yml with: platform: linux-x64 @@ -202,11 +214,11 @@ jobs: extra-conf-options: '--with-jvm-variants=zero --disable-precompiled-headers' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.linux-x64-variants == 'true' + if: needs.prepare.outputs.linux-x64-variants == 'true' build-linux-x64-hs-minimal: name: linux-x64-hs-minimal - needs: select + needs: prepare uses: ./.github/workflows/build-linux.yml with: platform: linux-x64 @@ -216,11 +228,11 @@ jobs: extra-conf-options: '--with-jvm-variants=minimal --disable-precompiled-headers' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.linux-x64-variants == 'true' + if: needs.prepare.outputs.linux-x64-variants == 'true' build-linux-x64-hs-optimized: name: linux-x64-hs-optimized - needs: select + needs: prepare uses: ./.github/workflows/build-linux.yml with: platform: linux-x64 @@ -231,32 +243,31 @@ jobs: extra-conf-options: '--with-debug-level=optimized --disable-precompiled-headers' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.linux-x64-variants == 'true' + if: needs.prepare.outputs.linux-x64-variants == 'true' build-linux-cross-compile: name: linux-cross-compile - needs: - - select + needs: prepare uses: ./.github/workflows/build-cross-compile.yml with: gcc-major-version: '10' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.linux-cross-compile == 'true' + if: needs.prepare.outputs.linux-cross-compile == 'true' build-alpine-linux-x64: name: alpine-linux-x64 - needs: select + needs: prepare uses: ./.github/workflows/build-alpine-linux.yml with: platform: alpine-linux-x64 configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.alpine-linux-x64 == 'true' + if: needs.prepare.outputs.alpine-linux-x64 == 'true' build-macos-x64: name: macos-x64 - needs: select + needs: prepare uses: ./.github/workflows/build-macos.yml with: platform: macos-x64 @@ -264,11 +275,11 @@ jobs: xcode-toolset-version: '14.3.1' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.macos-x64 == 'true' + if: needs.prepare.outputs.macos-x64 == 'true' build-macos-aarch64: name: macos-aarch64 - needs: select + needs: prepare uses: ./.github/workflows/build-macos.yml with: platform: macos-aarch64 @@ -276,11 +287,11 @@ jobs: xcode-toolset-version: '14.3.1' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.macos-aarch64 == 'true' + if: needs.prepare.outputs.macos-aarch64 == 'true' build-windows-x64: name: windows-x64 - needs: select + needs: prepare uses: ./.github/workflows/build-windows.yml with: platform: windows-x64 @@ -288,11 +299,11 @@ jobs: msvc-toolset-architecture: 'x86.x64' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.windows-x64 == 'true' + if: needs.prepare.outputs.windows-x64 == 'true' build-windows-aarch64: name: windows-aarch64 - needs: select + needs: prepare uses: ./.github/workflows/build-windows.yml with: platform: windows-aarch64 @@ -302,11 +313,11 @@ jobs: extra-conf-options: '--openjdk-target=aarch64-unknown-cygwin' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.windows-aarch64 == 'true' + if: needs.prepare.outputs.windows-aarch64 == 'true' build-docs: name: docs - needs: select + needs: prepare uses: ./.github/workflows/build-linux.yml with: platform: linux-x64 @@ -318,7 +329,7 @@ jobs: gcc-major-version: '10' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.docs == 'true' + if: needs.prepare.outputs.docs == 'true' ### ### Test jobs @@ -363,48 +374,3 @@ jobs: platform: windows-x64 bootjdk-platform: windows-x64 runs-on: windows-2019 - - # Remove bundles so they are not misconstrued as binary distributions from the JDK project - remove-bundles: - name: 'Remove bundle artifacts' - runs-on: ubuntu-22.04 - if: always() - needs: - - build-linux-x64 - - build-linux-x86-hs - - build-linux-x64-hs-nopch - - build-linux-x64-hs-zero - - build-linux-x64-hs-minimal - - build-linux-x64-hs-optimized - - build-linux-cross-compile - - build-alpine-linux-x64 - - build-macos-x64 - - build-macos-aarch64 - - build-windows-x64 - - build-windows-aarch64 - - test-linux-x64 - - test-macos-x64 - - test-macos-aarch64 - - test-windows-x64 - - steps: - - name: 'Remove bundle artifacts' - run: | - # Find and remove all bundle artifacts - # 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?per_page=100')" - 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/doc/building.html b/doc/building.html index c91d876246cde..63af224584ac3 100644 --- a/doc/building.html +++ b/doc/building.html @@ -2016,10 +2016,18 @@

Spaces in Path

have short paths. You can run fsutil file setshortname in -cmd on certain directories, such as -Microsoft Visual Studio or Windows Kits, to -assign arbitrary short paths so configure can access -them.

+cmd on directories to assign arbitrary short paths so +configure can access them. If the result says "Access +denied", it may be that there are processes running in that directory; +in this case, you can reboot Windows in safe mode and run the command on +those directories again.

+

The only directories required to have short paths are +Microsoft Visual Studio and Windows Kits; the +rest of the "contains space" warnings from configure, such +as IntelliJ IDEA, can be ignored. You can choose any short +name; once it is set, configure's tools like +cygpath can convert the directory with spaces to your +chosen short name and pass it to the build system.

Getting Help

If none of the suggestions in this document helps you, or if you find what you believe is a bug in the build system, please contact the Build diff --git a/doc/building.md b/doc/building.md index 47ad9e7c72b4c..466e8d7edf89a 100644 --- a/doc/building.md +++ b/doc/building.md @@ -1800,9 +1800,17 @@ temporarily. On Windows, when configuring, `fixpath.sh` may report that some directory names have spaces. Usually, it assumes those directories have [short paths](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/fsutil-8dot3name). -You can run `fsutil file setshortname` in `cmd` on certain directories, such as -`Microsoft Visual Studio` or `Windows Kits`, to assign arbitrary short paths so -`configure` can access them. +You can run `fsutil file setshortname` in `cmd` on directories to assign +arbitrary short paths so `configure` can access them. If the result says "Access +denied", it may be that there are processes running in that directory; in this +case, you can reboot Windows in safe mode and run the command on those directories +again. + +The only directories required to have short paths are `Microsoft Visual Studio` +and `Windows Kits`; the rest of the "contains space" warnings from `configure`, +such as `IntelliJ IDEA`, can be ignored. You can choose any short name; once it +is set, `configure`'s tools like `cygpath` can convert the directory with spaces +to your chosen short name and pass it to the build system. ### Getting Help diff --git a/doc/testing.html b/doc/testing.html index c56dfa3118833..6285fab1682e4 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -72,6 +72,9 @@

Testing the JDK

  • Non-US locale
  • PKCS11 Tests
  • +
  • Testing with +alternative security providers
  • Client UI Tests
  • @@ -434,7 +437,7 @@

    FAILURE_HANDLER_TIMEOUT

    Sets the argument -timeoutHandlerTimeout for JTReg. The default value is 0. This is only valid if the failure handler is built.

    -

    JTREG_TEST_THREAD_FACTORY

    +

    TEST_THREAD_FACTORY

    Sets the -testThreadFactory for JTReg. It should be the fully qualified classname of a class which implements java.util.concurrent.ThreadFactory. One such implementation @@ -586,6 +589,18 @@

    PKCS11 Tests

    JTREG="JAVA_OPTIONS=-Djdk.test.lib.artifacts.nsslib-linux_aarch64=/path/to/NSS-libs"

    For more notes about the PKCS11 tests, please refer to test/jdk/sun/security/pkcs11/README.

    +

    Testing with +alternative security providers

    +

    Some security tests use a hardcoded provider for +KeyFactory, Cipher, +KeyPairGenerator, KeyGenerator, +AlgorithmParameterGenerator, KeyAgreement, +Mac, MessageDigest, SecureRandom, +Signature, AlgorithmParameters, +Configuration, Policy, or +SecretKeyFactory objects. Specify the +-Dtest.provider.name=NAME property to use a different +provider for the service(s).

    Client UI Tests

    System key shortcuts

    Some Client UI tests use key sequences which may be reserved by the diff --git a/doc/testing.md b/doc/testing.md index 351745c9293c5..351690c5e601c 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -380,7 +380,7 @@ Defaults to 4. Sets the argument `-timeoutHandlerTimeout` for JTReg. The default value is 0. This is only valid if the failure handler is built. -#### JTREG_TEST_THREAD_FACTORY +#### TEST_THREAD_FACTORY Sets the `-testThreadFactory` for JTReg. It should be the fully qualified classname of a class which implements `java.util.concurrent.ThreadFactory`. One @@ -603,6 +603,15 @@ $ make test TEST="jtreg:sun/security/pkcs11/Secmod/AddTrustedCert.java" \ For more notes about the PKCS11 tests, please refer to test/jdk/sun/security/pkcs11/README. +### Testing with alternative security providers + +Some security tests use a hardcoded provider for `KeyFactory`, `Cipher`, +`KeyPairGenerator`, `KeyGenerator`, `AlgorithmParameterGenerator`, +`KeyAgreement`, `Mac`, `MessageDigest`, `SecureRandom`, `Signature`, +`AlgorithmParameters`, `Configuration`, `Policy`, or `SecretKeyFactory` objects. +Specify the `-Dtest.provider.name=NAME` property to use a different provider for +the service(s). + ### Client UI Tests #### System key shortcuts diff --git a/make/Global.gmk b/make/Global.gmk index 6b97b7ad05940..16a5b05cccbe3 100644 --- a/make/Global.gmk +++ b/make/Global.gmk @@ -102,6 +102,7 @@ help: $(info $(_) # method is 'auto', 'ignore' or 'fail' (default)) $(info $(_) TEST="test1 ..." # Use the given test descriptor(s) for testing, e.g.) $(info $(_) # make test TEST="jdk_lang gtest:all") + $(info $(_) TEST_DEPS="dependency1 ..." # Specify additional dependencies for running tests, e.g docs-jdk $(info $(_) JTREG="OPT1=x;OPT2=y" # Control the JTREG test harness, use 'make test-only JTREG=help' to list) $(info $(_) GTEST="OPT1=x;OPT2=y" # Control the GTEST test harness, use 'make test-only GTEST=help' to list) $(info $(_) MICRO="OPT1=x;OPT2=y" # Control the MICRO test harness, use 'make test-only MICRO=help' to list) diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk index 2471d82d6dbfb..eea593a80db95 100644 --- a/make/InitSupport.gmk +++ b/make/InitSupport.gmk @@ -50,7 +50,7 @@ ifeq ($(HAS_SPEC), ) # Make control variables, handled by Init.gmk INIT_CONTROL_VARIABLES += LOG CONF CONF_NAME SPEC JOBS TEST_JOBS CONF_CHECK \ - COMPARE_BUILD JTREG GTEST MICRO TEST_OPTS TEST_VM_OPTS + COMPARE_BUILD JTREG GTEST MICRO TEST_OPTS TEST_VM_OPTS TEST_DEPS # All known make control variables MAKE_CONTROL_VARIABLES := $(INIT_CONTROL_VARIABLES) TEST JDK_FILTER SPEC_FILTER diff --git a/make/Main.gmk b/make/Main.gmk index 4b3efaf651ec9..25dfba7d36c08 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -785,13 +785,13 @@ $(eval $(call SetupTarget, build-microbenchmark, \ $(eval $(call SetupTarget, test, \ MAKEFILE := RunTests, \ ARGS := TEST="$(TEST)", \ - DEPS := jdk-image test-image, \ + DEPS := jdk-image test-image $(TEST_DEPS), \ )) $(eval $(call SetupTarget, exploded-test, \ MAKEFILE := RunTests, \ ARGS := TEST="$(TEST)" JDK_IMAGE_DIR=$(JDK_OUTPUTDIR), \ - DEPS := exploded-image test-image, \ + DEPS := exploded-image test-image $(TEST_DEPS), \ )) ifeq ($(JCOV_ENABLED), true) @@ -1110,8 +1110,8 @@ else test-make-compile-commands: compile-commands # Declare dependency for all generated test targets - $(foreach t, $(filter-out test-make%, $(ALL_TEST_TARGETS)), $(eval $t: jdk-image test-image)) - $(foreach t, $(ALL_EXPLODED_TEST_TARGETS), $(eval $t: exploded-image test-image)) + $(foreach t, $(filter-out test-make%, $(ALL_TEST_TARGETS)), $(eval $t: jdk-image test-image $(TEST_DEPS))) + $(foreach t, $(ALL_EXPLODED_TEST_TARGETS), $(eval $t: exploded-image test-image $(TEST_DEPS))) interim-image: $(INTERIM_JMOD_TARGETS) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index a6a4bd343d5ba..2d6392d783bd2 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -264,6 +264,7 @@ jaxp_JTREG_PROBLEM_LIST += $(TOPDIR)/test/jaxp/ProblemList.txt langtools_JTREG_PROBLEM_LIST += $(TOPDIR)/test/langtools/ProblemList.txt hotspot_JTREG_PROBLEM_LIST += $(TOPDIR)/test/hotspot/jtreg/ProblemList.txt lib-test_JTREG_PROBLEM_LIST += $(TOPDIR)/test/lib-test/ProblemList.txt +docs_JTREG_PROBLEM_LIST += $(TOPDIR)/test/docs/ProblemList.txt ################################################################################ # Parse test selection @@ -603,7 +604,7 @@ define SetupRunMicroTestBody $1_JMH_JVM_ARGS += $$(MICRO_VM_OPTIONS) $$(MICRO_JAVA_OPTIONS) endif - $1_MICRO_VM_OPTIONS := -jvmArgs $(call ShellQuote,$$($1_JMH_JVM_ARGS)) + $1_MICRO_VM_OPTIONS := -jvmArgsPrepend $(call ShellQuote,$$($1_JMH_JVM_ARGS)) ifneq ($$(MICRO_ITER), ) $1_MICRO_ITER := -i $$(MICRO_ITER) @@ -739,6 +740,11 @@ define SetupRunJtregTestBody # Only the problem list for the current test root should be used. $1_JTREG_PROBLEM_LIST := $$(filter $$($1_TEST_ROOT)%, $$($1_JTREG_PROBLEM_LIST)) + # Pass along the path to the tidy html checker + ifneq ($$(TIDY), ) + $1_JTREG_BASIC_OPTIONS += -Dtidy=$$(TIDY) + endif + ifneq ($(TEST_JOBS), 0) $$(eval $$(call SetJtregValue,$1,JTREG_JOBS,$$(TEST_JOBS))) else @@ -847,11 +853,7 @@ define SetupRunJtregTestBody endif ifneq ($$(findstring -XX:+UseZGC, $$(JTREG_ALL_OPTIONS)), ) - ifneq ($$(findstring -XX:-ZGenerational, $$(JTREG_ALL_OPTIONS)), ) - JTREG_AUTO_PROBLEM_LISTS += ProblemList-zgc.txt - else - JTREG_AUTO_PROBLEM_LISTS += ProblemList-generational-zgc.txt - endif + JTREG_AUTO_PROBLEM_LISTS += ProblemList-zgc.txt endif ifneq ($$(JTREG_EXTRA_PROBLEM_LISTS), ) @@ -868,6 +870,8 @@ define SetupRunJtregTestBody $1_JTREG_BASIC_OPTIONS += -e:TEST_IMAGE_DIR=$(TEST_IMAGE_DIR) + $1_JTREG_BASIC_OPTIONS += -e:DOCS_JDK_IMAGE_DIR=$$(DOCS_JDK_IMAGE_DIR) + ifneq ($$(JTREG_FAILURE_HANDLER_OPTIONS), ) $1_JTREG_LAUNCHER_OPTIONS += -Djava.library.path="$(JTREG_FAILURE_HANDLER_DIR)" endif diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac index 3ec95ba8181de..21bf61a3fa1e9 100644 --- a/make/autoconf/configure.ac +++ b/make/autoconf/configure.ac @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -202,6 +202,7 @@ FLAGS_POST_TOOLCHAIN LIB_TESTS_SETUP_JTREG LIB_TESTS_SETUP_JMH LIB_TESTS_SETUP_JIB +LIB_TESTS_SETUP_TIDY # Now we can test some aspects on the target using configure macros. PLATFORM_SETUP_OPENJDK_TARGET_BITS diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 992a0282c043b..bd8f2ec9a7f2e 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -936,15 +936,13 @@ AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION], if test "x$OPENJDK_TARGET_CPU" = xaarch64; then if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then - FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${BRANCH_PROTECTION_FLAG}], + FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$BRANCH_PROTECTION_FLAG], IF_TRUE: [BRANCH_PROTECTION_AVAILABLE=true]) fi fi - BRANCH_PROTECTION_CFLAGS="" UTIL_ARG_ENABLE(NAME: branch-protection, DEFAULT: false, - RESULT: USE_BRANCH_PROTECTION, AVAILABLE: $BRANCH_PROTECTION_AVAILABLE, + RESULT: BRANCH_PROTECTION_ENABLED, AVAILABLE: $BRANCH_PROTECTION_AVAILABLE, DESC: [enable branch protection when compiling C/C++], - IF_ENABLED: [ BRANCH_PROTECTION_CFLAGS=${BRANCH_PROTECTION_FLAG}]) - AC_SUBST(BRANCH_PROTECTION_CFLAGS) + IF_ENABLED: [BRANCH_PROTECTION_CFLAGS=$BRANCH_PROTECTION_FLAG]) ]) diff --git a/make/autoconf/flags-other.m4 b/make/autoconf/flags-other.m4 index 8d4d405b07639..f0fa82489df30 100644 --- a/make/autoconf/flags-other.m4 +++ b/make/autoconf/flags-other.m4 @@ -150,5 +150,9 @@ AC_DEFUN([FLAGS_SETUP_ASFLAGS_CPU_DEP], $2JVM_ASFLAGS="${$2JVM_ASFLAGS} $ARM_ARCH_TYPE_ASFLAGS $ARM_FLOAT_TYPE_ASFLAGS" fi + if test "x$BRANCH_PROTECTION_ENABLED" = "xtrue"; then + $2JVM_ASFLAGS="${$2JVM_ASFLAGS} $BRANCH_PROTECTION_FLAG" + fi + AC_SUBST($2JVM_ASFLAGS) ]) diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4 index bd33315090fce..9695644bafe63 100644 --- a/make/autoconf/jvm-features.m4 +++ b/make/autoconf/jvm-features.m4 @@ -479,6 +479,22 @@ AC_DEFUN([JVM_FEATURES_CALCULATE_ACTIVE], $JVM_FEATURES_ENABLED, $JVM_FEATURES_DISABLED) ]) +################################################################################ +# Filter the unsupported feature combinations. +# This is called after JVM_FEATURES_ACTIVE are fully populated. +# +AC_DEFUN([JVM_FEATURES_FILTER_UNSUPPORTED], +[ + # G1 late barrier expansion in C2 is not implemented for some platforms. + # Choose not to support G1 in this configuration. + if JVM_FEATURES_IS_ACTIVE(compiler2); then + if test "x$OPENJDK_TARGET_CPU" = "xx86"; then + AC_MSG_NOTICE([G1 cannot be used with C2 on this platform, disabling G1]) + UTIL_GET_NON_MATCHING_VALUES(JVM_FEATURES_ACTIVE, $JVM_FEATURES_ACTIVE, "g1gc") + fi + fi +]) + ################################################################################ # Helper function for JVM_FEATURES_VERIFY. Check if the specified JVM # feature is active. To be used in shell if constructs, like this: @@ -554,6 +570,9 @@ AC_DEFUN_ONCE([JVM_FEATURES_SETUP], # The result is stored in JVM_FEATURES_ACTIVE. JVM_FEATURES_CALCULATE_ACTIVE($variant) + # Filter unsupported feature combinations from JVM_FEATURES_ACTIVE. + JVM_FEATURES_FILTER_UNSUPPORTED + # Verify consistency for JVM_FEATURES_ACTIVE. JVM_FEATURES_VERIFY($variant) diff --git a/make/autoconf/lib-hsdis.m4 b/make/autoconf/lib-hsdis.m4 index bd78768d03e48..a4d2c5f81f3f3 100644 --- a/make/autoconf/lib-hsdis.m4 +++ b/make/autoconf/lib-hsdis.m4 @@ -266,8 +266,10 @@ AC_DEFUN([LIB_SETUP_HSDIS_BINUTILS], HSDIS_CFLAGS="-DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB" elif test "x$BINUTILS_INSTALL_DIR" != x; then disasm_header="\"$BINUTILS_INSTALL_DIR/include/dis-asm.h\"" - if test -e $BINUTILS_INSTALL_DIR/lib/libbfd.a && \ - test -e $BINUTILS_INSTALL_DIR/lib/libopcodes.a && \ + if (test -e $BINUTILS_INSTALL_DIR/lib/libbfd.a || \ + test -e $BINUTILS_INSTALL_DIR/lib64/libbfd.a) && \ + (test -e $BINUTILS_INSTALL_DIR/lib/libopcodes.a || \ + test -e $BINUTILS_INSTALL_DIR/lib64/libopcodes.a) && \ (test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a || \ test -e $BINUTILS_INSTALL_DIR/lib64/libiberty.a || \ test -e $BINUTILS_INSTALL_DIR/lib32/libiberty.a); then @@ -275,7 +277,19 @@ AC_DEFUN([LIB_SETUP_HSDIS_BINUTILS], # libiberty ignores --libdir and may be installed in $BINUTILS_INSTALL_DIR/lib, $BINUTILS_INSTALL_DIR/lib32 # or $BINUTILS_INSTALL_DIR/lib64, depending on system setup + LIBOPCODES_LIB="" + LIBBFD_LIB="" LIBIBERTY_LIB="" + if test -e $BINUTILS_INSTALL_DIR/lib/libbfd.a; then + LIBBFD_LIB="$BINUTILS_INSTALL_DIR/lib/libbfd.a" + else + LIBBFD_LIB="$BINUTILS_INSTALL_DIR/lib64/libbfd.a" + fi + if test -e $BINUTILS_INSTALL_DIR/lib/libopcodes.a; then + LIBOPCODES_LIB="$BINUTILS_INSTALL_DIR/lib/libopcodes.a" + else + LIBOPCODES_LIB="$BINUTILS_INSTALL_DIR/lib64/libopcodes.a" + fi if test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a; then LIBIBERTY_LIB="$BINUTILS_INSTALL_DIR/lib/libiberty.a" elif test -e $BINUTILS_INSTALL_DIR/lib32/libiberty.a; then @@ -283,7 +297,7 @@ AC_DEFUN([LIB_SETUP_HSDIS_BINUTILS], else LIBIBERTY_LIB="$BINUTILS_INSTALL_DIR/lib64/libiberty.a" fi - HSDIS_LIBS="$BINUTILS_INSTALL_DIR/lib/libbfd.a $BINUTILS_INSTALL_DIR/lib/libopcodes.a $LIBIBERTY_LIB" + HSDIS_LIBS="$LIBBFD_LIB $LIBOPCODES_LIB $LIBIBERTY_LIB" # If we have libsframe add it. if test -e $BINUTILS_INSTALL_DIR/lib/libsframe.a; then HSDIS_LIBS="$HSDIS_LIBS $BINUTILS_INSTALL_DIR/lib/libsframe.a" diff --git a/make/autoconf/lib-tests.m4 b/make/autoconf/lib-tests.m4 index ffbc7d0531041..afb9403080871 100644 --- a/make/autoconf/lib-tests.m4 +++ b/make/autoconf/lib-tests.m4 @@ -308,6 +308,32 @@ AC_DEFUN_ONCE([LIB_TESTS_SETUP_JIB], AC_SUBST(JIB_HOME) ]) +# Setup the tidy html checker +AC_DEFUN_ONCE([LIB_TESTS_SETUP_TIDY], +[ + UTIL_LOOKUP_PROGS(TIDY, tidy) + + if test "x$TIDY" != x; then + AC_MSG_CHECKING([if tidy is working properly]) + tidy_output=`$TIDY --version 2>&1` + if ! $ECHO "$tidy_output" | $GREP -q "HTML Tidy" 2>&1 > /dev/null; then + AC_MSG_RESULT([no]) + AC_MSG_NOTICE([$TIDY is not a valid tidy executable and will be ignored. Output from --version: $tidy_output]) + TIDY= + elif ! $ECHO "$tidy_output" | $GREP -q "version" 2>&1 > /dev/null; then + AC_MSG_RESULT([no]) + AC_MSG_NOTICE([$TIDY is missing a proper version number and will be ignored. Output from --version: $tidy_output]) + TIDY= + else + AC_MSG_RESULT([yes]) + AC_MSG_CHECKING([for tidy version]) + tidy_version=`$ECHO $tidy_output | $SED -e 's/.*version //g'` + AC_MSG_RESULT([$tidy_version]) + fi + fi + AC_SUBST(TIDY) +]) + ################################################################################ # # Check if building of the jtreg failure handler should be enabled. diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index 20b1d00aa893f..a5f4143c8885f 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -429,7 +429,6 @@ ENABLE_LIBFFI_BUNDLING := @ENABLE_LIBFFI_BUNDLING@ LIBFFI_LIB_FILE := @LIBFFI_LIB_FILE@ FILE_MACRO_CFLAGS := @FILE_MACRO_CFLAGS@ REPRODUCIBLE_CFLAGS := @REPRODUCIBLE_CFLAGS@ -BRANCH_PROTECTION_CFLAGS := @BRANCH_PROTECTION_CFLAGS@ STATIC_LIBS_CFLAGS := @STATIC_LIBS_CFLAGS@ @@ -744,6 +743,7 @@ MKDIR := @MKDIR@ MV := @MV@ NICE := @NICE@ PANDOC := @PANDOC@ +TIDY := @TIDY@ PATCH := @PATCH@ PRINTF := @PRINTF@ READLINK := @READLINK@ diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 75c8d2b61d084..d84ae447e541a 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -307,7 +307,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION], [ # Restore old path, except for the microsoft toolchain, which requires the # toolchain path to remain in place. Otherwise the compiler will not work in - # some siutations in later configure checks. + # some situations in later configure checks. if test "x$TOOLCHAIN_TYPE" != "xmicrosoft"; then PATH="$OLD_PATH" fi @@ -316,10 +316,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION], # This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2" CFLAGS="$ORG_CFLAGS" CXXFLAGS="$ORG_CXXFLAGS" - - # filter out some unwanted additions autoconf may add to CXX; we saw this on macOS with autoconf 2.72 - UTIL_GET_NON_MATCHING_VALUES(cxx_filtered, $CXX, -std=c++11 -std=gnu++11) - CXX="$cxx_filtered" ]) # Check if a compiler is of the toolchain type we expect, and save the version @@ -358,6 +354,11 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION], # Copyright (C) 2013 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + # or look like + # gcc (GCC) 10.2.1 20200825 (Alibaba 10.2.1-3.8 2.32) + # Copyright (C) 2020 Free Software Foundation, Inc. + # This is free software; see the source for copying conditions. There is NO + # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. COMPILER_VERSION_OUTPUT=`$COMPILER --version 2>&1` # Check that this is likely to be GCC. $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Free Software Foundation" > /dev/null @@ -371,7 +372,8 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION], COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT | \ $SED -e 's/ *Copyright .*//'` COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ - $SED -e 's/^.* \(@<:@1-9@:>@<:@0-9@:>@*\.@<:@0-9.@:>@*\)@<:@^0-9.@:>@.*$/\1/'` + $AWK -F ')' '{print [$]2}' | \ + $AWK '{print [$]1}'` elif test "x$TOOLCHAIN_TYPE" = xclang; then # clang --version output typically looks like # Apple clang version 15.0.0 (clang-1500.3.9.4) diff --git a/make/autoconf/util.m4 b/make/autoconf/util.m4 index 6beadb4c942c7..5a6142d509202 100644 --- a/make/autoconf/util.m4 +++ b/make/autoconf/util.m4 @@ -25,6 +25,70 @@ m4_include([util_paths.m4]) +############################################################################### +# Overwrite the existing version of AC_PROG_CC with our own custom variant. +# Unlike the regular AC_PROG_CC, the compiler list must always be passed. +AC_DEFUN([AC_PROG_CC], +[ + AC_LANG_PUSH(C) + AC_ARG_VAR([CC], [C compiler command]) + AC_ARG_VAR([CFLAGS], [C compiler flags]) + + _AC_ARG_VAR_LDFLAGS() + _AC_ARG_VAR_LIBS() + _AC_ARG_VAR_CPPFLAGS() + + AC_CHECK_TOOLS(CC, [$1]) + + test -z "$CC" && AC_MSG_FAILURE([no acceptable C compiler found in \$PATH]) + + # Provide some information about the compiler. + _AS_ECHO_LOG([checking for _AC_LANG compiler version]) + set X $ac_compile + ac_compiler=$[2] + for ac_option in --version -v -V -qversion -version; do + _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD]) + done + + m4_expand_once([_AC_COMPILER_EXEEXT]) + m4_expand_once([_AC_COMPILER_OBJEXT]) + + _AC_PROG_CC_G + + AC_LANG_POP(C) +]) + +############################################################################### +# Overwrite the existing version of AC_PROG_CXX with our own custom variant. +# Unlike the regular AC_PROG_CXX, the compiler list must always be passed. +AC_DEFUN([AC_PROG_CXX], +[ + AC_LANG_PUSH(C++) + AC_ARG_VAR([CXX], [C++ compiler command]) + AC_ARG_VAR([CXXFLAGS], [C++ compiler flags]) + + _AC_ARG_VAR_LDFLAGS() + _AC_ARG_VAR_LIBS() + _AC_ARG_VAR_CPPFLAGS() + + AC_CHECK_TOOLS(CXX, [$1]) + + # Provide some information about the compiler. + _AS_ECHO_LOG([checking for _AC_LANG compiler version]) + set X $ac_compile + ac_compiler=$[2] + for ac_option in --version -v -V -qversion; do + _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD]) + done + + m4_expand_once([_AC_COMPILER_EXEEXT]) + m4_expand_once([_AC_COMPILER_OBJEXT]) + + _AC_PROG_CXX_G + + AC_LANG_POP(C++) +]) + ################################################################################ # Create a function/macro that takes a series of named arguments. The call is # similar to AC_DEFUN, but the setup of the function looks like this: diff --git a/make/common/FileUtils.gmk b/make/common/FileUtils.gmk index 89cbe872721af..d3cc4872ebb8f 100644 --- a/make/common/FileUtils.gmk +++ b/make/common/FileUtils.gmk @@ -136,7 +136,7 @@ ifeq ($(call isTargetOs, macosx), true) $(CP) -fRP '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'; \ fi if [ -n "`$(XATTR) -ls '$(call DecodeSpace, $@)'`" ]; then \ - $(CHMOD) u+w '$(call DecodeSpace, $@)'; \ + $(CHMOD) -h u+w '$(call DecodeSpace, $@)'; \ $(XATTR) -cs '$(call DecodeSpace, $@)'; \ fi endef diff --git a/make/common/FindTests.gmk b/make/common/FindTests.gmk index 14f0ef0b431e7..db9cfe774defe 100644 --- a/make/common/FindTests.gmk +++ b/make/common/FindTests.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2019, 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 @@ -43,7 +43,7 @@ $(eval $(call IncludeCustomExtension, common/FindTests.gmk)) TEST_BASEDIRS += $(TOPDIR)/test $(TOPDIR) # JTREG_TESTROOTS might have been set by a custom extension -JTREG_TESTROOTS += $(addprefix $(TOPDIR)/test/, hotspot/jtreg jdk langtools jaxp lib-test) +JTREG_TESTROOTS += $(addprefix $(TOPDIR)/test/, hotspot/jtreg jdk langtools jaxp lib-test docs) # Extract the names of the Jtreg group files from the TEST.ROOT files. The # TEST.ROOT files being properties files can be interpreted as makefiles so diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index eca6c05033d88..a6b383daa8fd4 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -29,21 +29,21 @@ GTEST_VERSION=1.14.0 JTREG_VERSION=7.4+1 LINUX_X64_BOOT_JDK_EXT=tar.gz -LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_SHA256=41536f115668308ecf4eba92aaf6acaeb0936225828b741efd83b6173ba82963 +LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_SHA256=08fea92724127c6fa0f2e5ea0b07ff4951ccb1e2f22db3c21eebbd7347152a67 ALPINE_LINUX_X64_BOOT_JDK_EXT=tar.gz -ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin22-binaries/releases/download/jdk-22.0.2%2B9/OpenJDK22U-jdk_x64_alpine-linux_hotspot_22.0.2_9.tar.gz -ALPINE_LINUX_X64_BOOT_JDK_SHA256=49f73414824b1a7c268a611225fa4d7ce5e25600201e0f1cd59f94d1040b5264 +ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin23-binaries/releases/download/jdk-23%2B37/OpenJDK23U-jdk_x64_alpine-linux_hotspot_23_37.tar.gz +ALPINE_LINUX_X64_BOOT_JDK_SHA256=bff4c78f30d8d173e622bf2f40c36113df47337fc6d1ee5105ed2459841165aa MACOS_AARCH64_BOOT_JDK_EXT=tar.gz -MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_macos-aarch64_bin.tar.gz -MACOS_AARCH64_BOOT_JDK_SHA256=3dab98730234e1a87aec14bcb8171d2cae101e96ff4eed1dab96abbb08e843fd +MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_macos-aarch64_bin.tar.gz +MACOS_AARCH64_BOOT_JDK_SHA256=9527bf080a74ae6dca51df413aa826f0c011c6048885e4c8ad112172be8815f3 MACOS_X64_BOOT_JDK_EXT=tar.gz -MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_macos-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_SHA256=e8b3ec7a7077711223d31156e771f11723cd7af31c2017f1bd2eda20855940fb +MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_macos-x64_bin.tar.gz +MACOS_X64_BOOT_JDK_SHA256=5c3a909fd2079d0e376dd43c85c4f7d02d08914866f196480bd47784b2a0121e WINDOWS_X64_BOOT_JDK_EXT=zip -WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_SHA256=f2a9b9ab944e71a64637fcdc6b13a1188cf02d4eb9ecf71dc927e98b3e45f5dc +WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_SHA256=cba5013874ba50cae543c86fe6423453816c77281e2751a8a9a633d966f1dc04 diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 30c45d4cde161..0785d340f48b6 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -390,8 +390,8 @@ var getJibProfilesCommon = function (input, data) { }; }; - common.boot_jdk_version = "22"; - common.boot_jdk_build_number = "36"; + common.boot_jdk_version = "23"; + common.boot_jdk_build_number = "37"; common.boot_jdk_home = input.get("boot_jdk", "install_path") + "/jdk-" + common.boot_jdk_version + (input.build_os == "macosx" ? ".jdk/Contents/Home" : ""); @@ -415,7 +415,7 @@ var getJibProfilesProfiles = function (input, common, data) { "linux-x64": { target_os: "linux", target_cpu: "x64", - dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc"], + dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc", "tidy"], configure_args: concat( (input.build_cpu == "x64" ? common.configure_args_64bit : "--openjdk-target=x86_64-linux-gnu"), @@ -441,7 +441,7 @@ var getJibProfilesProfiles = function (input, common, data) { "macosx-x64": { target_os: "macosx", target_cpu: "x64", - dependencies: ["devkit", "gtest", "graphviz", "pandoc"], + dependencies: ["devkit", "gtest", "graphviz", "pandoc", "tidy"], configure_args: concat(common.configure_args_64bit, "--with-zlib=system", "--with-macosx-version-max=11.00.00", "--enable-compatible-cds-alignment", @@ -453,7 +453,7 @@ var getJibProfilesProfiles = function (input, common, data) { "macosx-aarch64": { target_os: "macosx", target_cpu: "aarch64", - dependencies: ["devkit", "gtest", "graphviz", "pandoc"], + dependencies: ["devkit", "gtest", "graphviz", "pandoc", "tidy"], configure_args: concat(common.configure_args_64bit, "--with-macosx-version-max=11.00.00"), }, @@ -486,7 +486,7 @@ var getJibProfilesProfiles = function (input, common, data) { "linux-aarch64": { target_os: "linux", target_cpu: "aarch64", - dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc"], + dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc", "tidy"], configure_args: [ "--with-zlib=system", "--disable-dtrace", @@ -957,7 +957,7 @@ var getJibProfilesProfiles = function (input, common, data) { // Profiles used to run tests using Jib for internal dependencies. var testedProfile = input.testedProfile; - if (testedProfile == null) { + if (testedProfile == null || testedProfile == "docs") { testedProfile = input.build_os + "-" + input.build_cpu; } var testedProfileJdk = testedProfile + ".jdk"; @@ -999,25 +999,38 @@ var getJibProfilesProfiles = function (input, common, data) { testOnlyProfilesPrebuilt["run-test-prebuilt"]["dependencies"].push(testedProfile + ".jdk_symbols"); } + var testOnlyProfilesPrebuiltDocs = { + "run-test-prebuilt-docs": clone(testOnlyProfilesPrebuilt["run-test-prebuilt"]) + }; + + testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].dependencies.push("docs.doc_api_spec", "tidy"); + testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].environment["DOCS_JDK_IMAGE_DIR"] + = input.get("docs.doc_api_spec", "install_path"); + testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].environment["TIDY"] + = input.get("tidy", "home_path") + "/bin/tidy"; + testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].labels = "test-docs"; + // If actually running the run-test-prebuilt profile, verify that the input // variable is valid and if so, add the appropriate target_* values from // the tested profile. Use testImageProfile value as backup. - if (input.profile == "run-test-prebuilt") { + if (input.profile == "run-test-prebuilt" || input.profile == "run-test-prebuilt-docs") { if (profiles[testedProfile] == null && profiles[testImageProfile] == null) { error("testedProfile is not defined: " + testedProfile + " " + testImageProfile); } } - if (profiles[testedProfile] != null) { - testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_os"] - = profiles[testedProfile]["target_os"]; - testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_cpu"] - = profiles[testedProfile]["target_cpu"]; - } else if (profiles[testImageProfile] != null) { - testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_os"] - = profiles[testImageProfile]["target_os"]; - testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_cpu"] - = profiles[testImageProfile]["target_cpu"]; + function updateProfileTargets(profiles, testedProfile, testImageProfile, targetProfile, runTestProfile) { + var profileToCheck = profiles[testedProfile] || profiles[testImageProfile]; + + if (profileToCheck != null) { + targetProfile[runTestProfile]["target_os"] = profileToCheck["target_os"]; + targetProfile[runTestProfile]["target_cpu"] = profileToCheck["target_cpu"]; + } } + + updateProfileTargets(profiles, testedProfile, testImageProfile, testOnlyProfilesPrebuilt, "run-test-prebuilt"); + updateProfileTargets(profiles, testedProfile, testImageProfile, testOnlyProfilesPrebuiltDocs, "run-test-prebuilt-docs"); + + profiles = concatObjects(profiles, testOnlyProfilesPrebuiltDocs); profiles = concatObjects(profiles, testOnlyProfilesPrebuilt); // On macosx add the devkit bin dir to the path in all the run-test profiles. @@ -1067,6 +1080,8 @@ var getJibProfilesProfiles = function (input, common, data) { } profiles["run-test-prebuilt"] = concatObjects(profiles["run-test-prebuilt"], runTestPrebuiltSrcFullExtra); + profiles["run-test-prebuilt-docs"] = concatObjects(profiles["run-test-prebuilt-docs"], + runTestPrebuiltSrcFullExtra); } // Generate the missing platform attributes @@ -1275,6 +1290,14 @@ var getJibProfilesDependencies = function (input, common) { ext: "tar.gz", revision: "3.4.2+1.0" }, + tidy: { + organization: common.organization, + ext: "tar.gz", + revision: "5.9.20+1", + environment_path: input.get("tidy", "home_path") + "/bin/tidy", + configure_args: "TIDY=" + input.get("tidy", "home_path") + "/bin/tidy", + module: "tidy-html-" + (input.target_os === "macosx" ? input.target_os : input.target_platform), + }, }; return dependencies; diff --git a/make/conf/module-loader-map.conf b/make/conf/module-loader-map.conf index 1062b780a79ff..b628bfbf2da30 100644 --- a/make/conf/module-loader-map.conf +++ b/make/conf/module-loader-map.conf @@ -62,6 +62,7 @@ UPGRADEABLE_PLATFORM_MODULES= \ java.compiler \ jdk.graal.compiler \ jdk.graal.compiler.management \ + jdk.jsobject \ # PLATFORM_MODULES= \ @@ -79,7 +80,6 @@ PLATFORM_MODULES= \ jdk.crypto.cryptoki \ jdk.dynalink \ jdk.httpserver \ - jdk.jsobject \ jdk.localedata \ jdk.naming.dns \ jdk.security.auth \ diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 1d47c2cddd001..055f9ca886618 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -37,6 +37,6 @@ DEFAULT_VERSION_DATE=2025-03-18 DEFAULT_VERSION_CLASSFILE_MAJOR=68 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 -DEFAULT_ACCEPTABLE_BOOT_VERSIONS="22 23 24" +DEFAULT_ACCEPTABLE_BOOT_VERSIONS="23 24" DEFAULT_JDK_SOURCE_TARGET_VERSION=24 DEFAULT_PROMOTED_VERSION_PRE=ea diff --git a/make/devkit/createTidyBundle.sh b/make/devkit/createTidyBundle.sh new file mode 100644 index 0000000000000..b3f8e6bf07805 --- /dev/null +++ b/make/devkit/createTidyBundle.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# +# 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. +# + +# Creates a tidy bundle in the build directory. A dependency that can be +# used to validate and correct HTML. + +# wget, cmake and gcc are required to build tidy. + +set -e + +GITHUB_USER="htacg" +REPO_NAME="tidy-html5" +COMMIT_HASH="d08ddc2860aa95ba8e301343a30837f157977cba" +SCRIPT_DIR="$(cd "$(dirname $0)" > /dev/null && pwd)" +INSTALL_PREFIX="${SCRIPT_DIR}/../../build/tidy/tidy/" +BUILD_DIR="build/cmake" + +OS_NAME=$(uname -s) +OS_ARCH=$(uname -m) + +DOWNLOAD_URL="https://github.com/$GITHUB_USER/$REPO_NAME/archive/$COMMIT_HASH.tar.gz" +OUTPUT_FILE="$REPO_NAME-$COMMIT_HASH.tar.gz" + +wget "$DOWNLOAD_URL" -O "$OUTPUT_FILE" + +tar -xzf "$OUTPUT_FILE" +rm -rf "$OUTPUT_FILE" + +SRC_DIR="$REPO_NAME-$COMMIT_HASH" + +mkdir -p "$SRC_DIR/$BUILD_DIR" +cd "$SRC_DIR/$BUILD_DIR" + +case $OS_NAME in + Linux|Darwin) + echo "Building Tidy HTML5 for Unix-like platform ($OS_NAME)..." + + CMAKE_ARCH_OPTIONS="" + if [ "$OS_NAME" == "Darwin" ]; then + if [[ "$OS_ARCH" == "arm64" || "$OS_ARCH" == "x86_64" ]]; then + CMAKE_ARCH_OPTIONS="-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64" + fi + fi + + cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" $CMAKE_ARCH_OPTIONS + make install + ;; + + *) + echo "Unsupported OS: $OS_NAME" + exit 1 + ;; +esac + +cd "$SCRIPT_DIR" +rm -rf "$SRC_DIR" + +cd "$INSTALL_PREFIX.." +PACKAGED_FILE="tidy-html5.tar.gz" + +tar -czvf "$PACKAGED_FILE" -C "$INSTALL_PREFIX.." tidy + +echo "Created $INSTALL_PREFIX..$PACKAGED_FILE" diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk index 8dada3cec0a1d..ce3f268402672 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -193,13 +193,18 @@ ifeq ($(call check-jvm-feature, compiler2), true) ifeq ($(call check-jvm-feature, zgc), true) AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ - $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/x/x_$(HOTSPOT_TARGET_CPU).ad \ - $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/x/x_$(HOTSPOT_TARGET_CPU_ARCH).ad \ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/z/z_$(HOTSPOT_TARGET_CPU).ad \ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/z/z_$(HOTSPOT_TARGET_CPU_ARCH).ad \ ))) endif + ifeq ($(call check-jvm-feature, g1gc), true) + AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/g1/g1_$(HOTSPOT_TARGET_CPU).ad \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/g1/g1_$(HOTSPOT_TARGET_CPU_ARCH).ad \ + ))) + endif + SINGLE_AD_SRCFILE := $(ADLC_SUPPORT_DIR)/all-ad-src.ad INSERT_FILENAME_AWK_SCRIPT := \ diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk index c4c030810fc44..b94031515f79e 100644 --- a/make/hotspot/lib/JvmFeatures.gmk +++ b/make/hotspot/lib/JvmFeatures.gmk @@ -150,7 +150,6 @@ endif ifneq ($(call check-jvm-feature, zgc), true) JVM_CFLAGS_FEATURES += -DINCLUDE_ZGC=0 JVM_EXCLUDE_PATTERNS += gc/z - JVM_EXCLUDE_PATTERNS += gc/x endif ifneq ($(call check-jvm-feature, shenandoahgc), true) diff --git a/make/modules/jdk.hotspot.agent/Lib.gmk b/make/modules/jdk.hotspot.agent/Lib.gmk index f0ede594d0ce8..12f1c1f2a9077 100644 --- a/make/modules/jdk.hotspot.agent/Lib.gmk +++ b/make/modules/jdk.hotspot.agent/Lib.gmk @@ -59,9 +59,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBSAPROC, \ OPTIMIZATION := HIGH, \ EXTRA_HEADER_DIRS := java.base:libjvm, \ DISABLED_WARNINGS_gcc := sign-compare, \ - DISABLED_WARNINGS_gcc_LinuxDebuggerLocal.cpp := unused-variable, \ DISABLED_WARNINGS_gcc_ps_core.c := pointer-arith, \ - DISABLED_WARNINGS_gcc_symtab.c := unused-but-set-variable, \ DISABLED_WARNINGS_clang := sign-compare, \ DISABLED_WARNINGS_clang_libproc_impl.c := format-nonliteral, \ DISABLED_WARNINGS_clang_MacosxDebuggerLocal.m := unused-variable, \ diff --git a/make/modules/jdk.incubator.vector/Lib.gmk b/make/modules/jdk.incubator.vector/Lib.gmk index 0620549f05cd7..bf6ace6f97f7c 100644 --- a/make/modules/jdk.incubator.vector/Lib.gmk +++ b/make/modules/jdk.incubator.vector/Lib.gmk @@ -37,3 +37,21 @@ ifeq ($(call isTargetOs, linux windows)+$(call isTargetCpu, x86_64)+$(INCLUDE_CO TARGETS += $(BUILD_LIBJSVML) endif + +################################################################################ +## Build libsleef +################################################################################ + +ifeq ($(call isTargetOs, linux)+$(call isTargetCpu, riscv64)+$(INCLUDE_COMPILER2), true+true+true) + $(eval $(call SetupJdkLibrary, BUILD_LIBSLEEF, \ + NAME := sleef, \ + OPTIMIZATION := HIGH, \ + SRC := libsleef/lib, \ + EXTRA_SRC := libsleef/generated, \ + DISABLED_WARNINGS_gcc := unused-function sign-compare tautological-compare ignored-qualifiers, \ + DISABLED_WARNINGS_clang := unused-function sign-compare tautological-compare ignored-qualifiers, \ + CFLAGS := -march=rv64gcv, \ + )) + + TARGETS += $(BUILD_LIBSLEEF) +endif diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk index 700aac3c9c6dc..1b2eb40b252cf 100644 --- a/make/test/BuildMicrobenchmark.gmk +++ b/make/test/BuildMicrobenchmark.gmk @@ -49,7 +49,6 @@ MICROBENCHMARK_CLASSES := $(MICROBENCHMARK_OUTPUT)/classes MICROBENCHMARK_JAR_BIN := $(MICROBENCHMARK_OUTPUT)/jar MICROBENCHMARK_TOOLS_CLASSES := $(MICROBENCHMARK_OUTPUT)/tools-classes -MICROBENCHMARK_INDIFY_DONE := $(MICROBENCHMARK_CLASSES)/_indify.marker JMH_UNPACKED_DIR := $(MICROBENCHMARK_OUTPUT)/jmh_jars JMH_UNPACKED_JARS_DONE := $(JMH_UNPACKED_DIR)/_unpacked.marker @@ -71,17 +70,6 @@ MICROBENCHMARK_MANIFEST := Build: $(FULL_VERSION)\n\ \nJMH-Version: $(JMH_VERSION)\n\ \nName: OpenJDK Microbenchmark Suite -#### Compile Indify tool - -$(eval $(call SetupJavaCompilation, BUILD_INDIFY, \ - TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \ - SRC := $(TOPDIR)/test/jdk/java/lang/invoke, \ - INCLUDE_FILES := indify/Indify.java, \ - DISABLED_WARNINGS := this-escape rawtypes serial options, \ - BIN := $(MICROBENCHMARK_TOOLS_CLASSES), \ - JAVAC_FLAGS := -XDstringConcat=inline -Xprefer:newer, \ -)) - #### Compile Targets # Building microbenchmark requires the jdk.unsupported and java.management modules. @@ -124,14 +112,6 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \ $(BUILD_JDK_MICROBENCHMARK): $(JMH_COMPILE_JARS) -# Run Indify -$(MICROBENCHMARK_INDIFY_DONE): $(BUILD_INDIFY) $(BUILD_JDK_MICROBENCHMARK) - $(call LogWarn, Running Indify on microbenchmark classes) - $(JAVA_SMALL) -cp $(MICROBENCHMARK_TOOLS_CLASSES) \ - indify.Indify --overwrite $(MICROBENCHMARK_CLASSES) \ - $(LOG_DEBUG) 2>&1 - $(TOUCH) $@ - # Unpacking dependencies for inclusion in the benchmark JARs $(JMH_UNPACKED_JARS_DONE): $(JMH_RUNTIME_JARS) $(RM) -r $(JMH_UNPACKED_DIR) @@ -144,8 +124,7 @@ $(JMH_UNPACKED_JARS_DONE): $(JMH_RUNTIME_JARS) # Create benchmarks JAR file with benchmarks for both the old and new JDK $(eval $(call SetupJarArchive, BUILD_JDK_JAR, \ - DEPENDENCIES := $(BUILD_JDK_MICROBENCHMARK) $(JMH_UNPACKED_JARS_DONE) \ - $(MICROBENCHMARK_INDIFY_DONE), \ + DEPENDENCIES := $(BUILD_JDK_MICROBENCHMARK) $(JMH_UNPACKED_JARS_DONE), \ SRCS := $(MICROBENCHMARK_CLASSES) $(JMH_UNPACKED_DIR), \ BIN := $(MICROBENCHMARK_JAR_BIN), \ SUFFIXES := .*, \ diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index d9f1e334a5cf8..90055cb5c0114 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -115,6 +115,8 @@ ifeq ($(call isTargetOs, linux), true) # stripping during the test libraries' build. BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libFib := -g BUILD_JDK_JTREG_LIBRARIES_STRIP_SYMBOLS_libFib := false + # nio tests' libCreationTimeHelper native needs -ldl linker flag + BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libCreationTimeHelper := -ldl endif ifeq ($(ASAN_ENABLED), true) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 39eae43a287e7..d9c77a2f52926 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2307,10 +2307,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return &_PR_REG_mask; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return new TypeVectMask(elemTy, length); -} - // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { return false; @@ -2620,7 +2616,8 @@ static bool is_vector_bitwise_not_pattern(Node* n, Node* m) { bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { if (is_vshift_con_pattern(n, m) || is_vector_bitwise_not_pattern(n, m) || - is_valid_sve_arith_imm_pattern(n, m)) { + is_valid_sve_arith_imm_pattern(n, m) || + is_encode_and_store_pattern(n, m)) { mstack.push(m, Visit); return true; } @@ -2720,7 +2717,7 @@ typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt, { Address addr = mem2address(opcode, base, index, scale, disp); if (addr.getMode() == Address::base_plus_offset) { - // Fix up any out-of-range offsets. + /* Fix up any out-of-range offsets. */ assert_different_registers(rscratch1, base); assert_different_registers(rscratch1, reg); addr = __ legitimize_address(addr, size_in_memory, rscratch1); @@ -2761,11 +2758,7 @@ typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt, int opcode, Register base, int index, int size, int disp) { if (index == -1) { - // Fix up any out-of-range offsets. - assert_different_registers(rscratch1, base); - Address addr = Address(base, disp); - addr = __ legitimize_address(addr, (1 << T), rscratch1); - (masm->*insn)(reg, T, addr); + (masm->*insn)(reg, T, Address(base, disp)); } else { assert(disp == 0, "unsupported address mode"); (masm->*insn)(reg, T, Address(base, as_Register(index), Address::lsl(size))); @@ -2820,7 +2813,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsbw(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrsbw(iRegI dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsbw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2828,7 +2821,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsb(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrsb(iRegI dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2836,7 +2829,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrb(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrb(iRegI dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2844,7 +2837,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrb(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldrb(iRegL dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2852,7 +2845,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrshw(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrshw(iRegI dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrshw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2860,7 +2853,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsh(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrsh(iRegI dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2868,7 +2861,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrh(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrh(iRegI dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2876,7 +2869,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrh(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldrh(iRegL dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2884,7 +2877,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrw(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrw(iRegI dst, memory4 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2892,7 +2885,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrw(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldrw(iRegL dst, memory4 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2900,7 +2893,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsw(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldrsw(iRegL dst, memory4 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2908,7 +2901,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldr(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldr(iRegL dst, memory8 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldr, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -2916,7 +2909,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrs(vRegF dst, memory mem) %{ + enc_class aarch64_enc_ldrs(vRegF dst, memory4 mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(masm, &MacroAssembler::ldrs, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2924,7 +2917,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrd(vRegD dst, memory mem) %{ + enc_class aarch64_enc_ldrd(vRegD dst, memory8 mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(masm, &MacroAssembler::ldrd, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -2932,7 +2925,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb(iRegI src, memory mem) %{ + enc_class aarch64_enc_strb(iRegI src, memory1 mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strb, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2940,14 +2933,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0(memory mem) %{ + enc_class aarch64_enc_strb0(memory1 mem) %{ loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strh(iRegI src, memory mem) %{ + enc_class aarch64_enc_strh(iRegI src, memory2 mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strh, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2955,14 +2948,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strh0(memory mem) %{ + enc_class aarch64_enc_strh0(memory2 mem) %{ loadStore(masm, &MacroAssembler::strh, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strw(iRegI src, memory mem) %{ + enc_class aarch64_enc_strw(iRegI src, memory4 mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strw, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2970,14 +2963,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strw0(memory mem) %{ + enc_class aarch64_enc_strw0(memory4 mem) %{ loadStore(masm, &MacroAssembler::strw, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_str(iRegL src, memory mem) %{ + enc_class aarch64_enc_str(iRegL src, memory8 mem) %{ Register src_reg = as_Register($src$$reg); // we sometimes get asked to store the stack pointer into the // current thread -- we cannot do that directly on AArch64 @@ -2992,14 +2985,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_str0(memory mem) %{ + enc_class aarch64_enc_str0(memory8 mem) %{ loadStore(masm, &MacroAssembler::str, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strs(vRegF src, memory mem) %{ + enc_class aarch64_enc_strs(vRegF src, memory4 mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(masm, &MacroAssembler::strs, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -3007,7 +3000,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strd(vRegD src, memory mem) %{ + enc_class aarch64_enc_strd(vRegD src, memory8 mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(masm, &MacroAssembler::strd, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -3015,7 +3008,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0_ordered(memory mem) %{ + enc_class aarch64_enc_strb0_ordered(memory4 mem) %{ __ membar(Assembler::StoreStore); loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -3217,7 +3210,7 @@ encode %{ // synchronized read/update encodings - enc_class aarch64_enc_ldaxr(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldaxr(iRegL dst, memory8 mem) %{ Register dst_reg = as_Register($dst$$reg); Register base = as_Register($mem$$base); int index = $mem$$index; @@ -3245,7 +3238,7 @@ encode %{ } %} - enc_class aarch64_enc_stlxr(iRegLNoSp src, memory mem) %{ + enc_class aarch64_enc_stlxr(iRegLNoSp src, memory8 mem) %{ Register src_reg = as_Register($src$$reg); Register base = as_Register($mem$$base); int index = $mem$$index; @@ -4173,10 +4166,60 @@ operand immIU7() interface(CONST_INTER); %} -// Offset for immediate loads and stores +// Offset for scaled or unscaled immediate loads and stores operand immIOffset() %{ - predicate(n->get_int() >= -256 && n->get_int() <= 65520); + predicate(Address::offset_ok_for_immed(n->get_int(), 0)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset1() +%{ + predicate(Address::offset_ok_for_immed(n->get_int(), 0)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset2() +%{ + predicate(Address::offset_ok_for_immed(n->get_int(), 1)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset4() +%{ + predicate(Address::offset_ok_for_immed(n->get_int(), 2)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset8() +%{ + predicate(Address::offset_ok_for_immed(n->get_int(), 3)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset16() +%{ + predicate(Address::offset_ok_for_immed(n->get_int(), 4)); match(ConI); op_cost(0); @@ -4194,6 +4237,56 @@ operand immLOffset() interface(CONST_INTER); %} +operand immLoffset1() +%{ + predicate(Address::offset_ok_for_immed(n->get_long(), 0)); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immLoffset2() +%{ + predicate(Address::offset_ok_for_immed(n->get_long(), 1)); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immLoffset4() +%{ + predicate(Address::offset_ok_for_immed(n->get_long(), 2)); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immLoffset8() +%{ + predicate(Address::offset_ok_for_immed(n->get_long(), 3)); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immLoffset16() +%{ + predicate(Address::offset_ok_for_immed(n->get_long(), 4)); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // 5 bit signed long integer operand immL5() %{ @@ -5106,7 +5199,105 @@ operand indIndex(iRegP reg, iRegL lreg) %} %} -operand indOffI(iRegP reg, immIOffset off) +operand indOffI1(iRegP reg, immIOffset1 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffI2(iRegP reg, immIOffset2 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffI4(iRegP reg, immIOffset4 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffI8(iRegP reg, immIOffset8 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffI16(iRegP reg, immIOffset16 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffL1(iRegP reg, immLoffset1 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffL2(iRegP reg, immLoffset2 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffL4(iRegP reg, immLoffset4 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); @@ -5120,7 +5311,21 @@ operand indOffI(iRegP reg, immIOffset off) %} %} -operand indOffL(iRegP reg, immLOffset off) +operand indOffL8(iRegP reg, immLoffset8 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffL16(iRegP reg, immLoffset16 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); @@ -5496,7 +5701,10 @@ operand iRegL2P(iRegL reg) %{ interface(REG_INTER) %} -opclass vmem(indirect, indIndex, indOffI, indOffL, indOffIN, indOffLN); +opclass vmem2(indirect, indIndex, indOffI2, indOffL2); +opclass vmem4(indirect, indIndex, indOffI4, indOffL4); +opclass vmem8(indirect, indIndex, indOffI8, indOffL8); +opclass vmem16(indirect, indIndex, indOffI16, indOffL16); //----------OPERAND CLASSES---------------------------------------------------- // Operand Classes are groups of operands that are used as to simplify @@ -5508,9 +5716,23 @@ opclass vmem(indirect, indIndex, indOffI, indOffL, indOffIN, indOffLN); // memory is used to define read/write location for load/store // instruction defs. we can turn a memory op into an Address -opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI, indOffL, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, - indOffLN, indirectX2P, indOffX2P); +opclass memory1(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI1, indOffL1, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indirectX2P, indOffX2P); + +opclass memory2(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI2, indOffL2, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indirectX2P, indOffX2P); + +opclass memory4(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI4, indOffL4, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); + +opclass memory8(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI8, indOffL8, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); + +// All of the memory operands. For the pipeline description. +opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, + indOffI1, indOffL1, indOffI2, indOffL2, indOffI4, indOffL4, indOffI8, indOffL8, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); + // iRegIorL2I is used for src inputs in rules for 32 bit int (I) // operations. it allows the src to be either an iRegI or a (ConvL2I @@ -6212,7 +6434,7 @@ define %{ // Load Instructions // Load Byte (8 bit signed) -instruct loadB(iRegINoSp dst, memory mem) +instruct loadB(iRegINoSp dst, memory1 mem) %{ match(Set dst (LoadB mem)); predicate(!needs_acquiring_load(n)); @@ -6226,7 +6448,7 @@ instruct loadB(iRegINoSp dst, memory mem) %} // Load Byte (8 bit signed) into long -instruct loadB2L(iRegLNoSp dst, memory mem) +instruct loadB2L(iRegLNoSp dst, memory1 mem) %{ match(Set dst (ConvI2L (LoadB mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6240,7 +6462,7 @@ instruct loadB2L(iRegLNoSp dst, memory mem) %} // Load Byte (8 bit unsigned) -instruct loadUB(iRegINoSp dst, memory mem) +instruct loadUB(iRegINoSp dst, memory1 mem) %{ match(Set dst (LoadUB mem)); predicate(!needs_acquiring_load(n)); @@ -6254,7 +6476,7 @@ instruct loadUB(iRegINoSp dst, memory mem) %} // Load Byte (8 bit unsigned) into long -instruct loadUB2L(iRegLNoSp dst, memory mem) +instruct loadUB2L(iRegLNoSp dst, memory1 mem) %{ match(Set dst (ConvI2L (LoadUB mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6268,7 +6490,7 @@ instruct loadUB2L(iRegLNoSp dst, memory mem) %} // Load Short (16 bit signed) -instruct loadS(iRegINoSp dst, memory mem) +instruct loadS(iRegINoSp dst, memory2 mem) %{ match(Set dst (LoadS mem)); predicate(!needs_acquiring_load(n)); @@ -6282,7 +6504,7 @@ instruct loadS(iRegINoSp dst, memory mem) %} // Load Short (16 bit signed) into long -instruct loadS2L(iRegLNoSp dst, memory mem) +instruct loadS2L(iRegLNoSp dst, memory2 mem) %{ match(Set dst (ConvI2L (LoadS mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6296,7 +6518,7 @@ instruct loadS2L(iRegLNoSp dst, memory mem) %} // Load Char (16 bit unsigned) -instruct loadUS(iRegINoSp dst, memory mem) +instruct loadUS(iRegINoSp dst, memory2 mem) %{ match(Set dst (LoadUS mem)); predicate(!needs_acquiring_load(n)); @@ -6310,7 +6532,7 @@ instruct loadUS(iRegINoSp dst, memory mem) %} // Load Short/Char (16 bit unsigned) into long -instruct loadUS2L(iRegLNoSp dst, memory mem) +instruct loadUS2L(iRegLNoSp dst, memory2 mem) %{ match(Set dst (ConvI2L (LoadUS mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6324,7 +6546,7 @@ instruct loadUS2L(iRegLNoSp dst, memory mem) %} // Load Integer (32 bit signed) -instruct loadI(iRegINoSp dst, memory mem) +instruct loadI(iRegINoSp dst, memory4 mem) %{ match(Set dst (LoadI mem)); predicate(!needs_acquiring_load(n)); @@ -6338,7 +6560,7 @@ instruct loadI(iRegINoSp dst, memory mem) %} // Load Integer (32 bit signed) into long -instruct loadI2L(iRegLNoSp dst, memory mem) +instruct loadI2L(iRegLNoSp dst, memory4 mem) %{ match(Set dst (ConvI2L (LoadI mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6352,7 +6574,7 @@ instruct loadI2L(iRegLNoSp dst, memory mem) %} // Load Integer (32 bit unsigned) into long -instruct loadUI2L(iRegLNoSp dst, memory mem, immL_32bits mask) +instruct loadUI2L(iRegLNoSp dst, memory4 mem, immL_32bits mask) %{ match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); predicate(!needs_acquiring_load(n->in(1)->in(1)->as_Load())); @@ -6366,7 +6588,7 @@ instruct loadUI2L(iRegLNoSp dst, memory mem, immL_32bits mask) %} // Load Long (64 bit signed) -instruct loadL(iRegLNoSp dst, memory mem) +instruct loadL(iRegLNoSp dst, memory8 mem) %{ match(Set dst (LoadL mem)); predicate(!needs_acquiring_load(n)); @@ -6380,7 +6602,7 @@ instruct loadL(iRegLNoSp dst, memory mem) %} // Load Range -instruct loadRange(iRegINoSp dst, memory mem) +instruct loadRange(iRegINoSp dst, memory4 mem) %{ match(Set dst (LoadRange mem)); @@ -6393,7 +6615,7 @@ instruct loadRange(iRegINoSp dst, memory mem) %} // Load Pointer -instruct loadP(iRegPNoSp dst, memory mem) +instruct loadP(iRegPNoSp dst, memory8 mem) %{ match(Set dst (LoadP mem)); predicate(!needs_acquiring_load(n) && (n->as_Load()->barrier_data() == 0)); @@ -6407,10 +6629,10 @@ instruct loadP(iRegPNoSp dst, memory mem) %} // Load Compressed Pointer -instruct loadN(iRegNNoSp dst, memory mem) +instruct loadN(iRegNNoSp dst, memory4 mem) %{ match(Set dst (LoadN mem)); - predicate(!needs_acquiring_load(n)); + predicate(!needs_acquiring_load(n) && n->as_Load()->barrier_data() == 0); ins_cost(4 * INSN_COST); format %{ "ldrw $dst, $mem\t# compressed ptr" %} @@ -6421,7 +6643,7 @@ instruct loadN(iRegNNoSp dst, memory mem) %} // Load Klass Pointer -instruct loadKlass(iRegPNoSp dst, memory mem) +instruct loadKlass(iRegPNoSp dst, memory8 mem) %{ match(Set dst (LoadKlass mem)); predicate(!needs_acquiring_load(n)); @@ -6435,7 +6657,7 @@ instruct loadKlass(iRegPNoSp dst, memory mem) %} // Load Narrow Klass Pointer -instruct loadNKlass(iRegNNoSp dst, memory mem) +instruct loadNKlass(iRegNNoSp dst, memory4 mem) %{ match(Set dst (LoadNKlass mem)); predicate(!needs_acquiring_load(n)); @@ -6449,7 +6671,7 @@ instruct loadNKlass(iRegNNoSp dst, memory mem) %} // Load Float -instruct loadF(vRegF dst, memory mem) +instruct loadF(vRegF dst, memory4 mem) %{ match(Set dst (LoadF mem)); predicate(!needs_acquiring_load(n)); @@ -6463,7 +6685,7 @@ instruct loadF(vRegF dst, memory mem) %} // Load Double -instruct loadD(vRegD dst, memory mem) +instruct loadD(vRegD dst, memory8 mem) %{ match(Set dst (LoadD mem)); predicate(!needs_acquiring_load(n)); @@ -6666,38 +6888,8 @@ instruct loadConD(vRegD dst, immD con) %{ // Store Instructions -// Store CMS card-mark Immediate -instruct storeimmCM0(immI0 zero, memory mem) -%{ - match(Set mem (StoreCM mem zero)); - - ins_cost(INSN_COST); - format %{ "storestore (elided)\n\t" - "strb zr, $mem\t# byte" %} - - ins_encode(aarch64_enc_strb0(mem)); - - ins_pipe(istore_mem); -%} - -// Store CMS card-mark Immediate with intervening StoreStore -// needed when using CMS with no conditional card marking -instruct storeimmCM0_ordered(immI0 zero, memory mem) -%{ - match(Set mem (StoreCM mem zero)); - - ins_cost(INSN_COST * 2); - format %{ "storestore\n\t" - "dmb ishst" - "\n\tstrb zr, $mem\t# byte" %} - - ins_encode(aarch64_enc_strb0_ordered(mem)); - - ins_pipe(istore_mem); -%} - // Store Byte -instruct storeB(iRegIorL2I src, memory mem) +instruct storeB(iRegIorL2I src, memory1 mem) %{ match(Set mem (StoreB mem src)); predicate(!needs_releasing_store(n)); @@ -6711,7 +6903,7 @@ instruct storeB(iRegIorL2I src, memory mem) %} -instruct storeimmB0(immI0 zero, memory mem) +instruct storeimmB0(immI0 zero, memory1 mem) %{ match(Set mem (StoreB mem zero)); predicate(!needs_releasing_store(n)); @@ -6725,7 +6917,7 @@ instruct storeimmB0(immI0 zero, memory mem) %} // Store Char/Short -instruct storeC(iRegIorL2I src, memory mem) +instruct storeC(iRegIorL2I src, memory2 mem) %{ match(Set mem (StoreC mem src)); predicate(!needs_releasing_store(n)); @@ -6738,7 +6930,7 @@ instruct storeC(iRegIorL2I src, memory mem) ins_pipe(istore_reg_mem); %} -instruct storeimmC0(immI0 zero, memory mem) +instruct storeimmC0(immI0 zero, memory2 mem) %{ match(Set mem (StoreC mem zero)); predicate(!needs_releasing_store(n)); @@ -6753,7 +6945,7 @@ instruct storeimmC0(immI0 zero, memory mem) // Store Integer -instruct storeI(iRegIorL2I src, memory mem) +instruct storeI(iRegIorL2I src, memory4 mem) %{ match(Set mem(StoreI mem src)); predicate(!needs_releasing_store(n)); @@ -6766,7 +6958,7 @@ instruct storeI(iRegIorL2I src, memory mem) ins_pipe(istore_reg_mem); %} -instruct storeimmI0(immI0 zero, memory mem) +instruct storeimmI0(immI0 zero, memory4 mem) %{ match(Set mem(StoreI mem zero)); predicate(!needs_releasing_store(n)); @@ -6780,7 +6972,7 @@ instruct storeimmI0(immI0 zero, memory mem) %} // Store Long (64 bit signed) -instruct storeL(iRegL src, memory mem) +instruct storeL(iRegL src, memory8 mem) %{ match(Set mem (StoreL mem src)); predicate(!needs_releasing_store(n)); @@ -6794,7 +6986,7 @@ instruct storeL(iRegL src, memory mem) %} // Store Long (64 bit signed) -instruct storeimmL0(immL0 zero, memory mem) +instruct storeimmL0(immL0 zero, memory8 mem) %{ match(Set mem (StoreL mem zero)); predicate(!needs_releasing_store(n)); @@ -6808,7 +7000,7 @@ instruct storeimmL0(immL0 zero, memory mem) %} // Store Pointer -instruct storeP(iRegP src, memory mem) +instruct storeP(iRegP src, memory8 mem) %{ match(Set mem (StoreP mem src)); predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); @@ -6822,7 +7014,7 @@ instruct storeP(iRegP src, memory mem) %} // Store Pointer -instruct storeimmP0(immP0 zero, memory mem) +instruct storeimmP0(immP0 zero, memory8 mem) %{ match(Set mem (StoreP mem zero)); predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); @@ -6836,10 +7028,10 @@ instruct storeimmP0(immP0 zero, memory mem) %} // Store Compressed Pointer -instruct storeN(iRegN src, memory mem) +instruct storeN(iRegN src, memory4 mem) %{ match(Set mem (StoreN mem src)); - predicate(!needs_releasing_store(n)); + predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); ins_cost(INSN_COST); format %{ "strw $src, $mem\t# compressed ptr" %} @@ -6849,10 +7041,10 @@ instruct storeN(iRegN src, memory mem) ins_pipe(istore_reg_mem); %} -instruct storeImmN0(immN0 zero, memory mem) +instruct storeImmN0(immN0 zero, memory4 mem) %{ match(Set mem (StoreN mem zero)); - predicate(!needs_releasing_store(n)); + predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); ins_cost(INSN_COST); format %{ "strw zr, $mem\t# compressed ptr" %} @@ -6863,7 +7055,7 @@ instruct storeImmN0(immN0 zero, memory mem) %} // Store Float -instruct storeF(vRegF src, memory mem) +instruct storeF(vRegF src, memory4 mem) %{ match(Set mem (StoreF mem src)); predicate(!needs_releasing_store(n)); @@ -6880,7 +7072,7 @@ instruct storeF(vRegF src, memory mem) // implement storeImmF0 and storeFImmPacked // Store Double -instruct storeD(vRegD src, memory mem) +instruct storeD(vRegD src, memory8 mem) %{ match(Set mem (StoreD mem src)); predicate(!needs_releasing_store(n)); @@ -6894,7 +7086,7 @@ instruct storeD(vRegD src, memory mem) %} // Store Compressed Klass Pointer -instruct storeNKlass(iRegN src, memory mem) +instruct storeNKlass(iRegN src, memory4 mem) %{ predicate(!needs_releasing_store(n)); match(Set mem (StoreNKlass mem src)); @@ -6913,7 +7105,7 @@ instruct storeNKlass(iRegN src, memory mem) // prefetch instructions // Must be safe to execute with invalid address (cannot fault). -instruct prefetchalloc( memory mem ) %{ +instruct prefetchalloc( memory8 mem ) %{ match(PrefetchAllocation mem); ins_cost(INSN_COST); @@ -7086,6 +7278,7 @@ instruct loadP_volatile(iRegPNoSp dst, /* sync_memory*/indirect mem) instruct loadN_volatile(iRegNNoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadN mem)); + predicate(n->as_Load()->barrier_data() == 0); ins_cost(VOLATILE_REF_COST); format %{ "ldarw $dst, $mem\t# compressed ptr" %} @@ -7253,6 +7446,7 @@ instruct storeimmP0_volatile(immP0 zero, /* sync_memory*/indirect mem) instruct storeN_volatile(iRegN src, /* sync_memory*/indirect mem) %{ match(Set mem (StoreN mem src)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(VOLATILE_REF_COST); format %{ "stlrw $src, $mem\t# compressed ptr" %} @@ -7265,6 +7459,7 @@ instruct storeN_volatile(iRegN src, /* sync_memory*/indirect mem) instruct storeimmN0_volatile(immN0 zero, /* sync_memory*/indirect mem) %{ match(Set mem (StoreN mem zero)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(VOLATILE_REF_COST); format %{ "stlrw zr, $mem\t# compressed ptr" %} @@ -7482,7 +7677,7 @@ instruct popCountI(iRegINoSp dst, iRegIorL2I src, vRegF tmp) %{ ins_pipe(pipe_class_default); %} -instruct popCountI_mem(iRegINoSp dst, memory mem, vRegF tmp) %{ +instruct popCountI_mem(iRegINoSp dst, memory4 mem, vRegF tmp) %{ match(Set dst (PopCountI (LoadI mem))); effect(TEMP tmp); ins_cost(INSN_COST * 13); @@ -7523,7 +7718,7 @@ instruct popCountL(iRegINoSp dst, iRegL src, vRegD tmp) %{ ins_pipe(pipe_class_default); %} -instruct popCountL_mem(iRegINoSp dst, memory mem, vRegD tmp) %{ +instruct popCountL_mem(iRegINoSp dst, memory8 mem, vRegD tmp) %{ match(Set dst (PopCountL (LoadL mem))); effect(TEMP tmp); ins_cost(INSN_COST * 13); @@ -8061,6 +8256,7 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapN mem (Binary oldval newval))); + predicate(n->as_LoadStore()->barrier_data() == 0); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8175,7 +8371,7 @@ instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP new instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndSwapN mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); @@ -8280,6 +8476,7 @@ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL ne // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -8389,7 +8586,7 @@ instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -8501,6 +8698,7 @@ instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL ne // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8620,7 +8818,7 @@ instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); @@ -8681,6 +8879,7 @@ instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) %{ %} instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set prev (GetAndSetN mem newv)); ins_cost(2 * VOLATILE_REF_COST); format %{ "atomic_xchgw $prev, $newv, [$mem]" %} @@ -8724,7 +8923,7 @@ instruct get_and_setLAcq(indirect mem, iRegL newv, iRegLNoSp prev) %{ %} instruct get_and_setNAcq(indirect mem, iRegN newv, iRegINoSp prev) %{ - predicate(needs_acquiring_load_exclusive(n)); + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set prev (GetAndSetN mem newv)); ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgw_acq $prev, $newv, [$mem]" %} @@ -16672,7 +16871,7 @@ instruct compressBitsI_reg(iRegINoSp dst, iRegIorL2I src, iRegIorL2I mask, ins_pipe(pipe_slow); %} -instruct compressBitsI_memcon(iRegINoSp dst, memory mem, immI mask, +instruct compressBitsI_memcon(iRegINoSp dst, memory4 mem, immI mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (CompressBits (LoadI mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -16709,7 +16908,7 @@ instruct compressBitsL_reg(iRegLNoSp dst, iRegL src, iRegL mask, ins_pipe(pipe_slow); %} -instruct compressBitsL_memcon(iRegLNoSp dst, memory mem, immL mask, +instruct compressBitsL_memcon(iRegLNoSp dst, memory8 mem, immL mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (CompressBits (LoadL mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -16746,7 +16945,7 @@ instruct expandBitsI_reg(iRegINoSp dst, iRegIorL2I src, iRegIorL2I mask, ins_pipe(pipe_slow); %} -instruct expandBitsI_memcon(iRegINoSp dst, memory mem, immI mask, +instruct expandBitsI_memcon(iRegINoSp dst, memory4 mem, immI mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (ExpandBits (LoadI mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -16784,7 +16983,7 @@ instruct expandBitsL_reg(iRegLNoSp dst, iRegL src, iRegL mask, %} -instruct expandBitsL_memcon(iRegINoSp dst, memory mem, immL mask, +instruct expandBitsL_memcon(iRegINoSp dst, memory8 mem, immL mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (ExpandBits (LoadL mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index cdbc4103df89a..0d3a240cecfd3 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -345,7 +345,7 @@ source %{ // ------------------------------ Vector load/store ---------------------------- // Load Vector (16 bits) -instruct loadV2(vReg dst, vmem mem) %{ +instruct loadV2(vReg dst, vmem2 mem) %{ predicate(n->as_LoadVector()->memory_size() == 2); match(Set dst (LoadVector mem)); format %{ "loadV2 $dst, $mem\t# vector (16 bits)" %} @@ -354,7 +354,7 @@ instruct loadV2(vReg dst, vmem mem) %{ %} // Store Vector (16 bits) -instruct storeV2(vReg src, vmem mem) %{ +instruct storeV2(vReg src, vmem2 mem) %{ predicate(n->as_StoreVector()->memory_size() == 2); match(Set mem (StoreVector mem src)); format %{ "storeV2 $mem, $src\t# vector (16 bits)" %} @@ -363,7 +363,7 @@ instruct storeV2(vReg src, vmem mem) %{ %} // Load Vector (32 bits) -instruct loadV4(vReg dst, vmem mem) %{ +instruct loadV4(vReg dst, vmem4 mem) %{ predicate(n->as_LoadVector()->memory_size() == 4); match(Set dst (LoadVector mem)); format %{ "loadV4 $dst, $mem\t# vector (32 bits)" %} @@ -372,7 +372,7 @@ instruct loadV4(vReg dst, vmem mem) %{ %} // Store Vector (32 bits) -instruct storeV4(vReg src, vmem mem) %{ +instruct storeV4(vReg src, vmem4 mem) %{ predicate(n->as_StoreVector()->memory_size() == 4); match(Set mem (StoreVector mem src)); format %{ "storeV4 $mem, $src\t# vector (32 bits)" %} @@ -381,7 +381,7 @@ instruct storeV4(vReg src, vmem mem) %{ %} // Load Vector (64 bits) -instruct loadV8(vReg dst, vmem mem) %{ +instruct loadV8(vReg dst, vmem8 mem) %{ predicate(n->as_LoadVector()->memory_size() == 8); match(Set dst (LoadVector mem)); format %{ "loadV8 $dst, $mem\t# vector (64 bits)" %} @@ -390,7 +390,7 @@ instruct loadV8(vReg dst, vmem mem) %{ %} // Store Vector (64 bits) -instruct storeV8(vReg src, vmem mem) %{ +instruct storeV8(vReg src, vmem8 mem) %{ predicate(n->as_StoreVector()->memory_size() == 8); match(Set mem (StoreVector mem src)); format %{ "storeV8 $mem, $src\t# vector (64 bits)" %} @@ -399,7 +399,7 @@ instruct storeV8(vReg src, vmem mem) %{ %} // Load Vector (128 bits) -instruct loadV16(vReg dst, vmem mem) %{ +instruct loadV16(vReg dst, vmem16 mem) %{ predicate(n->as_LoadVector()->memory_size() == 16); match(Set dst (LoadVector mem)); format %{ "loadV16 $dst, $mem\t# vector (128 bits)" %} @@ -408,7 +408,7 @@ instruct loadV16(vReg dst, vmem mem) %{ %} // Store Vector (128 bits) -instruct storeV16(vReg src, vmem mem) %{ +instruct storeV16(vReg src, vmem16 mem) %{ predicate(n->as_StoreVector()->memory_size() == 16); match(Set mem (StoreVector mem src)); format %{ "storeV16 $mem, $src\t# vector (128 bits)" %} diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index 020a75b51fa8f..99708e9ef317d 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -338,7 +338,7 @@ dnl VECTOR_LOAD_STORE($1, $2, $3, $4, $5 ) dnl VECTOR_LOAD_STORE(type, nbytes, arg_name, nbits, size) define(`VECTOR_LOAD_STORE', ` // ifelse(load, $1, Load, Store) Vector ($4 bits) -instruct $1V$2(vReg $3, vmem mem) %{ +instruct $1V$2(vReg $3, vmem$2 mem) %{ predicate(`n->as_'ifelse(load, $1, Load, Store)Vector()->memory_size() == $2); match(Set ifelse(load, $1, dst (LoadVector mem), mem (StoreVector mem src))); format %{ "$1V$2 ifelse(load, $1, `$dst, $mem', `$mem, $src')\t# vector ($4 bits)" %} diff --git a/src/hotspot/cpu/aarch64/ad_encode.m4 b/src/hotspot/cpu/aarch64/ad_encode.m4 index e3d8ea661b60a..008dbd2c9369c 100644 --- a/src/hotspot/cpu/aarch64/ad_encode.m4 +++ b/src/hotspot/cpu/aarch64/ad_encode.m4 @@ -34,7 +34,7 @@ define(access, ` define(load,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2($1 dst, memory mem) %{dnl + enc_class aarch64_enc_$2($1 dst, memory$5 mem) %{dnl access(dst,$2,$3,$4,$5)')dnl load(iRegI,ldrsbw,,,1) load(iRegI,ldrsb,,,1) @@ -53,12 +53,12 @@ load(vRegD,ldrd,Float,,8) define(STORE,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2($1 src, memory mem) %{dnl + enc_class aarch64_enc_$2($1 src, memory$5 mem) %{dnl access(src,$2,$3,$4,$5)')dnl define(STORE0,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2`'0(memory mem) %{ + enc_class aarch64_enc_$2`'0(memory$4 mem) %{ choose(masm,zr,$2,$mem->opcode(), as_$3Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp,$4)')dnl STORE(iRegI,strb,,,1) @@ -82,7 +82,7 @@ STORE(vRegD,strd,Float,,8) // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0_ordered(memory mem) %{ + enc_class aarch64_enc_strb0_ordered(memory4 mem) %{ __ membar(Assembler::StoreStore); loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 5e116d82761ac..3d1be91e9b232 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -275,14 +275,14 @@ void LIR_Assembler::osr_entry() { // verify the interpreter's monitor has a non-null object { Label L; - __ ldr(rscratch1, Address(OSR_buf, slot_offset + 1*BytesPerWord)); + __ ldr(rscratch1, __ form_address(rscratch1, OSR_buf, slot_offset + 1*BytesPerWord, 0)); __ cbnz(rscratch1, L); __ stop("locked object is null"); __ bind(L); } #endif - __ ldr(r19, Address(OSR_buf, slot_offset)); - __ ldr(r20, Address(OSR_buf, slot_offset + BytesPerWord)); + __ ldr(r19, __ form_address(rscratch1, OSR_buf, slot_offset, 0)); + __ ldr(r20, __ form_address(rscratch1, OSR_buf, slot_offset + BytesPerWord, 0)); __ str(r19, frame_map()->address_for_monitor_lock(i)); __ str(r20, frame_map()->address_for_monitor_object(i)); } @@ -990,10 +990,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch __ decode_heap_oop(dest->as_register()); } - if (!(UseZGC && !ZGenerational)) { - // Load barrier has not yet been applied, so ZGC can't verify the oop here - __ verify_oop(dest->as_register()); - } + __ verify_oop(dest->as_register()); } } @@ -1168,8 +1165,8 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { if (op->init_check()) { - __ ldrb(rscratch1, Address(op->klass()->as_register(), - InstanceKlass::init_state_offset())); + __ lea(rscratch1, Address(op->klass()->as_register(), InstanceKlass::init_state_offset())); + __ ldarb(rscratch1, rscratch1); __ cmpw(rscratch1, InstanceKlass::fully_initialized); add_debug_info_for_null_check_here(op->stub()->info()); __ br(Assembler::NE, *op->stub()->entry()); diff --git a/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp index dabafb9288b83..4bd509880f29c 100644 --- a/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp @@ -64,31 +64,4 @@ void C2EntryBarrierStub::emit(C2_MacroAssembler& masm) { __ emit_int32(0); // nmethod guard value } -int C2HandleAnonOMOwnerStub::max_size() const { - // Max size of stub has been determined by testing with 0, in which case - // C2CodeStubList::emit() will throw an assertion and report the actual size that - // is needed. - return 24; -} - -void C2HandleAnonOMOwnerStub::emit(C2_MacroAssembler& masm) { - __ bind(entry()); - Register mon = monitor(); - Register t = tmp(); - assert(t != noreg, "need tmp register"); - - // Fix owner to be the current thread. - __ str(rthread, Address(mon, ObjectMonitor::owner_offset())); - - // Pop owner object from lock-stack. - __ ldrw(t, Address(rthread, JavaThread::lock_stack_top_offset())); - __ subw(t, t, oopSize); -#ifdef ASSERT - __ str(zr, Address(rthread, t)); -#endif - __ strw(t, Address(rthread, JavaThread::lock_stack_top_offset())); - - __ b(continuation()); -} - #undef __ diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 62831ee72ba05..b29be7213baf4 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -217,7 +217,7 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Registe // StoreLoad achieves this. membar(StoreLoad); - // Check if the entry lists are empty. + // Check if the entry lists are empty (EntryList first - by convention). ldr(rscratch1, Address(tmp, ObjectMonitor::EntryList_offset())); ldr(tmpReg, Address(tmp, ObjectMonitor::cxq_offset())); orr(rscratch1, rscratch1, tmpReg); @@ -538,7 +538,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Regi // StoreLoad achieves this. membar(StoreLoad); - // Check if the entry lists are empty. + // Check if the entry lists are empty (EntryList first - by convention). ldr(rscratch1, Address(t1_monitor, ObjectMonitor::EntryList_offset())); ldr(t3_t, Address(t1_monitor, ObjectMonitor::cxq_offset())); orr(rscratch1, rscratch1, t3_t); diff --git a/src/hotspot/cpu/aarch64/cas.m4 b/src/hotspot/cpu/aarch64/cas.m4 index f8aac0c4939fa..7e13e153db18a 100644 --- a/src/hotspot/cpu/aarch64/cas.m4 +++ b/src/hotspot/cpu/aarch64/cas.m4 @@ -45,7 +45,9 @@ define(`CAS_INSN', // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchange$1$6(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), + $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), `dnl') match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); @@ -122,7 +124,9 @@ define(`CAS_INSN3', // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), + $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), `dnl') match(Set res (WeakCompareAndSwap$1 mem (Binary oldval newval))); diff --git a/src/hotspot/cpu/aarch64/copy_aarch64.hpp b/src/hotspot/cpu/aarch64/copy_aarch64.hpp index 0ff9ace59cc2f..5ccf2cd835ee7 100644 --- a/src/hotspot/cpu/aarch64/copy_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/copy_aarch64.hpp @@ -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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -64,28 +64,34 @@ static void pd_zero_to_bytes(void* to, size_t count) { " br %[t0];\n" \ " .align 5;\n" \ "0:" \ +" hint #0x24; // bti j\n" \ " b 1f;\n" \ " .align 5;\n" \ +" hint #0x24; // bti j\n" \ " ldr %[t0], [%[s], #0];\n" \ " str %[t0], [%[d], #0];\n" \ " b 1f;\n" \ " .align 5;\n" \ +" hint #0x24; // bti j\n" \ " ldp %[t0], %[t1], [%[s], #0];\n" \ " stp %[t0], %[t1], [%[d], #0];\n" \ " b 1f;\n" \ " .align 5;\n" \ +" hint #0x24; // bti j\n" \ " ldp %[t0], %[t1], [%[s], #0];\n" \ " ldr %[t2], [%[s], #16];\n" \ " stp %[t0], %[t1], [%[d], #0];\n" \ " str %[t2], [%[d], #16];\n" \ " b 1f;\n" \ " .align 5;\n" \ +" hint #0x24; // bti j\n" \ " ldp %[t0], %[t1], [%[s], #0];\n" \ " ldp %[t2], %[t3], [%[s], #16];\n" \ " stp %[t0], %[t1], [%[d], #0];\n" \ " stp %[t2], %[t3], [%[d], #16];\n" \ " b 1f;\n" \ " .align 5;\n" \ +" hint #0x24; // bti j\n" \ " ldp %[t0], %[t1], [%[s], #0];\n" \ " ldp %[t2], %[t3], [%[s], #16];\n" \ " ldr %[t4], [%[s], #32];\n" \ @@ -94,6 +100,7 @@ static void pd_zero_to_bytes(void* to, size_t count) { " str %[t4], [%[d], #32];\n" \ " b 1f;\n" \ " .align 5;\n" \ +" hint #0x24; // bti j\n" \ " ldp %[t0], %[t1], [%[s], #0];\n" \ " ldp %[t2], %[t3], [%[s], #16];\n" \ " ldp %[t4], %[t5], [%[s], #32];\n" \ @@ -103,6 +110,7 @@ static void pd_zero_to_bytes(void* to, size_t count) { " stp %[t4], %[t5], [%[d], #32];\n" \ " b 1f;\n" \ " .align 5;\n" \ +" hint #0x24; // bti j\n" \ " ldr %[t6], [%[s], #0];\n" \ " ldp %[t0], %[t1], [%[s], #8];\n" \ " ldp %[t2], %[t3], [%[s], #24];\n" \ @@ -110,6 +118,7 @@ static void pd_zero_to_bytes(void* to, size_t count) { " str %[t6], [%[d]], #8;\n" \ " b 2b;\n" \ " .align 5;\n" \ +" hint #0x24; // bti j\n" \ " ldp %[t0], %[t1], [%[s], #0];\n" \ " ldp %[t2], %[t3], [%[s], #16];\n" \ " ldp %[t4], %[t5], [%[s], #32];\n" \ diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp index d02038b6e9193..b978c350ce131 100644 --- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp @@ -38,7 +38,10 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> @@ -95,6 +98,54 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ pop(saved_regs, sp); } +static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register thread, const Register value, const Register temp1, const Register temp2) { + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + __ ldr(temp1, Address(thread, in_bytes(index_offset))); // temp1 := *(index address) + __ cbz(temp1, runtime); // jump to runtime if index == 0 (full buffer) + // The buffer is not full, store value into it. + __ sub(temp1, temp1, wordSize); // temp1 := next index + __ str(temp1, Address(thread, in_bytes(index_offset))); // *(index address) := next index + __ ldr(temp2, Address(thread, in_bytes(buffer_offset))); // temp2 := buffer address + __ str(value, Address(temp2, temp1)); // *(buffer address + next index) := value +} + +static void generate_pre_barrier_fast_path(MacroAssembler* masm, + const Register thread, + const Register tmp1) { + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ ldrw(tmp1, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldrb(tmp1, in_progress); + } +} + +static void generate_pre_barrier_slow_path(MacroAssembler* masm, + const Register obj, + const Register pre_val, + const Register thread, + const Register tmp1, + const Register tmp2, + Label& done, + Label& runtime) { + // Do we need to load the previous value? + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + } + // Is the previous value null? + __ cbz(pre_val, done); + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, + thread, pre_val, tmp1, tmp2); + __ b(done); +} + void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, @@ -115,43 +166,10 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, assert_different_registers(obj, pre_val, tmp1, tmp2); assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - - // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ ldrw(tmp1, in_progress); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ ldrb(tmp1, in_progress); - } + generate_pre_barrier_fast_path(masm, thread, tmp1); + // If marking is not active (*(mark queue active address) == 0), jump to done __ cbzw(tmp1, done); - - // Do we need to load the previous value? - if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); - } - - // Is the previous value null? - __ cbz(pre_val, done); - - // Can we store original value in the thread's buffer? - // Is index == 0? - // (The index field is typed as size_t.) - - __ ldr(tmp1, index); // tmp := *index_adr - __ cbz(tmp1, runtime); // tmp == 0? - // If yes, goto runtime - - __ sub(tmp1, tmp1, wordSize); // tmp := tmp - wordSize - __ str(tmp1, index); // *index_adr := tmp - __ ldr(tmp2, buffer); - __ add(tmp1, tmp1, tmp2); // tmp := tmp + *buffer_adr - - // Record the previous value - __ str(pre_val, Address(tmp1, 0)); - __ b(done); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, done, runtime); __ bind(runtime); @@ -182,6 +200,50 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, } +static void generate_post_barrier_fast_path(MacroAssembler* masm, + const Register store_addr, + const Register new_val, + const Register tmp1, + const Register tmp2, + Label& done, + bool new_val_may_be_null) { + // Does store cross heap regions? + __ eor(tmp1, store_addr, new_val); // tmp1 := store address ^ new value + __ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes) + __ cbz(tmp1, done); + // Crosses regions, storing null? + if (new_val_may_be_null) { + __ cbz(new_val, done); + } + // Storing region crossing non-null, is card young? + __ lsr(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base + __ load_byte_map_base(tmp2); // tmp2 := card table base address + __ add(tmp1, tmp1, tmp2); // tmp1 := card address + __ ldrb(tmp2, Address(tmp1)); // tmp2 := card + __ cmpw(tmp2, (int)G1CardTable::g1_young_card_val()); // tmp2 := card == young_card_val? +} + +static void generate_post_barrier_slow_path(MacroAssembler* masm, + const Register thread, + const Register tmp1, + const Register tmp2, + Label& done, + Label& runtime) { + __ membar(Assembler::StoreLoad); // StoreLoad membar + __ ldrb(tmp2, Address(tmp1)); // tmp2 := card + __ cbzw(tmp2, done); + // Storing a region crossing, non-null oop, card is clean. + // Dirty card and log. + STATIC_ASSERT(CardTable::dirty_card_val() == 0); + __ strb(zr, Address(tmp1)); // *(card address) := dirty_card_val + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, + thread, tmp1, tmp2, rscratch1); + __ b(done); +} + void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, @@ -194,70 +256,116 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - BarrierSet* bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); - CardTable* ct = ctbs->card_table(); - Label done; Label runtime; - // Does store cross heap regions? + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */); + // If card is young, jump to done + __ br(Assembler::EQ, done); + generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime); - __ eor(tmp1, store_addr, new_val); - __ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); - __ cbz(tmp1, done); + __ bind(runtime); + // save the live input values + RegSet saved = RegSet::of(store_addr); + __ push(saved, sp); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread); + __ pop(saved, sp); - // crosses regions, storing null? + __ bind(done); +} - __ cbz(new_val, done); +#if defined(COMPILER2) - // storing region crossing non-null, is card already dirty? +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { + SaveLiveRegisters save_registers(masm, stub); + if (c_rarg0 != arg) { + __ mov(c_rarg0, arg); + } + __ mov(c_rarg1, rthread); + __ mov(rscratch1, runtime_path); + __ blr(rscratch1); +} - const Register card_addr = tmp1; +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* stub) { + assert(thread == rthread, "must be"); + assert_different_registers(obj, pre_val, tmp1, tmp2); + assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - __ lsr(card_addr, store_addr, CardTable::card_shift()); + stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2); - // get the address of the card - __ load_byte_map_base(tmp2); - __ add(card_addr, card_addr, tmp2); - __ ldrb(tmp2, Address(card_addr)); - __ cmpw(tmp2, (int)G1CardTable::g1_young_card_val()); - __ br(Assembler::EQ, done); + generate_pre_barrier_fast_path(masm, thread, tmp1); + // If marking is active (*(mark queue active address) != 0), jump to stub (slow path) + __ cbnzw(tmp1, *stub->entry()); - assert((int)CardTable::dirty_card_val() == 0, "must be 0"); + __ bind(*stub->continuation()); +} - __ membar(Assembler::StoreLoad); +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); + Register tmp2 = stub->tmp2(); - __ ldrb(tmp2, Address(card_addr)); - __ cbzw(tmp2, done); + __ bind(*stub->entry()); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, *stub->continuation(), runtime); - // storing a region crossing, non-null oop, card is clean. - // dirty card and log. + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); + __ b(*stub->continuation()); +} - __ strb(zr, Address(card_addr)); +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* stub) { + assert(thread == rthread, "must be"); + assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, + rscratch1); + assert(store_addr != noreg && new_val != noreg && tmp1 != noreg + && tmp2 != noreg, "expecting a register"); - __ ldr(rscratch1, queue_index); - __ cbz(rscratch1, runtime); - __ sub(rscratch1, rscratch1, wordSize); - __ str(rscratch1, queue_index); + stub->initialize_registers(thread, tmp1, tmp2); - __ ldr(tmp2, buffer); - __ str(card_addr, Address(tmp2, rscratch1)); - __ b(done); + bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null); + // If card is not young, jump to stub (slow path) + __ br(Assembler::NE, *stub->entry()); - __ bind(runtime); - // save the live input values - RegSet saved = RegSet::of(store_addr); - __ push(saved, sp); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); - __ pop(saved, sp); + __ bind(*stub->continuation()); +} - __ bind(done); +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); // tmp1 holds the card address. + Register tmp2 = stub->tmp2(); + assert(stub->tmp3() == noreg, "not needed in this platform"); + + __ bind(*stub->entry()); + generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); + __ b(*stub->continuation()); } +#endif // COMPILER2 + void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp2) { bool on_oop = is_reference_type(type); diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp index 7b4bc8cdc49de..4baa18cb94544 100644 --- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp @@ -33,6 +33,8 @@ class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -69,6 +71,27 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); #endif +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* c2_stub); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif + void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp2); }; diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad new file mode 100644 index 0000000000000..081a67d68807b --- /dev/null +++ b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad @@ -0,0 +1,680 @@ +// +// 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. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_aarch64.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void write_barrier_pre(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2, + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, rthread, tmp1, tmp2, stub); +} + +static void write_barrier_post(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, rthread, tmp1, tmp2, stub); +} + +%} + +// BEGIN This section of the file is automatically generated. Do not edit -------------- + +// This section is generated from g1_aarch64.m4 + + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StoreP(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(INSN_COST); + format %{ "str $src, $mem\t# ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ str($src$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StorePVolatile(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "stlr $src, $mem\t# ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ stlr($src$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_class_memory); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StoreN(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(INSN_COST); + format %{ "strw $src, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ strw($src$$Register, $mem$$Register); + if ((barrier_data() & G1C2BarrierPost) != 0) { + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ decode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + } + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StoreNVolatile(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "stlrw $src, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ stlrw($src$$Register, $mem$$Register); + if ((barrier_data() & G1C2BarrierPost) != 0) { + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ decode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + } + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_class_memory); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(INSN_COST); + format %{ "encode_heap_oop $tmp1, $src\n\t" + "strw $tmp1, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ encode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + __ strw($tmp1$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1EncodePAndStoreNVolatile(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "encode_heap_oop $tmp1, $src\n\t" + "stlrw $tmp1, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ encode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + __ stlrw($tmp1$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_class_memory); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $res = $mem, $oldval, $newval\t# ptr" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP and its Acq variant. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + false /* acquire */, true /* release */, false /* weak */, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# ptr" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP and its Acq variant. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + true /* acquire */, true /* release */, false /* weak */, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $res = $mem, $oldval, $newval\t# narrow oop" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + false /* acquire */, true /* release */, false /* weak */, $res$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# narrow oop" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + true /* acquire */, true /* release */, false /* weak */, $res$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapP(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $mem, $oldval, $newval\t# (ptr)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + false /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (ptr)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + true /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapN(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $mem, $oldval, $newval\t# (narrow oop)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + false /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (narrow oop)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + true /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetP(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "atomic_xchg $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchg($preval$$Register, $newval$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "atomic_xchg_acq $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgal($preval$$Register, $newval$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetN(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetN mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "atomic_xchgw $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgw($preval$$Register, $newval$$Register, $mem$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetNAcq(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetN mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "atomic_xchgw_acq $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgalw($preval$$Register, $newval$$Register, $mem$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + // This instruction does not need an acquiring counterpart because it is only + // used for reference loading (Reference::get()). The same holds for g1LoadN. + predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(4 * INSN_COST); + format %{ "ldr $dst, $mem\t# ptr" %} + ins_encode %{ + __ ldr($dst$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(iload_reg_mem); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadN mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(4 * INSN_COST); + format %{ "ldrw $dst, $mem\t# compressed ptr" %} + ins_encode %{ + __ ldrw($dst$$Register, $mem$$Register); + if ((barrier_data() & G1C2BarrierPre) != 0) { + __ decode_heap_oop($tmp1$$Register, $dst$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + } + %} + ins_pipe(iload_reg_mem); +%} + +// END This section of the file is automatically generated. Do not edit -------------- diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4 b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4 new file mode 100644 index 0000000000000..8fb1f7e8e428b --- /dev/null +++ b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4 @@ -0,0 +1,384 @@ +dnl Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +dnl +dnl This code is free software; you can redistribute it and/or modify it +dnl under the terms of the GNU General Public License version 2 only, as +dnl published by the Free Software Foundation. +dnl +dnl This code is distributed in the hope that it will be useful, but WITHOUT +dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +dnl version 2 for more details (a copy is included in the LICENSE file that +dnl accompanied this code). +dnl +dnl You should have received a copy of the GNU General Public License version +dnl 2 along with this work; if not, write to the Free Software Foundation, +dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +dnl +dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +dnl or visit www.oracle.com if you need additional information or have any +dnl questions. +dnl +// BEGIN This section of the file is automatically generated. Do not edit -------------- + +// This section is generated from g1_aarch64.m4 + +define(`STOREP_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StoreP$1(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Volatile,'needs_releasing_store(n)`,'!needs_releasing_store(n)`) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Volatile,VOLATILE_REF_COST,INSN_COST)); + format %{ "$2 $src, $mem\t# ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ $2($src$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(ifelse($1,Volatile,pipe_class_memory,istore_reg_mem)); +%}')dnl +STOREP_INSN(,str) +STOREP_INSN(Volatile,stlr) +dnl +define(`STOREN_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StoreN$1(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Volatile,'needs_releasing_store(n)`,'!needs_releasing_store(n)`) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Volatile,VOLATILE_REF_COST,INSN_COST)); + format %{ "$2 $src, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ $2($src$$Register, $mem$$Register); + if ((barrier_data() & G1C2BarrierPost) != 0) { + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ decode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + } + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(ifelse($1,Volatile,pipe_class_memory,istore_reg_mem)); +%}')dnl +STOREN_INSN(,strw) +STOREN_INSN(Volatile,stlrw) +dnl +define(`ENCODESTOREN_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1EncodePAndStoreN$1(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Volatile,'needs_releasing_store(n)`,'!needs_releasing_store(n)`) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Volatile,VOLATILE_REF_COST,INSN_COST)); + format %{ "encode_heap_oop $tmp1, $src\n\t" + "$2 $tmp1, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ encode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + __ $2($tmp1$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(ifelse($1,Volatile,pipe_class_memory,istore_reg_mem)); +%}')dnl +ENCODESTOREN_INSN(,strw) +ENCODESTOREN_INSN(Volatile,stlrw) +dnl +define(`CAEP_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangeP$1(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "cmpxchg$2 $res = $mem, $oldval, $newval\t# ptr" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP and its Acq variant. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + $3 /* acquire */, true /* release */, false /* weak */, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%}')dnl +CAEP_INSN(,,false) +CAEP_INSN(Acq,_acq,true) +dnl +define(`CAEN_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangeN$1(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "cmpxchg$2 $res = $mem, $oldval, $newval\t# narrow oop" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + $3 /* acquire */, true /* release */, false /* weak */, $res$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%}')dnl +CAEN_INSN(,,false) +CAEN_INSN(Acq,_acq,true) +dnl +define(`CASP_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapP$1(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "cmpxchg$2 $mem, $oldval, $newval\t# (ptr)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + $3 /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%}')dnl +CASP_INSN(,,false) +CASP_INSN(Acq,_acq,true) +dnl +define(`CASN_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapN$1(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "cmpxchg$2 $mem, $oldval, $newval\t# (narrow oop)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + $3 /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%}')dnl +CASN_INSN(,,false) +CASN_INSN(Acq,_acq,true) +dnl +define(`XCHGP_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetP$1(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "atomic_xchg$2 $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ $3($preval$$Register, $newval$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%}')dnl +XCHGP_INSN(,,atomic_xchg) +XCHGP_INSN(Acq,_acq,atomic_xchgal) +dnl +define(`XCHGN_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetN$1(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetN mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "$2 $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ $3($preval$$Register, $newval$$Register, $mem$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%}')dnl +XCHGN_INSN(,atomic_xchgw,atomic_xchgw) +XCHGN_INSN(Acq,atomic_xchgw_acq,atomic_xchgalw) + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + // This instruction does not need an acquiring counterpart because it is only + // used for reference loading (Reference::get()). The same holds for g1LoadN. + predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(4 * INSN_COST); + format %{ "ldr $dst, $mem\t# ptr" %} + ins_encode %{ + __ ldr($dst$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(iload_reg_mem); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadN mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(4 * INSN_COST); + format %{ "ldrw $dst, $mem\t# compressed ptr" %} + ins_encode %{ + __ ldrw($dst$$Register, $mem$$Register); + if ((barrier_data() & G1C2BarrierPre) != 0) { + __ decode_heap_oop($tmp1$$Register, $dst$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + } + %} + ins_pipe(iload_reg_mem); +%} + +// END This section of the file is automatically generated. Do not edit -------------- diff --git a/src/hotspot/cpu/aarch64/gc/x/xBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/x/xBarrierSetAssembler_aarch64.cpp deleted file mode 100644 index 5c891e8c170fb..0000000000000 --- a/src/hotspot/cpu/aarch64/gc/x/xBarrierSetAssembler_aarch64.cpp +++ /dev/null @@ -1,462 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/codeBlob.hpp" -#include "code/vmreg.inline.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xBarrierSet.hpp" -#include "gc/x/xBarrierSetAssembler.hpp" -#include "gc/x/xBarrierSetRuntime.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/sharedRuntime.hpp" -#include "utilities/macros.hpp" -#ifdef COMPILER1 -#include "c1/c1_LIRAssembler.hpp" -#include "c1/c1_MacroAssembler.hpp" -#include "gc/x/c1/xBarrierSetC1.hpp" -#endif // COMPILER1 -#ifdef COMPILER2 -#include "gc/x/c2/xBarrierSetC2.hpp" -#endif // COMPILER2 - -#ifdef PRODUCT -#define BLOCK_COMMENT(str) /* nothing */ -#else -#define BLOCK_COMMENT(str) __ block_comment(str) -#endif - -#undef __ -#define __ masm-> - -void XBarrierSetAssembler::load_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Register dst, - Address src, - Register tmp1, - Register tmp2) { - if (!XBarrierSet::barrier_needed(decorators, type)) { - // Barrier not needed - BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2); - return; - } - - assert_different_registers(rscratch1, rscratch2, src.base()); - assert_different_registers(rscratch1, rscratch2, dst); - - Label done; - - // Load bad mask into scratch register. - __ ldr(rscratch1, address_bad_mask_from_thread(rthread)); - __ lea(rscratch2, src); - __ ldr(dst, src); - - // Test reference against bad mask. If mask bad, then we need to fix it up. - __ tst(dst, rscratch1); - __ br(Assembler::EQ, done); - - __ enter(/*strip_ret_addr*/true); - - __ push_call_clobbered_registers_except(RegSet::of(dst)); - - if (c_rarg0 != dst) { - __ mov(c_rarg0, dst); - } - __ mov(c_rarg1, rscratch2); - - __ call_VM_leaf(XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), 2); - - // Make sure dst has the return value. - if (dst != r0) { - __ mov(dst, r0); - } - - __ pop_call_clobbered_registers_except(RegSet::of(dst)); - __ leave(); - - __ bind(done); -} - -#ifdef ASSERT - -void XBarrierSetAssembler::store_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Address dst, - Register val, - Register tmp1, - Register tmp2, - Register tmp3) { - // Verify value - if (is_reference_type(type)) { - // Note that src could be noreg, which means we - // are storing null and can skip verification. - if (val != noreg) { - Label done; - - // tmp1, tmp2 and tmp3 are often set to noreg. - RegSet savedRegs = RegSet::of(rscratch1); - __ push(savedRegs, sp); - - __ ldr(rscratch1, address_bad_mask_from_thread(rthread)); - __ tst(val, rscratch1); - __ br(Assembler::EQ, done); - __ stop("Verify oop store failed"); - __ should_not_reach_here(); - __ bind(done); - __ pop(savedRegs, sp); - } - } - - // Store value - BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, noreg); -} - -#endif // ASSERT - -void XBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, - DecoratorSet decorators, - bool is_oop, - Register src, - Register dst, - Register count, - RegSet saved_regs) { - if (!is_oop) { - // Barrier not needed - return; - } - - BLOCK_COMMENT("XBarrierSetAssembler::arraycopy_prologue {"); - - assert_different_registers(src, count, rscratch1); - - __ push(saved_regs, sp); - - if (count == c_rarg0) { - if (src == c_rarg1) { - // exactly backwards!! - __ mov(rscratch1, c_rarg0); - __ mov(c_rarg0, c_rarg1); - __ mov(c_rarg1, rscratch1); - } else { - __ mov(c_rarg1, count); - __ mov(c_rarg0, src); - } - } else { - __ mov(c_rarg0, src); - __ mov(c_rarg1, count); - } - - __ call_VM_leaf(XBarrierSetRuntime::load_barrier_on_oop_array_addr(), 2); - - __ pop(saved_regs, sp); - - BLOCK_COMMENT("} XBarrierSetAssembler::arraycopy_prologue"); -} - -void XBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, - Register jni_env, - Register robj, - Register tmp, - Label& slowpath) { - BLOCK_COMMENT("XBarrierSetAssembler::try_resolve_jobject_in_native {"); - - assert_different_registers(jni_env, robj, tmp); - - // Resolve jobject - BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, robj, tmp, slowpath); - - // The Address offset is too large to direct load - -784. Our range is +127, -128. - __ mov(tmp, (int64_t)(in_bytes(XThreadLocalData::address_bad_mask_offset()) - - in_bytes(JavaThread::jni_environment_offset()))); - - // Load address bad mask - __ add(tmp, jni_env, tmp); - __ ldr(tmp, Address(tmp)); - - // Check address bad mask - __ tst(robj, tmp); - __ br(Assembler::NE, slowpath); - - BLOCK_COMMENT("} XBarrierSetAssembler::try_resolve_jobject_in_native"); -} - -#ifdef COMPILER1 - -#undef __ -#define __ ce->masm()-> - -void XBarrierSetAssembler::generate_c1_load_barrier_test(LIR_Assembler* ce, - LIR_Opr ref) const { - assert_different_registers(rscratch1, rthread, ref->as_register()); - - __ ldr(rscratch1, address_bad_mask_from_thread(rthread)); - __ tst(ref->as_register(), rscratch1); -} - -void XBarrierSetAssembler::generate_c1_load_barrier_stub(LIR_Assembler* ce, - XLoadBarrierStubC1* stub) const { - // Stub entry - __ bind(*stub->entry()); - - Register ref = stub->ref()->as_register(); - Register ref_addr = noreg; - Register tmp = noreg; - - if (stub->tmp()->is_valid()) { - // Load address into tmp register - ce->leal(stub->ref_addr(), stub->tmp()); - ref_addr = tmp = stub->tmp()->as_pointer_register(); - } else { - // Address already in register - ref_addr = stub->ref_addr()->as_address_ptr()->base()->as_pointer_register(); - } - - assert_different_registers(ref, ref_addr, noreg); - - // Save r0 unless it is the result or tmp register - // Set up SP to accommodate parameters and maybe r0.. - if (ref != r0 && tmp != r0) { - __ sub(sp, sp, 32); - __ str(r0, Address(sp, 16)); - } else { - __ sub(sp, sp, 16); - } - - // Setup arguments and call runtime stub - ce->store_parameter(ref_addr, 1); - ce->store_parameter(ref, 0); - - __ far_call(stub->runtime_stub()); - - // Verify result - __ verify_oop(r0); - - // Move result into place - if (ref != r0) { - __ mov(ref, r0); - } - - // Restore r0 unless it is the result or tmp register - if (ref != r0 && tmp != r0) { - __ ldr(r0, Address(sp, 16)); - __ add(sp, sp, 32); - } else { - __ add(sp, sp, 16); - } - - // Stub exit - __ b(*stub->continuation()); -} - -#undef __ -#define __ sasm-> - -void XBarrierSetAssembler::generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, - DecoratorSet decorators) const { - __ prologue("zgc_load_barrier stub", false); - - __ push_call_clobbered_registers_except(RegSet::of(r0)); - - // Setup arguments - __ load_parameter(0, c_rarg0); - __ load_parameter(1, c_rarg1); - - __ call_VM_leaf(XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), 2); - - __ pop_call_clobbered_registers_except(RegSet::of(r0)); - - __ epilogue(); -} -#endif // COMPILER1 - -#ifdef COMPILER2 - -OptoReg::Name XBarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) { - if (!OptoReg::is_reg(opto_reg)) { - return OptoReg::Bad; - } - - const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); - if (vm_reg->is_FloatRegister()) { - return opto_reg & ~1; - } - - return opto_reg; -} - -#undef __ -#define __ _masm-> - -class XSaveLiveRegisters { -private: - MacroAssembler* const _masm; - RegSet _gp_regs; - FloatRegSet _fp_regs; - PRegSet _p_regs; - -public: - void initialize(XLoadBarrierStubC2* stub) { - // Record registers that needs to be saved/restored - RegMaskIterator rmi(stub->live()); - while (rmi.has_next()) { - const OptoReg::Name opto_reg = rmi.next(); - if (OptoReg::is_reg(opto_reg)) { - const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); - if (vm_reg->is_Register()) { - _gp_regs += RegSet::of(vm_reg->as_Register()); - } else if (vm_reg->is_FloatRegister()) { - _fp_regs += FloatRegSet::of(vm_reg->as_FloatRegister()); - } else if (vm_reg->is_PRegister()) { - _p_regs += PRegSet::of(vm_reg->as_PRegister()); - } else { - fatal("Unknown register type"); - } - } - } - - // Remove C-ABI SOE registers, scratch regs and _ref register that will be updated - _gp_regs -= RegSet::range(r19, r30) + RegSet::of(r8, r9, stub->ref()); - } - - XSaveLiveRegisters(MacroAssembler* masm, XLoadBarrierStubC2* stub) : - _masm(masm), - _gp_regs(), - _fp_regs(), - _p_regs() { - - // Figure out what registers to save/restore - initialize(stub); - - // Save registers - __ push(_gp_regs, sp); - __ push_fp(_fp_regs, sp); - __ push_p(_p_regs, sp); - } - - ~XSaveLiveRegisters() { - // Restore registers - __ pop_p(_p_regs, sp); - __ pop_fp(_fp_regs, sp); - - // External runtime call may clobber ptrue reg - __ reinitialize_ptrue(); - - __ pop(_gp_regs, sp); - } -}; - -#undef __ -#define __ _masm-> - -class XSetupArguments { -private: - MacroAssembler* const _masm; - const Register _ref; - const Address _ref_addr; - -public: - XSetupArguments(MacroAssembler* masm, XLoadBarrierStubC2* stub) : - _masm(masm), - _ref(stub->ref()), - _ref_addr(stub->ref_addr()) { - - // Setup arguments - if (_ref_addr.base() == noreg) { - // No self healing - if (_ref != c_rarg0) { - __ mov(c_rarg0, _ref); - } - __ mov(c_rarg1, 0); - } else { - // Self healing - if (_ref == c_rarg0) { - // _ref is already at correct place - __ lea(c_rarg1, _ref_addr); - } else if (_ref != c_rarg1) { - // _ref is in wrong place, but not in c_rarg1, so fix it first - __ lea(c_rarg1, _ref_addr); - __ mov(c_rarg0, _ref); - } else if (_ref_addr.base() != c_rarg0 && _ref_addr.index() != c_rarg0) { - assert(_ref == c_rarg1, "Mov ref first, vacating c_rarg0"); - __ mov(c_rarg0, _ref); - __ lea(c_rarg1, _ref_addr); - } else { - assert(_ref == c_rarg1, "Need to vacate c_rarg1 and _ref_addr is using c_rarg0"); - if (_ref_addr.base() == c_rarg0 || _ref_addr.index() == c_rarg0) { - __ mov(rscratch2, c_rarg1); - __ lea(c_rarg1, _ref_addr); - __ mov(c_rarg0, rscratch2); - } else { - ShouldNotReachHere(); - } - } - } - } - - ~XSetupArguments() { - // Transfer result - if (_ref != r0) { - __ mov(_ref, r0); - } - } -}; - -#undef __ -#define __ masm-> - -void XBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, XLoadBarrierStubC2* stub) const { - BLOCK_COMMENT("XLoadBarrierStubC2"); - - // Stub entry - __ bind(*stub->entry()); - - { - XSaveLiveRegisters save_live_registers(masm, stub); - XSetupArguments setup_arguments(masm, stub); - __ mov(rscratch1, stub->slow_path()); - __ blr(rscratch1); - } - // Stub exit - __ b(*stub->continuation()); -} - -#endif // COMPILER2 - -#undef __ -#define __ masm-> - -void XBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) { - // Check if mask is good. - // verifies that XAddressBadMask & r0 == 0 - __ ldr(tmp2, Address(rthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(tmp1, obj, tmp2); - __ cbnz(tmp1, error); - - BarrierSetAssembler::check_oop(masm, obj, tmp1, tmp2, error); -} - -#undef __ diff --git a/src/hotspot/cpu/aarch64/gc/x/xBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/x/xBarrierSetAssembler_aarch64.hpp deleted file mode 100644 index 8c1e9521757b4..0000000000000 --- a/src/hotspot/cpu/aarch64/gc/x/xBarrierSetAssembler_aarch64.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 CPU_AARCH64_GC_X_XBARRIERSETASSEMBLER_AARCH64_HPP -#define CPU_AARCH64_GC_X_XBARRIERSETASSEMBLER_AARCH64_HPP - -#include "code/vmreg.hpp" -#include "oops/accessDecorators.hpp" -#ifdef COMPILER2 -#include "opto/optoreg.hpp" -#endif // COMPILER2 - -#ifdef COMPILER1 -class LIR_Assembler; -class LIR_Opr; -class StubAssembler; -#endif // COMPILER1 - -#ifdef COMPILER2 -class Node; -#endif // COMPILER2 - -#ifdef COMPILER1 -class XLoadBarrierStubC1; -#endif // COMPILER1 - -#ifdef COMPILER2 -class XLoadBarrierStubC2; -#endif // COMPILER2 - -class XBarrierSetAssembler : public XBarrierSetAssemblerBase { -public: - virtual void load_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Register dst, - Address src, - Register tmp1, - Register tmp2); - -#ifdef ASSERT - virtual void store_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Address dst, - Register val, - Register tmp1, - Register tmp2, - Register tmp3); -#endif // ASSERT - - virtual void arraycopy_prologue(MacroAssembler* masm, - DecoratorSet decorators, - bool is_oop, - Register src, - Register dst, - Register count, - RegSet saved_regs); - - virtual void try_resolve_jobject_in_native(MacroAssembler* masm, - Register jni_env, - Register robj, - Register tmp, - Label& slowpath); - - virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; } - -#ifdef COMPILER1 - void generate_c1_load_barrier_test(LIR_Assembler* ce, - LIR_Opr ref) const; - - void generate_c1_load_barrier_stub(LIR_Assembler* ce, - XLoadBarrierStubC1* stub) const; - - void generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, - DecoratorSet decorators) const; -#endif // COMPILER1 - -#ifdef COMPILER2 - OptoReg::Name refine_register(const Node* node, - OptoReg::Name opto_reg); - - void generate_c2_load_barrier_stub(MacroAssembler* masm, - XLoadBarrierStubC2* stub) const; -#endif // COMPILER2 - - void check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error); -}; - -#endif // CPU_AARCH64_GC_X_XBARRIERSETASSEMBLER_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/gc/x/xGlobals_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/x/xGlobals_aarch64.cpp deleted file mode 100644 index a9c53da3d0186..0000000000000 --- a/src/hotspot/cpu/aarch64/gc/x/xGlobals_aarch64.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xGlobals.hpp" -#include "runtime/globals.hpp" -#include "runtime/os.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/powerOfTwo.hpp" - -#ifdef LINUX -#include -#endif // LINUX - -// -// The heap can have three different layouts, depending on the max heap size. -// -// Address Space & Pointer Layout 1 -// -------------------------------- -// -// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) -// . . -// . . -// . . -// +--------------------------------+ 0x0000014000000000 (20TB) -// | Remapped View | -// +--------------------------------+ 0x0000010000000000 (16TB) -// . . -// +--------------------------------+ 0x00000c0000000000 (12TB) -// | Marked1 View | -// +--------------------------------+ 0x0000080000000000 (8TB) -// | Marked0 View | -// +--------------------------------+ 0x0000040000000000 (4TB) -// . . -// +--------------------------------+ 0x0000000000000000 -// -// 6 4 4 4 4 -// 3 6 5 2 1 0 -// +--------------------+----+-----------------------------------------------+ -// |00000000 00000000 00|1111|11 11111111 11111111 11111111 11111111 11111111| -// +--------------------+----+-----------------------------------------------+ -// | | | -// | | * 41-0 Object Offset (42-bits, 4TB address space) -// | | -// | * 45-42 Metadata Bits (4-bits) 0001 = Marked0 (Address view 4-8TB) -// | 0010 = Marked1 (Address view 8-12TB) -// | 0100 = Remapped (Address view 16-20TB) -// | 1000 = Finalizable (Address view N/A) -// | -// * 63-46 Fixed (18-bits, always zero) -// -// -// Address Space & Pointer Layout 2 -// -------------------------------- -// -// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) -// . . -// . . -// . . -// +--------------------------------+ 0x0000280000000000 (40TB) -// | Remapped View | -// +--------------------------------+ 0x0000200000000000 (32TB) -// . . -// +--------------------------------+ 0x0000180000000000 (24TB) -// | Marked1 View | -// +--------------------------------+ 0x0000100000000000 (16TB) -// | Marked0 View | -// +--------------------------------+ 0x0000080000000000 (8TB) -// . . -// +--------------------------------+ 0x0000000000000000 -// -// 6 4 4 4 4 -// 3 7 6 3 2 0 -// +------------------+-----+------------------------------------------------+ -// |00000000 00000000 0|1111|111 11111111 11111111 11111111 11111111 11111111| -// +-------------------+----+------------------------------------------------+ -// | | | -// | | * 42-0 Object Offset (43-bits, 8TB address space) -// | | -// | * 46-43 Metadata Bits (4-bits) 0001 = Marked0 (Address view 8-16TB) -// | 0010 = Marked1 (Address view 16-24TB) -// | 0100 = Remapped (Address view 32-40TB) -// | 1000 = Finalizable (Address view N/A) -// | -// * 63-47 Fixed (17-bits, always zero) -// -// -// Address Space & Pointer Layout 3 -// -------------------------------- -// -// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) -// . . -// . . -// . . -// +--------------------------------+ 0x0000500000000000 (80TB) -// | Remapped View | -// +--------------------------------+ 0x0000400000000000 (64TB) -// . . -// +--------------------------------+ 0x0000300000000000 (48TB) -// | Marked1 View | -// +--------------------------------+ 0x0000200000000000 (32TB) -// | Marked0 View | -// +--------------------------------+ 0x0000100000000000 (16TB) -// . . -// +--------------------------------+ 0x0000000000000000 -// -// 6 4 4 4 4 -// 3 8 7 4 3 0 -// +------------------+----+-------------------------------------------------+ -// |00000000 00000000 |1111|1111 11111111 11111111 11111111 11111111 11111111| -// +------------------+----+-------------------------------------------------+ -// | | | -// | | * 43-0 Object Offset (44-bits, 16TB address space) -// | | -// | * 47-44 Metadata Bits (4-bits) 0001 = Marked0 (Address view 16-32TB) -// | 0010 = Marked1 (Address view 32-48TB) -// | 0100 = Remapped (Address view 64-80TB) -// | 1000 = Finalizable (Address view N/A) -// | -// * 63-48 Fixed (16-bits, always zero) -// - -// 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 -static const size_t DEFAULT_MAX_ADDRESS_BIT = 46; -// Minimum value returned, if probing fails -static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; - -static size_t probe_valid_max_address_bit() { -#ifdef LINUX - size_t max_address_bit = 0; - const size_t page_size = os::vm_page_size(); - for (size_t i = DEFAULT_MAX_ADDRESS_BIT; i > MINIMUM_MAX_ADDRESS_BIT; --i) { - const uintptr_t base_addr = ((uintptr_t) 1U) << i; - if (msync((void*)base_addr, page_size, MS_ASYNC) == 0) { - // msync succeeded, the address is valid, and maybe even already mapped. - max_address_bit = i; - break; - } - if (errno != ENOMEM) { - // Some error occurred. This should never happen, but msync - // has some undefined behavior, hence ignore this bit. -#ifdef ASSERT - fatal("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno)); -#else // ASSERT - log_warning_p(gc)("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno)); -#endif // ASSERT - continue; - } - // Since msync failed with ENOMEM, the page might not be mapped. - // Try to map it, to see if the address is valid. - void* const result_addr = mmap((void*) base_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); - if (result_addr != MAP_FAILED) { - munmap(result_addr, page_size); - } - if ((uintptr_t) result_addr == base_addr) { - // address is valid - max_address_bit = i; - break; - } - } - if (max_address_bit == 0) { - // probing failed, allocate a very high page and take that bit as the maximum - const uintptr_t high_addr = ((uintptr_t) 1U) << DEFAULT_MAX_ADDRESS_BIT; - void* const result_addr = mmap((void*) high_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); - if (result_addr != MAP_FAILED) { - max_address_bit = BitsPerSize_t - count_leading_zeros((size_t) result_addr) - 1; - munmap(result_addr, page_size); - } - } - log_info_p(gc, init)("Probing address space for the highest valid bit: " SIZE_FORMAT, max_address_bit); - return MAX2(max_address_bit, MINIMUM_MAX_ADDRESS_BIT); -#else // LINUX - return DEFAULT_MAX_ADDRESS_BIT; -#endif // LINUX -} - -size_t XPlatformAddressOffsetBits() { - const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; - const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; - const size_t min_address_offset_bits = max_address_offset_bits - 2; - const size_t address_offset = round_up_power_of_2(MaxHeapSize * XVirtualToPhysicalRatio); - const size_t address_offset_bits = log2i_exact(address_offset); - return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); -} - -size_t XPlatformAddressMetadataShift() { - return XPlatformAddressOffsetBits(); -} diff --git a/src/hotspot/cpu/aarch64/gc/x/xGlobals_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/x/xGlobals_aarch64.hpp deleted file mode 100644 index 870b0d74d5766..0000000000000 --- a/src/hotspot/cpu/aarch64/gc/x/xGlobals_aarch64.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 CPU_AARCH64_GC_X_XGLOBALS_AARCH64_HPP -#define CPU_AARCH64_GC_X_XGLOBALS_AARCH64_HPP - -const size_t XPlatformHeapViews = 3; -const size_t XPlatformCacheLineSize = 64; - -size_t XPlatformAddressOffsetBits(); -size_t XPlatformAddressMetadataShift(); - -#endif // CPU_AARCH64_GC_X_XGLOBALS_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad b/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad deleted file mode 100644 index 5e690a8e47b94..0000000000000 --- a/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad +++ /dev/null @@ -1,249 +0,0 @@ -// -// 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 -// 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. -// - -source_hpp %{ - -#include "gc/shared/gc_globals.hpp" -#include "gc/x/c2/xBarrierSetC2.hpp" -#include "gc/x/xThreadLocalData.hpp" - -%} - -source %{ - -static void x_load_barrier(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref, Register tmp, uint8_t barrier_data) { - if (barrier_data == XLoadBarrierElided) { - return; - } - XLoadBarrierStubC2* const stub = XLoadBarrierStubC2::create(node, ref_addr, ref, tmp, barrier_data); - __ ldr(tmp, Address(rthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(tmp, tmp, ref); - __ cbnz(tmp, *stub->entry()); - __ bind(*stub->continuation()); -} - -static void x_load_barrier_slow_path(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref, Register tmp) { - XLoadBarrierStubC2* const stub = XLoadBarrierStubC2::create(node, ref_addr, ref, tmp, XLoadBarrierStrong); - __ b(*stub->entry()); - __ bind(*stub->continuation()); -} - -%} - -// Load Pointer -instruct xLoadP(iRegPNoSp dst, memory mem, rFlagsReg cr) -%{ - match(Set dst (LoadP mem)); - predicate(UseZGC && !ZGenerational && !needs_acquiring_load(n) && (n->as_Load()->barrier_data() != 0)); - effect(TEMP dst, KILL cr); - - ins_cost(4 * INSN_COST); - - format %{ "ldr $dst, $mem" %} - - ins_encode %{ - Address ref_addr = mem2address($mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp); - if (ref_addr.getMode() == Address::base_plus_offset) { - // Fix up any out-of-range offsets. - assert_different_registers(rscratch1, as_Register($mem$$base)); - assert_different_registers(rscratch1, $dst$$Register); - ref_addr = __ legitimize_address(ref_addr, 8, rscratch1); - } - __ ldr($dst$$Register, ref_addr); - x_load_barrier(masm, this, ref_addr, $dst$$Register, rscratch2 /* tmp */, barrier_data()); - %} - - ins_pipe(iload_reg_mem); -%} - -// Load Pointer Volatile -instruct xLoadPVolatile(iRegPNoSp dst, indirect mem /* sync_memory */, rFlagsReg cr) -%{ - match(Set dst (LoadP mem)); - predicate(UseZGC && !ZGenerational && needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); - effect(TEMP dst, KILL cr); - - ins_cost(VOLATILE_REF_COST); - - format %{ "ldar $dst, $mem\t" %} - - ins_encode %{ - __ ldar($dst$$Register, $mem$$Register); - x_load_barrier(masm, this, Address($mem$$Register), $dst$$Register, rscratch2 /* tmp */, barrier_data()); - %} - - ins_pipe(pipe_serial); -%} - -instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - predicate(UseZGC && !ZGenerational && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(KILL cr, TEMP_DEF res); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ "cmpxchg $mem, $oldval, $newval\n\t" - "cset $res, EQ" %} - - ins_encode %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, - false /* acquire */, true /* release */, false /* weak */, rscratch2); - __ cset($res$$Register, Assembler::EQ); - if (barrier_data() != XLoadBarrierElided) { - Label good; - __ ldr(rscratch1, Address(rthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(rscratch1, rscratch1, rscratch2); - __ cbz(rscratch1, good); - x_load_barrier_slow_path(masm, this, Address($mem$$Register), rscratch2 /* ref */, rscratch1 /* tmp */); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, - false /* acquire */, true /* release */, false /* weak */, rscratch2); - __ cset($res$$Register, Assembler::EQ); - __ bind(good); - } - %} - - ins_pipe(pipe_slow); -%} - -instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - predicate(UseZGC && !ZGenerational && needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == XLoadBarrierStrong)); - effect(KILL cr, TEMP_DEF res); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ "cmpxchg $mem, $oldval, $newval\n\t" - "cset $res, EQ" %} - - ins_encode %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, - true /* acquire */, true /* release */, false /* weak */, rscratch2); - __ cset($res$$Register, Assembler::EQ); - if (barrier_data() != XLoadBarrierElided) { - Label good; - __ ldr(rscratch1, Address(rthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(rscratch1, rscratch1, rscratch2); - __ cbz(rscratch1, good); - x_load_barrier_slow_path(masm, this, Address($mem$$Register), rscratch2 /* ref */, rscratch1 /* tmp */ ); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, - true /* acquire */, true /* release */, false /* weak */, rscratch2); - __ cset($res$$Register, Assembler::EQ); - __ bind(good); - } - %} - - ins_pipe(pipe_slow); -%} - -instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - predicate(UseZGC && !ZGenerational && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(TEMP_DEF res, KILL cr); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ "cmpxchg $res = $mem, $oldval, $newval" %} - - ins_encode %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, - false /* acquire */, true /* release */, false /* weak */, $res$$Register); - if (barrier_data() != XLoadBarrierElided) { - Label good; - __ ldr(rscratch1, Address(rthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(rscratch1, rscratch1, $res$$Register); - __ cbz(rscratch1, good); - x_load_barrier_slow_path(masm, this, Address($mem$$Register), $res$$Register /* ref */, rscratch1 /* tmp */); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, - false /* acquire */, true /* release */, false /* weak */, $res$$Register); - __ bind(good); - } - %} - - ins_pipe(pipe_slow); -%} - -instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - predicate(UseZGC && !ZGenerational && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(TEMP_DEF res, KILL cr); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ "cmpxchg $res = $mem, $oldval, $newval" %} - - ins_encode %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, - true /* acquire */, true /* release */, false /* weak */, $res$$Register); - if (barrier_data() != XLoadBarrierElided) { - Label good; - __ ldr(rscratch1, Address(rthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(rscratch1, rscratch1, $res$$Register); - __ cbz(rscratch1, good); - x_load_barrier_slow_path(masm, this, Address($mem$$Register), $res$$Register /* ref */, rscratch1 /* tmp */); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, - true /* acquire */, true /* release */, false /* weak */, $res$$Register); - __ bind(good); - } - %} - - ins_pipe(pipe_slow); -%} - -instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{ - match(Set prev (GetAndSetP mem newv)); - predicate(UseZGC && !ZGenerational && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP_DEF prev, KILL cr); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ "atomic_xchg $prev, $newv, [$mem]" %} - - ins_encode %{ - __ atomic_xchg($prev$$Register, $newv$$Register, $mem$$Register); - x_load_barrier(masm, this, Address(noreg, 0), $prev$$Register, rscratch2 /* tmp */, barrier_data()); - %} - - ins_pipe(pipe_serial); -%} - -instruct xGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{ - match(Set prev (GetAndSetP mem newv)); - predicate(UseZGC && !ZGenerational && needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() != 0)); - effect(TEMP_DEF prev, KILL cr); - - ins_cost(VOLATILE_REF_COST); - - format %{ "atomic_xchg_acq $prev, $newv, [$mem]" %} - - ins_encode %{ - __ atomic_xchgal($prev$$Register, $newv$$Register, $mem$$Register); - x_load_barrier(masm, this, Address(noreg, 0), $prev$$Register, rscratch2 /* tmp */, barrier_data()); - %} - ins_pipe(pipe_serial); -%} diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp index 466e77a4460d0..3f1898b6742e1 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp @@ -1189,6 +1189,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, __ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr())); } else if (stub->is_atomic()) { __ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr())); + } else if (stub->is_nokeepalive()) { + __ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr())); } else { __ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr())); } @@ -1307,11 +1309,11 @@ Label* ZLoadBarrierStubC2Aarch64::entry() { return ZBarrierStubC2::entry(); } -ZStoreBarrierStubC2Aarch64::ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic) - : ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic), _deferred_emit(false) {} +ZStoreBarrierStubC2Aarch64::ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive) + : ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic, is_nokeepalive), _deferred_emit(false) {} -ZStoreBarrierStubC2Aarch64* ZStoreBarrierStubC2Aarch64::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic) { - ZStoreBarrierStubC2Aarch64* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2Aarch64(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic); +ZStoreBarrierStubC2Aarch64* ZStoreBarrierStubC2Aarch64::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive) { + ZStoreBarrierStubC2Aarch64* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2Aarch64(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic, is_nokeepalive); register_stub(stub); return stub; } diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp index 2f716140ed19d..ad3a171c10370 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp @@ -280,10 +280,10 @@ class ZStoreBarrierStubC2Aarch64 : public ZStoreBarrierStubC2 { private: bool _deferred_emit; - ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic); + ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive); public: - static ZStoreBarrierStubC2Aarch64* create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic); + static ZStoreBarrierStubC2Aarch64* create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive); virtual void emit_code(MacroAssembler& masm); }; diff --git a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad index 1510b42bfe97d..47abaae3d5b77 100644 --- a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad @@ -91,7 +91,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address z_color(masm, node, rnew_zpointer, rnew_zaddress); } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; - ZStoreBarrierStubC2Aarch64* const stub = ZStoreBarrierStubC2Aarch64::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic); + bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0; + ZStoreBarrierStubC2Aarch64* const stub = ZStoreBarrierStubC2Aarch64::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive); ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler(); bs_asm->store_barrier_fast(masm, ref_addr, rnew_zaddress, rnew_zpointer, tmp, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation()); } @@ -100,10 +101,10 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address %} // Load Pointer -instruct zLoadP(iRegPNoSp dst, memory mem, rFlagsReg cr) +instruct zLoadP(iRegPNoSp dst, memory8 mem, rFlagsReg cr) %{ match(Set dst (LoadP mem)); - predicate(UseZGC && ZGenerational && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); + predicate(UseZGC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); effect(TEMP dst, KILL cr); ins_cost(4 * INSN_COST); @@ -129,7 +130,7 @@ instruct zLoadP(iRegPNoSp dst, memory mem, rFlagsReg cr) instruct zLoadPVolatile(iRegPNoSp dst, indirect mem /* sync_memory */, rFlagsReg cr) %{ match(Set dst (LoadP mem)); - predicate(UseZGC && ZGenerational && needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); + predicate(UseZGC && needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); effect(TEMP dst, KILL cr); ins_cost(VOLATILE_REF_COST); @@ -148,7 +149,7 @@ instruct zLoadPVolatile(iRegPNoSp dst, indirect mem /* sync_memory */, rFlagsReg // Store Pointer instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp, rFlagsReg cr) %{ - predicate(UseZGC && ZGenerational && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + predicate(UseZGC && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); match(Set mem (StoreP mem src)); effect(TEMP tmp, KILL cr); @@ -165,7 +166,7 @@ instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp, rFlagsReg cr) // Store Pointer Volatile instruct zStorePVolatile(indirect mem, iRegP src, iRegPNoSp tmp, rFlagsReg cr) %{ - predicate(UseZGC && ZGenerational && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + predicate(UseZGC && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); match(Set mem (StoreP mem src)); effect(TEMP tmp, KILL cr); @@ -182,7 +183,7 @@ instruct zStorePVolatile(indirect mem, iRegP src, iRegPNoSp tmp, rFlagsReg cr) instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - predicate(UseZGC && ZGenerational && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + predicate(UseZGC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -206,7 +207,7 @@ instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - predicate(UseZGC && ZGenerational && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + predicate(UseZGC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -230,7 +231,7 @@ instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, rFlagsReg cr) %{ match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - predicate(UseZGC && ZGenerational && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + predicate(UseZGC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -253,7 +254,7 @@ instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, rFlagsReg cr) %{ match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - predicate(UseZGC && ZGenerational && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + predicate(UseZGC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -276,7 +277,7 @@ instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{ match(Set prev (GetAndSetP mem newv)); - predicate(UseZGC && ZGenerational && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + predicate(UseZGC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); effect(TEMP prev, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -294,7 +295,7 @@ instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{ instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{ match(Set prev (GetAndSetP mem newv)); - predicate(UseZGC && ZGenerational && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + predicate(UseZGC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); effect(TEMP prev, KILL cr); ins_cost(2 * VOLATILE_REF_COST); diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index 9c20e3737c868..800e771892109 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -38,7 +38,7 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap nulls define_pd_global(bool, DelayCompilerStubsGeneration, COMPILER2_OR_JVMCI); -define_pd_global(uintx, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment. +define_pd_global(uintx, CodeCacheSegmentSize, 64); define_pd_global(intx, CodeEntryAlignment, 64); define_pd_global(intx, OptoLoopAlignment, 16); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index c5c02619d446e..252f423211580 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -1838,7 +1838,8 @@ void MacroAssembler::clinit_barrier(Register klass, Register scratch, Label* L_f L_slow_path = &L_fallthrough; } // Fast path check: class is fully initialized - ldrb(scratch, Address(klass, InstanceKlass::init_state_offset())); + lea(scratch, Address(klass, InstanceKlass::init_state_offset())); + ldarb(scratch, scratch); subs(zr, scratch, InstanceKlass::fully_initialized); br(Assembler::EQ, *L_fast_path); @@ -4781,23 +4782,6 @@ void MacroAssembler::kernel_crc32_common_fold_using_crypto_pmull(Register crc, R mov(tmp1, v0, D, 1); } -SkipIfEqual::SkipIfEqual( - MacroAssembler* masm, const bool* flag_addr, bool value) { - _masm = masm; - uint64_t offset; - _masm->adrp(rscratch1, ExternalAddress((address)flag_addr), offset); - _masm->ldrb(rscratch1, Address(rscratch1, offset)); - if (value) { - _masm->cbnzw(rscratch1, _label); - } else { - _masm->cbzw(rscratch1, _label); - } -} - -SkipIfEqual::~SkipIfEqual() { - _masm->bind(_label); -} - void MacroAssembler::addptr(const Address &dst, int32_t src) { Address adr; switch(dst.getMode()) { @@ -5010,8 +4994,10 @@ void MacroAssembler::decode_heap_oop(Register d, Register s) { verify_heapbase("MacroAssembler::decode_heap_oop: heap base corrupted?"); #endif if (CompressedOops::base() == nullptr) { - if (CompressedOops::shift() != 0 || d != s) { + if (CompressedOops::shift() != 0) { lsl(d, s, CompressedOops::shift()); + } else if (d != s) { + mov(d, s); } } else { Label done; diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index e49f0c49ef66f..48fb3c2b07138 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1652,24 +1652,6 @@ class MacroAssembler: public Assembler { inline bool AbstractAssembler::pd_check_instruction_mark() { return false; } #endif -/** - * class SkipIfEqual: - * - * Instantiating this class will result in assembly code being output that will - * jump around any code emitted between the creation of the instance and it's - * automatic destruction at the end of a scope block, depending on the value of - * the flag passed to the constructor, which will be checked at run-time. - */ -class SkipIfEqual { - private: - MacroAssembler* _masm; - Label _label; - - public: - SkipIfEqual(MacroAssembler*, const bool* flag_addr, bool value); - ~SkipIfEqual(); -}; - struct tableswitch { Register _reg; int _insn_index; jint _first_key; jint _last_key; diff --git a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp index 68800d04d69ba..aa6a9d14ff176 100644 --- a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/methodHandles_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, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,6 +27,7 @@ #include "asm/macroAssembler.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/vmClasses.hpp" +#include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "memory/allocation.inline.hpp" @@ -36,7 +37,7 @@ #include "runtime/frame.inline.hpp" #include "runtime/stubRoutines.hpp" -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 770ed2f6c3868..1f6d729238974 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -78,7 +78,7 @@ address NativeCall::destination() const { // // Used in the runtime linkage of calls; see class CompiledIC. void NativeCall::set_destination_mt_safe(address dest) { - assert((Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || + assert((CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index eb235f8472c1d..de7fc5b281bc2 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -1374,7 +1374,9 @@ class StubGenerator: public StubCodeGenerator { // r15 is the byte adjustment needed to align s. __ cbz(r15, aligned); int shift = exact_log2(granularity); - if (shift) __ lsr(r15, r15, shift); + if (shift > 0) { + __ lsr(r15, r15, shift); + } __ sub(count, count, r15); #if 0 @@ -1402,9 +1404,15 @@ class StubGenerator: public StubCodeGenerator { // s is now 2-word-aligned. - // We have a count of units and some trailing bytes. Adjust the - // count and do a bulk copy of words. - __ lsr(r15, count, exact_log2(wordSize/granularity)); + // We have a count of units and some trailing bytes. Adjust the + // count and do a bulk copy of words. If the shift is zero + // perform a move instead to benefit from zero latency moves. + int shift = exact_log2(wordSize/granularity); + if (shift > 0) { + __ lsr(r15, count, shift); + } else { + __ mov(r15, count); + } if (direction == copy_forwards) { if (type != T_OBJECT) { __ bl(copy_f); @@ -7320,6 +7328,28 @@ class StubGenerator: public StubCodeGenerator { return start; } + // load Method* target of MethodHandle + // j_rarg0 = jobject receiver + // rmethod = result + address generate_upcall_stub_load_target() { + StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target"); + address start = __ pc(); + + __ resolve_global_jobject(j_rarg0, rscratch1, rscratch2); + // Load target method from receiver + __ load_heap_oop(rmethod, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), rscratch1, rscratch2); + __ load_heap_oop(rmethod, Address(rmethod, java_lang_invoke_LambdaForm::vmentry_offset()), rscratch1, rscratch2); + __ load_heap_oop(rmethod, Address(rmethod, java_lang_invoke_MemberName::method_offset()), rscratch1, rscratch2); + __ access_load_at(T_ADDRESS, IN_HEAP, rmethod, + Address(rmethod, java_lang_invoke_ResolvedMethodName::vmtarget_offset()), + noreg, noreg); + __ str(rmethod, Address(rthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized + + __ ret(lr); + + return start; + } + #undef __ #define __ masm-> @@ -8241,6 +8271,7 @@ class StubGenerator: public StubCodeGenerator { #endif StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); StubRoutines::aarch64::set_completed(); // Inidicate that arraycopy and zero_blocks stubs are generated } diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index 3210789bbbdfa..9894841e933d8 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "classfile/javaClasses.hpp" +#include "compiler/disassembler.hpp" #include "compiler/compiler_globals.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" @@ -67,7 +68,7 @@ // Max size with JVMTI int TemplateInterpreter::InterpreterCodeSize = 200 * 1024; -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> address TemplateInterpreterGenerator::generate_slow_signature_handler() { address entry = __ pc(); @@ -1998,13 +1999,21 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address& vep) { assert(t->is_valid() && t->tos_in() == vtos, "illegal template"); Label L; - aep = __ pc(); __ push_ptr(); __ b(L); - fep = __ pc(); __ push_f(); __ b(L); - dep = __ pc(); __ push_d(); __ b(L); - lep = __ pc(); __ push_l(); __ b(L); - bep = cep = sep = - iep = __ pc(); __ push_i(); - vep = __ pc(); + aep = __ pc(); // atos entry point + __ push_ptr(); + __ b(L); + fep = __ pc(); // ftos entry point + __ push_f(); + __ b(L); + dep = __ pc(); // dtos entry point + __ push_d(); + __ b(L); + lep = __ pc(); // ltos entry point + __ push_l(); + __ b(L); + bep = cep = sep = iep = __ pc(); // [bcsi]tos entry point + __ push_i(); + vep = __ pc(); // vtos entry point __ bind(L); generate_and_dispatch(t); } diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index 25eb339bfce71..48ff356f9a558 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "compiler/disassembler.hpp" #include "compiler/compilerDefinitions.inline.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/collectedHeap.hpp" @@ -49,7 +50,7 @@ #include "runtime/synchronizer.hpp" #include "utilities/powerOfTwo.hpp" -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> // Address computation: local variables diff --git a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp index 28ec07815be5c..517fccb2d1aa5 100644 --- a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "classfile/javaClasses.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "prims/upcallLinker.hpp" @@ -117,7 +118,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, @@ -222,7 +223,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ lea(c_rarg0, Address(sp, frame_data_offset)); - __ movptr(c_rarg1, (intptr_t)receiver); __ movptr(rscratch1, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry)); __ blr(rscratch1); __ mov(rthread, r0); @@ -238,12 +238,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0); __ block_comment("} argument shuffle"); - __ block_comment("{ receiver "); - __ get_vm_result(j_rarg0, rthread); - __ block_comment("} receiver "); - - __ mov_metadata(rmethod, entry); - __ str(rmethod, Address(rthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized + __ block_comment("{ load target "); + __ movptr(j_rarg0, (intptr_t)receiver); + __ far_call(RuntimeAddress(StubRoutines::upcall_stub_load_target()), rscratch1); // puts target Method* in rmethod + __ block_comment("} load target "); __ push_cont_fastpath(rthread); @@ -318,7 +316,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, #ifndef PRODUCT stringStream ss; - ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + ss.print("upcall_stub_%s", signature->as_C_string()); const char* name = _masm->code_string(ss.as_string()); #else // PRODUCT const char* name = "upcall_stub"; diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index d71162ac568ea..f18cec16488ae 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -259,6 +259,9 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(UseCryptoPmullForCRC32)) { FLAG_SET_DEFAULT(UseCryptoPmullForCRC32, true); } + if (FLAG_IS_DEFAULT(CodeEntryAlignment)) { + FLAG_SET_DEFAULT(CodeEntryAlignment, 32); + } } if (UseCryptoPmullForCRC32 && (!VM_Version::supports_pmull() || !VM_Version::supports_sha3() || !VM_Version::supports_crc32())) { diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 2c7de0a58a204..bfca986f350cb 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -1003,10 +1003,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return nullptr; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return nullptr; -} - // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { return false; @@ -3890,6 +3886,7 @@ instruct loadRange(iRegI dst, memoryI mem) %{ instruct loadP(iRegP dst, memoryP mem) %{ + predicate(!(UseG1GC && n->as_Load()->barrier_data() != 0)); match(Set dst (LoadP mem)); ins_cost(MEMORY_REF_COST); size(4); @@ -4225,18 +4222,6 @@ instruct storeB(memoryB mem, store_RegI src) %{ ins_pipe(istore_mem_reg); %} -instruct storeCM(memoryB mem, store_RegI src) %{ - match(Set mem (StoreCM mem src)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "STRB $src,$mem\t! CMS card-mark byte" %} - ins_encode %{ - __ strb($src$$Register, $mem$$Address); - %} - ins_pipe(istore_mem_reg); -%} - // Store Char/Short @@ -4356,6 +4341,7 @@ instruct movSP(store_ptr_RegP dst, SPRegP src) %{ instruct storeP(memoryP mem, store_ptr_RegP src) %{ + predicate(!(UseG1GC && n->as_Store()->barrier_data() != 0)); match(Set mem (StoreP mem src)); ins_cost(MEMORY_REF_COST); size(4); @@ -5390,6 +5376,7 @@ instruct compareAndSwapI_bool(memoryex mem, iRegI oldval, iRegI newval, iRegI re %} instruct compareAndSwapP_bool(memoryex mem, iRegP oldval, iRegP newval, iRegI res, iRegI tmp, flagsReg ccr ) %{ + predicate(!(UseG1GC && n->as_LoadStore()->barrier_data() != 0)); match(Set res (CompareAndSwapP mem (Binary oldval newval))); effect( KILL ccr, TEMP tmp); size(28); @@ -5659,6 +5646,7 @@ instruct xchgL(memoryex mem, iRegLd newval, iRegLd res, iRegI tmp, flagsReg ccr) %} instruct xchgP(memoryex mem, iRegP newval, iRegP res, iRegI tmp, flagsReg ccr) %{ + predicate(!(UseG1GC && n->as_LoadStore()->barrier_data() != 0)); match(Set res (GetAndSetP mem newval)); effect(KILL ccr, TEMP tmp, TEMP res); size(16); diff --git a/src/hotspot/cpu/arm/assembler_arm_32.hpp b/src/hotspot/cpu/arm/assembler_arm_32.hpp index dd04ad1ab3a3c..e53eefac097ef 100644 --- a/src/hotspot/cpu/arm/assembler_arm_32.hpp +++ b/src/hotspot/cpu/arm/assembler_arm_32.hpp @@ -119,8 +119,9 @@ class RegisterSet { } friend RegisterSet operator | (const RegisterSet set1, const RegisterSet set2) { - assert((set1._encoding & set2._encoding) == 0, - "encoding constraint"); +// why so strong constraint? +// assert((set1._encoding & set2._encoding) == 0, +// "encoding constraint"); return RegisterSet(set1._encoding | set2._encoding); } @@ -142,6 +143,11 @@ class RegisterSet { } return count; } + + static RegisterSet from(RegSet set) { + assert(set.size(), "RegSet must not be empty"); + return RegisterSet(set.bits()); + } }; #if R9_IS_SCRATCHED @@ -157,6 +163,10 @@ class FloatRegisterSet { public: + FloatRegisterSet() { + _encoding = 0; + } + FloatRegisterSet(FloatRegister reg) { if (reg->hi_bit() == 0) { _encoding = reg->hi_bits() << 12 | reg->lo_bit() << 22 | 1; @@ -185,6 +195,15 @@ class FloatRegisterSet { return (_encoding & 0xFFFFFF00) | ((_encoding & 0xFF) << 1); } + static FloatRegisterSet from(FloatRegSet set) { + assert(set.size(), "FloatRegSet must not be empty"); + // the vector load/store instructions operate on a set of consecutive registers. + // for the sake of simplicity, write all registers between the first and last in the set + size_t range = (*set.rbegin())->encoding() - (*set.begin())->encoding() + 1; + // push_float stores float regisgters by pairs + return FloatRegisterSet(*set.begin(), (range+1)/2); + } + }; diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index bb6a93e6f8da7..b14e6f0b4ca0c 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -948,6 +948,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { if (op->init_check()) { Register tmp = op->tmp1()->as_register(); __ ldrb(tmp, Address(op->klass()->as_register(), InstanceKlass::init_state_offset())); + __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp); add_debug_info_for_null_check_here(op->stub()->info()); __ cmp(tmp, InstanceKlass::fully_initialized); __ b(*op->stub()->entry(), ne); diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp index 3c5e29aa8710f..56ae7707fbf38 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp @@ -39,8 +39,10 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif - +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> #ifdef PRODUCT @@ -106,70 +108,87 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas #endif // !R9_IS_SCRATCHED } -// G1 pre-barrier. -// Blows all volatile registers R0-R3, Rtemp, LR). -// If store_addr != noreg, then previous value is loaded from [store_addr]; -// in such case store_addr and new_val registers are preserved; -// otherwise pre_val register is preserved. -void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, - Register store_addr, - Register new_val, - Register pre_val, - Register tmp1, - Register tmp2) { - Label done; - Label runtime; - - if (store_addr != noreg) { - assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg); - } else { - assert (new_val == noreg, "should be"); - assert_different_registers(pre_val, tmp1, tmp2, noreg); - } - - Address in_progress(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); +static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register thread, const Register value, const Register temp1, const Register temp2) { + assert_different_registers(value, temp1, temp2); + // Can we store original value in the thread's buffer? + // (The index field is typed as size_t.) + __ ldr(temp1, Address(thread, in_bytes(index_offset))); // temp1 := *(index address) + __ cbz(temp1, runtime); // jump to runtime if index == 0 (full buffer) + // The buffer is not full, store value into it. + __ sub(temp1, temp1, wordSize); // temp1 := next index + __ str(temp1, Address(thread, in_bytes(index_offset))); // *(index address) := next index + __ ldr(temp2, Address(thread, in_bytes(buffer_offset))); // temp2 := buffer address + // Record the previous value + __ str(value, Address(temp2, temp1)); // *(buffer address + next index) := value + } +static void generate_pre_barrier_fast_path(MacroAssembler* masm, + const Register thread, + const Register tmp1) { + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); // Is marking active? assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code"); __ ldrb(tmp1, in_progress); - __ cbz(tmp1, done); +} +static void generate_pre_barrier_slow_path(MacroAssembler* masm, + const Register obj, + const Register pre_val, + const Register thread, + const Register tmp1, + const Register tmp2, + Label& done, + Label& runtime) { // Do we need to load the previous value? - if (store_addr != noreg) { - __ load_heap_oop(pre_val, Address(store_addr, 0)); + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj, 0)); } // Is the previous value null? __ cbz(pre_val, done); - // Can we store original value in the thread's buffer? - // Is index == 0? - // (The index field is typed as size_t.) + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, + thread, pre_val, tmp1, tmp2); + __ b(done); +} - __ ldr(tmp1, index); // tmp1 := *index_adr - __ ldr(tmp2, buffer); +// G1 pre-barrier. +// Blows all volatile registers R0-R3, LR). +// If obj != noreg, then previous value is loaded from [obj]; +// in such case obj and pre_val registers is preserved; +// otherwise pre_val register is preserved. +void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2) { + Label done; + Label runtime; - __ subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize - __ b(runtime, lt); // If negative, goto runtime + assert_different_registers(obj, pre_val, tmp1, tmp2, noreg); - __ str(tmp1, index); // *index_adr := tmp1 + generate_pre_barrier_fast_path(masm, Rthread, tmp1); + // If marking is not active (*(mark queue active address) == 0), jump to done + __ cbz(tmp1, done); - // Record the previous value - __ str(pre_val, Address(tmp2, tmp1)); - __ b(done); + generate_pre_barrier_slow_path(masm, obj, pre_val, Rthread, tmp1, tmp2, done, runtime); __ bind(runtime); // save the live input values - if (store_addr != noreg) { - // avoid raw_push to support any ordering of store_addr and new_val - __ push(RegisterSet(store_addr) | RegisterSet(new_val)); - } else { - __ push(pre_val); + RegisterSet set = RegisterSet(pre_val) | RegisterSet(R0, R3) | RegisterSet(R12); + // save the live input values + if (obj != noreg) { + // avoid raw_push to support any ordering of store_addr and pre_val + set = set | RegisterSet(obj); } + __ push(set); + if (pre_val != R0) { __ mov(R0, pre_val); } @@ -177,33 +196,17 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), R0, R1); - if (store_addr != noreg) { - __ pop(RegisterSet(store_addr) | RegisterSet(new_val)); - } else { - __ pop(pre_val); - } - + __ pop(set); __ bind(done); } -// G1 post-barrier. -// Blows all volatile registers R0-R3, Rtemp, LR). -void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, - Register store_addr, - Register new_val, - Register tmp1, - Register tmp2, - Register tmp3) { - - Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - BarrierSet* bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); - CardTable* ct = ctbs->card_table(); - Label done; - Label runtime; - +static void generate_post_barrier_fast_path(MacroAssembler* masm, + const Register store_addr, + const Register new_val, + const Register tmp1, + const Register tmp2, + Label& done, + bool new_val_may_be_null) { // Does store cross heap regions? __ eor(tmp1, store_addr, new_val); @@ -211,22 +214,31 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, __ b(done, eq); // crosses regions, storing null? - - __ cbz(new_val, done); - + if (new_val_may_be_null) { + __ cbz(new_val, done); + } // storing region crossing non-null, is card already dirty? const Register card_addr = tmp1; - __ mov_address(tmp2, (address)ct->byte_map_base()); + CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); + __ mov_address(tmp2, (address)ct->card_table()->byte_map_base()); __ add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift())); __ ldrb(tmp2, Address(card_addr)); __ cmp(tmp2, (int)G1CardTable::g1_young_card_val()); - __ b(done, eq); +} +static void generate_post_barrier_slow_path(MacroAssembler* masm, + const Register thread, + const Register tmp1, + const Register tmp2, + const Register tmp3, + Label& done, + Label& runtime) { __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2); - assert(CardTable::dirty_card_val() == 0, "adjust this code"); + // card_addr is loaded by generate_post_barrier_fast_path + const Register card_addr = tmp1; __ ldrb(tmp2, Address(card_addr)); __ cbz(tmp2, done); @@ -234,29 +246,139 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, // dirty card and log. __ strb(__ zero_register(tmp2), Address(card_addr)); + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, + thread, card_addr, tmp2, tmp3); + __ b(done); +} - __ ldr(tmp2, queue_index); - __ ldr(tmp3, buffer); - __ subs(tmp2, tmp2, wordSize); - __ b(runtime, lt); // go to runtime if now negative - - __ str(tmp2, queue_index); +// G1 post-barrier. +// Blows all volatile registers R0-R3, LR). +void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + Register tmp3) { + Label done; + Label runtime; - __ str(card_addr, Address(tmp3, tmp2)); - __ b(done); + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */); + // If card is young, jump to done + // card_addr and card are loaded by generate_post_barrier_fast_path + const Register card = tmp2; + const Register card_addr = tmp1; + __ b(done, eq); + generate_post_barrier_slow_path(masm, Rthread, card_addr, tmp2, tmp3, done, runtime); __ bind(runtime); + RegisterSet set = RegisterSet(store_addr) | RegisterSet(R0, R3) | RegisterSet(R12); + __ push(set); + if (card_addr != R0) { __ mov(R0, card_addr); } __ mov(R1, Rthread); __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), R0, R1); + __ pop(set); + __ bind(done); } +#if defined(COMPILER2) + +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path, Register tmp1) { + SaveLiveRegisters save_registers(masm, stub); + if (c_rarg0 != arg) { + __ mov(c_rarg0, arg); + } + __ mov(c_rarg1, Rthread); + __ call_VM_leaf(runtime_path, R0, R1); +} + +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* stub) { + assert(thread == Rthread, "must be"); + assert_different_registers(obj, pre_val, tmp1, tmp2); + assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); + + stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2); + + generate_pre_barrier_fast_path(masm, thread, tmp1); + // If marking is active (*(mark queue active address) != 0), jump to stub (slow path) + __ cbnz(tmp1, *stub->entry()); + + __ bind(*stub->continuation()); +} + +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); + Register tmp2 = stub->tmp2(); + + __ bind(*stub->entry()); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, *stub->continuation(), runtime); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), tmp1); + __ b(*stub->continuation()); +} + +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + Register tmp3, + G1PostBarrierStubC2* stub) { + assert(thread == Rthread, "must be"); + assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg); + + stub->initialize_registers(thread, tmp1, tmp2, tmp3); + + bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null); + // If card is not young, jump to stub (slow path) + __ b(*stub->entry(), ne); + + __ bind(*stub->continuation()); +} + +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); // tmp1 holds the card address. + Register tmp2 = stub->tmp2(); + Register tmp3 = stub->tmp3(); + + __ bind(*stub->entry()); + generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, tmp3, *stub->continuation(), runtime); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp2); + __ b(*stub->continuation()); +} + +#endif // COMPILER2 + void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp2, Register tmp3) { bool on_oop = type == T_OBJECT || type == T_ARRAY; @@ -268,7 +390,7 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator if (on_oop && on_reference) { // Generate the G1 pre-barrier code to log the value of // the referent field in an SATB buffer. - g1_write_barrier_pre(masm, noreg, noreg, dst, tmp1, tmp2); + g1_write_barrier_pre(masm, noreg, dst, tmp1, tmp2); } } @@ -295,7 +417,7 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco } if (needs_pre_barrier) { - g1_write_barrier_pre(masm, store_addr, new_val, tmp1, tmp2, tmp3); + g1_write_barrier_pre(masm, store_addr, tmp3 /*pre_val*/, tmp1, tmp2); } if (is_null) { diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp index 52932faa3e4de..aefde19142e40 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp @@ -33,6 +33,8 @@ class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -43,7 +45,6 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void g1_write_barrier_pre(MacroAssembler* masm, Register store_addr, - Register new_val, Register pre_val, Register tmp1, Register tmp2); @@ -70,6 +71,29 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); #endif + +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + Register tmp3, + G1PostBarrierStubC2* c2_stub); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif + }; #endif // CPU_ARM_GC_G1_G1BARRIERSETASSEMBLER_ARM_HPP diff --git a/src/hotspot/cpu/arm/gc/g1/g1_arm.ad b/src/hotspot/cpu/arm/gc/g1/g1_arm.ad new file mode 100644 index 0000000000000..8a0a9e1aa531a --- /dev/null +++ b/src/hotspot/cpu/arm/gc/g1/g1_arm.ad @@ -0,0 +1,201 @@ +// +// 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. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_arm.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void write_barrier_pre(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2, + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, Rthread, tmp1, tmp2, stub); +} + +static void write_barrier_post(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + Register tmp3) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Rthread, tmp1, tmp2, tmp3, stub); +} + +%} + +instruct g1StoreP(indirect mem, iRegP src, iRegP tmp1, iRegP tmp2, iRegP tmp3, flagsReg icc) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL icc); + ins_cost(2 * (MEMORY_REF_COST + BRANCH_COST)); + format %{ "sd $src, $mem\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ str($src$$Register, Address($mem$$Register)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + $tmp3$$Register /* tmp3 */); + %} + ins_pipe(istore_mem_reg); +%} + +instruct g1CompareAndSwapP(iRegI res, indirect mem, iRegP newval, iRegP tmp1, iRegP tmp2, iRegP tmp3, iRegP oldval, flagsReg ccr ) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + effect(KILL ccr, TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(4 * (MEMORY_REF_COST + BRANCH_COST)); + format %{ "loop: \n\t" + "LDREX $tmp1, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t" + "CMP $tmp1, $oldval\n\t" + "STREX.eq $tmp1, $newval, $mem\n\t" + "MOV.ne $tmp1, 0 \n\t" + "EORS.eq $tmp1,$tmp1, 1 \n\t" + "B.eq loop \n\t" + "MOV $res, $tmp1" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + Label loop; + __ bind(loop); + __ ldrex($tmp1$$Register,$mem$$Address); + __ cmp($tmp1$$Register, $oldval$$Register); + __ strex($tmp1$$Register, $newval$$Register, $mem$$Address, eq); + __ mov($tmp1$$Register, 0, ne); + __ eors($tmp1$$Register, $tmp1$$Register, 1, eq); + __ b(loop, eq); + __ mov($res$$Register, $tmp1$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + $tmp3$$Register /* tmp3 */); + %} + ins_pipe(long_memory_op); +%} + + +instruct g1GetAndSetP(indirect mem, iRegP newval, iRegP tmp1, iRegP tmp2, iRegP tmp3, iRegP preval, flagsReg ccr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(KILL ccr, TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(4 * (MEMORY_REF_COST + BRANCH_COST)); + format %{ "loop: \n\t" + "LDREX $preval, $mem\n\t" + "STREX $tmp1, $newval, $mem\n\t" + "CMP $tmp1, 0 \n\t" + "B.ne loop \n\t" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + Label loop; + __ bind(loop); + __ ldrex($preval$$Register,$mem$$Address); + __ strex($tmp1$$Register, $newval$$Register, $mem$$Address); + __ cmp($tmp1$$Register, 0); + __ b(loop, ne); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + $tmp3$$Register /* tmp3 */); + %} + ins_pipe(long_memory_op); +%} + +instruct g1LoadP(iRegP dst, indirect mem, iRegP tmp1, iRegP tmp2, flagsReg icc) +%{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL icc); + ins_cost(MEMORY_REF_COST + BRANCH_COST); + format %{ "ld $dst, $mem\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + __ ldr($dst$$Register, Address($mem$$Register)); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(iload_mem); +%} diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp index ea19730673cb6..c13a259a1b960 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp @@ -31,6 +31,10 @@ #include "runtime/javaThread.hpp" #include "runtime/stubRoutines.hpp" +#ifdef COMPILER2 +#include "gc/shared/c2/barrierSetC2.hpp" +#endif // COMPILER2 + #define __ masm-> void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, @@ -206,7 +210,57 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { #ifdef COMPILER2 OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) { - Unimplemented(); // This must be implemented to support late barrier expansion. + if (!OptoReg::is_reg(opto_reg)) { + return OptoReg::Bad; + } + + const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if (!vm_reg->is_valid()){ + // skip APSR and FPSCR + return OptoReg::Bad; + } + + return opto_reg; } +void SaveLiveRegisters::initialize(BarrierStubC2* stub) { + // Record registers that needs to be saved/restored + RegMaskIterator rmi(stub->preserve_set()); + while (rmi.has_next()) { + const OptoReg::Name opto_reg = rmi.next(); + if (OptoReg::is_reg(opto_reg)) { + const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if (vm_reg->is_Register()) { + gp_regs += RegSet::of(vm_reg->as_Register()); + } else if (vm_reg->is_FloatRegister()) { + fp_regs += FloatRegSet::of(vm_reg->as_FloatRegister()); + } else { + fatal("Unknown register type"); + } + } + } + // Remove C-ABI SOE registers that will be updated + gp_regs -= RegSet::range(R4, R11) + RegSet::of(R13, R15); + + // Remove C-ABI SOE fp registers + fp_regs -= FloatRegSet::range(S16, S31); +} + +SaveLiveRegisters::SaveLiveRegisters(MacroAssembler* masm, BarrierStubC2* stub) + : masm(masm), + gp_regs(), + fp_regs() { + // Figure out what registers to save/restore + initialize(stub); + + // Save registers + if (gp_regs.size() > 0) __ push(RegisterSet::from(gp_regs)); + if (fp_regs.size() > 0) __ fpush(FloatRegisterSet::from(fp_regs)); +} + +SaveLiveRegisters::~SaveLiveRegisters() { + // Restore registers + if (fp_regs.size() > 0) __ fpop(FloatRegisterSet::from(fp_regs)); + if (gp_regs.size() > 0) __ pop(RegisterSet::from(gp_regs)); +} #endif // COMPILER2 diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp index 60021390ea26f..054d172f46340 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp @@ -31,7 +31,9 @@ #ifdef COMPILER2 #include "code/vmreg.hpp" #include "opto/optoreg.hpp" +#include "opto/regmask.hpp" +class BarrierStubC2; class Node; #endif // COMPILER2 @@ -69,4 +71,26 @@ class BarrierSetAssembler: public CHeapObj { #endif // COMPILER2 }; +#ifdef COMPILER2 +// This class saves and restores the registers that need to be preserved across +// the runtime call represented by a given C2 barrier stub. Use as follows: +// { +// SaveLiveRegisters save(masm, stub); +// .. +// __ bl(...); +// .. +// } +class SaveLiveRegisters { +private: + MacroAssembler* const masm; + RegSet gp_regs; + FloatRegSet fp_regs; + +public: + void initialize(BarrierStubC2* stub); + SaveLiveRegisters(MacroAssembler* masm, BarrierStubC2* stub); + ~SaveLiveRegisters(); +}; + +#endif // COMPILER2 #endif // CPU_ARM_GC_SHARED_BARRIERSETASSEMBLER_ARM_HPP diff --git a/src/hotspot/cpu/arm/globals_arm.hpp b/src/hotspot/cpu/arm/globals_arm.hpp index 084d10beea1d8..9c4b8500e1873 100644 --- a/src/hotspot/cpu/arm/globals_arm.hpp +++ b/src/hotspot/cpu/arm/globals_arm.hpp @@ -36,7 +36,7 @@ define_pd_global(bool, TrapBasedNullChecks, false); // Not needed define_pd_global(bool, DelayCompilerStubsGeneration, false); // No need - only few compiler's stubs -define_pd_global(uintx, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment. +define_pd_global(uintx, CodeCacheSegmentSize, 64); define_pd_global(intx, CodeEntryAlignment, 16); define_pd_global(intx, OptoLoopAlignment, 16); diff --git a/src/hotspot/cpu/arm/register_arm.hpp b/src/hotspot/cpu/arm/register_arm.hpp index 9f486d2a62586..d8961fd293578 100644 --- a/src/hotspot/cpu/arm/register_arm.hpp +++ b/src/hotspot/cpu/arm/register_arm.hpp @@ -303,6 +303,31 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { static const int max_fpr; }; +typedef AbstractRegSet RegSet; +typedef AbstractRegSet FloatRegSet; + +template <> +inline Register AbstractRegSet::first() { + if (_bitset == 0) { return noreg; } + return as_Register(count_trailing_zeros(_bitset)); +} + + +template <> +inline FloatRegister AbstractRegSet::first() { + uint32_t first = _bitset & -_bitset; + return first ? as_FloatRegister(exact_log2(first)) : fnoreg; +} + +template <> +inline FloatRegister AbstractRegSet::last() { + if (_bitset == 0) { return fnoreg; } + int last = max_size() - 1 - count_leading_zeros(_bitset); + return as_FloatRegister(last); +} + + + class VFPSystemRegisterImpl; typedef VFPSystemRegisterImpl* VFPSystemRegister; class VFPSystemRegisterImpl : public AbstractRegisterImpl { diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp index 80519fd89f426..0974ff1f9a9c3 100644 --- a/src/hotspot/cpu/arm/templateTable_arm.cpp +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp @@ -3974,6 +3974,7 @@ void TemplateTable::_new() { // make sure klass is initialized // make sure klass is fully initialized __ ldrb(Rtemp, Address(Rklass, InstanceKlass::init_state_offset())); + __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp); __ cmp(Rtemp, InstanceKlass::fully_initialized); __ b(slow_case, ne); diff --git a/src/hotspot/cpu/arm/upcallLinker_arm.cpp b/src/hotspot/cpu/arm/upcallLinker_arm.cpp index c7645f4a03351..696b2001e6b7b 100644 --- a/src/hotspot/cpu/arm/upcallLinker_arm.cpp +++ b/src/hotspot/cpu/arm/upcallLinker_arm.cpp @@ -25,7 +25,7 @@ #include "prims/upcallLinker.hpp" #include "utilities/debug.hpp" -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp index d445108098b86..b2711ac43b0b0 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp @@ -2502,19 +2502,19 @@ class Assembler : public AbstractAssembler { // load the constant are emitted beforehand. Store instructions need a // tmp reg if the constant is not encodable as immediate. // Size unpredictable. - void ld( Register d, RegisterOrConstant roc, Register s1 = noreg); - void lwa( Register d, RegisterOrConstant roc, Register s1 = noreg); - void lwz( Register d, RegisterOrConstant roc, Register s1 = noreg); - void lha( Register d, RegisterOrConstant roc, Register s1 = noreg); - void lhz( Register d, RegisterOrConstant roc, Register s1 = noreg); - void lbz( Register d, RegisterOrConstant roc, Register s1 = noreg); - void std( Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); - void stw( Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); - void sth( Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); - void stb( Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); - void add( Register d, Register s, RegisterOrConstant roc); - void add( Register d, RegisterOrConstant roc, Register s) { add(d, s, roc); } - void sub( Register d, Register s, RegisterOrConstant roc); + void ld( Register d, RegisterOrConstant roc, Register s1 = noreg); + void lwa(Register d, RegisterOrConstant roc, Register s1 = noreg); + void lwz(Register d, RegisterOrConstant roc, Register s1 = noreg); + void lha(Register d, RegisterOrConstant roc, Register s1 = noreg); + void lhz(Register d, RegisterOrConstant roc, Register s1 = noreg); + void lbz(Register d, RegisterOrConstant roc, Register s1 = noreg); + void std(Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); + void stw(Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); + void sth(Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); + void stb(Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); + void add(Register d, Register s, RegisterOrConstant roc); + void add(Register d, RegisterOrConstant roc, Register s) { add(d, s, roc); } + void sub(Register d, Register s, RegisterOrConstant roc); void xorr(Register d, Register s, RegisterOrConstant roc); void xorr(Register d, RegisterOrConstant roc, Register s) { xorr(d, s, roc); } void cmpw(ConditionRegister d, Register s, RegisterOrConstant roc); @@ -2522,6 +2522,17 @@ class Assembler : public AbstractAssembler { // Load pointer d from s1+roc. void ld_ptr(Register d, RegisterOrConstant roc, Register s1 = noreg) { ld(d, roc, s1); } + void ld( Register d, Address &a); + void lwa(Register d, Address &a); + void lwz(Register d, Address &a); + void lha(Register d, Address &a); + void lhz(Register d, Address &a); + void lbz(Register d, Address &a); + void std(Register d, Address &a, Register tmp = noreg); + void stw(Register d, Address &a, Register tmp = noreg); + void sth(Register d, Address &a, Register tmp = noreg); + void stb(Register d, Address &a, Register tmp = noreg); + // Emit several instructions to load a 64 bit constant. This issues a fixed // instruction pattern so that the constant can be patched later on. enum { diff --git a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp index 98c8b629844c9..b0eaaccf0d097 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp @@ -338,28 +338,46 @@ inline void Assembler::insrwi( Register a, Register s, int n, int b) // PPC 1, section 3.3.2 Fixed-Point Load Instructions inline void Assembler::lwzx( Register d, Register s1, Register s2) { emit_int32(LWZX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} +inline void Assembler::lwz( Register d, Address &a) { + lwz(d, a.index() != noreg ? RegisterOrConstant(a.index()) : RegisterOrConstant(a.disp()), a.base()); +} inline void Assembler::lwz( Register d, int si16, Register s1) { emit_int32(LWZ_OPCODE | rt(d) | d1(si16) | ra0mem(s1));} inline void Assembler::lwzu( Register d, int si16, Register s1) { assert(d != s1, "according to ibm manual"); emit_int32(LWZU_OPCODE | rt(d) | d1(si16) | rta0mem(s1));} inline void Assembler::lwax( Register d, Register s1, Register s2) { emit_int32(LWAX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} +inline void Assembler::lwa( Register d, Address &a) { + lwa(d, a.index() != noreg ? RegisterOrConstant(a.index()) : RegisterOrConstant(a.disp()), a.base()); +} inline void Assembler::lwa( Register d, int si16, Register s1) { emit_int32(LWA_OPCODE | rt(d) | ds(si16) | ra0mem(s1));} inline void Assembler::lwbrx( Register d, Register s1, Register s2) { emit_int32(LWBRX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} inline void Assembler::lhzx( Register d, Register s1, Register s2) { emit_int32(LHZX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} +inline void Assembler::lhz( Register d, Address &a) { + lhz(d, a.index() != noreg ? RegisterOrConstant(a.index()) : RegisterOrConstant(a.disp()), a.base()); +} inline void Assembler::lhz( Register d, int si16, Register s1) { emit_int32(LHZ_OPCODE | rt(d) | d1(si16) | ra0mem(s1));} inline void Assembler::lhzu( Register d, int si16, Register s1) { assert(d != s1, "according to ibm manual"); emit_int32(LHZU_OPCODE | rt(d) | d1(si16) | rta0mem(s1));} inline void Assembler::lhbrx( Register d, Register s1, Register s2) { emit_int32(LHBRX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} inline void Assembler::lhax( Register d, Register s1, Register s2) { emit_int32(LHAX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} +inline void Assembler::lha( Register d, Address &a) { + lha(d, a.index() != noreg ? RegisterOrConstant(a.index()) : RegisterOrConstant(a.disp()), a.base()); +} inline void Assembler::lha( Register d, int si16, Register s1) { emit_int32(LHA_OPCODE | rt(d) | d1(si16) | ra0mem(s1));} inline void Assembler::lhau( Register d, int si16, Register s1) { assert(d != s1, "according to ibm manual"); emit_int32(LHAU_OPCODE | rt(d) | d1(si16) | rta0mem(s1));} inline void Assembler::lbzx( Register d, Register s1, Register s2) { emit_int32(LBZX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} +inline void Assembler::lbz( Register d, Address &a) { + lbz(d, a.index() != noreg ? RegisterOrConstant(a.index()) : RegisterOrConstant(a.disp()), a.base()); +} inline void Assembler::lbz( Register d, int si16, Register s1) { emit_int32(LBZ_OPCODE | rt(d) | d1(si16) | ra0mem(s1));} inline void Assembler::lbzu( Register d, int si16, Register s1) { assert(d != s1, "according to ibm manual"); emit_int32(LBZU_OPCODE | rt(d) | d1(si16) | rta0mem(s1));} +inline void Assembler::ld( Register d, Address &a) { + ld(d, a.index() != noreg ? RegisterOrConstant(a.index()) : RegisterOrConstant(a.disp()), a.base()); +} inline void Assembler::ld( Register d, int si16, Register s1) { emit_int32(LD_OPCODE | rt(d) | ds(si16) | ra0mem(s1));} inline void Assembler::ld( Register d, ByteSize si16, Register s1) { assert(in_bytes(si16) < 0x7fff, "overflow"); ld(d, in_bytes(si16), s1); } inline void Assembler::ldx( Register d, Register s1, Register s2) { emit_int32(LDX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} @@ -371,19 +389,31 @@ inline void Assembler::ld_ptr(Register d, ByteSize b, Register s1) { ld(d, in_by // PPC 1, section 3.3.3 Fixed-Point Store Instructions inline void Assembler::stwx( Register d, Register s1, Register s2) { emit_int32(STWX_OPCODE | rs(d) | ra0mem(s1) | rb(s2));} +inline void Assembler::stw( Register d, Address &a, Register tmp) { + stw(d, a.index() != noreg ? RegisterOrConstant(a.index()) : RegisterOrConstant(a.disp()), a.base(), tmp); +} inline void Assembler::stw( Register d, int si16, Register s1) { emit_int32(STW_OPCODE | rs(d) | d1(si16) | ra0mem(s1));} inline void Assembler::stwu( Register d, int si16, Register s1) { emit_int32(STWU_OPCODE | rs(d) | d1(si16) | rta0mem(s1));} inline void Assembler::stwbrx( Register d, Register s1, Register s2) { emit_int32(STWBRX_OPCODE | rs(d) | ra0mem(s1) | rb(s2));} inline void Assembler::sthx( Register d, Register s1, Register s2) { emit_int32(STHX_OPCODE | rs(d) | ra0mem(s1) | rb(s2));} +inline void Assembler::sth( Register d, Address &a, Register tmp) { + sth(d, a.index() != noreg ? RegisterOrConstant(a.index()) : RegisterOrConstant(a.disp()), a.base(), tmp); +} inline void Assembler::sth( Register d, int si16, Register s1) { emit_int32(STH_OPCODE | rs(d) | d1(si16) | ra0mem(s1));} inline void Assembler::sthu( Register d, int si16, Register s1) { emit_int32(STHU_OPCODE | rs(d) | d1(si16) | rta0mem(s1));} inline void Assembler::sthbrx( Register d, Register s1, Register s2) { emit_int32(STHBRX_OPCODE | rs(d) | ra0mem(s1) | rb(s2));} inline void Assembler::stbx( Register d, Register s1, Register s2) { emit_int32(STBX_OPCODE | rs(d) | ra0mem(s1) | rb(s2));} +inline void Assembler::stb( Register d, Address &a, Register tmp) { + stb(d, a.index() != noreg ? RegisterOrConstant(a.index()) : RegisterOrConstant(a.disp()), a.base(), tmp); +} inline void Assembler::stb( Register d, int si16, Register s1) { emit_int32(STB_OPCODE | rs(d) | d1(si16) | ra0mem(s1));} inline void Assembler::stbu( Register d, int si16, Register s1) { emit_int32(STBU_OPCODE | rs(d) | d1(si16) | rta0mem(s1));} +inline void Assembler::std( Register d, Address &a, Register tmp) { + std(d, a.index() != noreg ? RegisterOrConstant(a.index()) : RegisterOrConstant(a.disp()), a.base(), tmp); +} inline void Assembler::std( Register d, int si16, Register s1) { emit_int32(STD_OPCODE | rs(d) | ds(si16) | ra0mem(s1));} inline void Assembler::stdx( Register d, Register s1, Register s2) { emit_int32(STDX_OPCODE | rs(d) | ra0mem(s1) | rb(s2));} inline void Assembler::stdu( Register d, int si16, Register s1) { emit_int32(STDU_OPCODE | rs(d) | ds(si16) | rta0mem(s1));} diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 42934dc7c3179..36e1ac82334fd 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -133,9 +133,20 @@ void LIR_Assembler::osr_entry() { // copied into place by code emitted in the IR. Register OSR_buf = osrBufferPointer()->as_register(); - { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); - int monitor_offset = BytesPerWord * method()->max_locals() + - (2 * BytesPerWord) * (number_of_locks - 1); + { + assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); + + const int locals_space = BytesPerWord * method()->max_locals(); + int monitor_offset = locals_space + (2 * BytesPerWord) * (number_of_locks - 1); + bool use_OSR_bias = false; + + if (!Assembler::is_simm16(monitor_offset + BytesPerWord) && number_of_locks > 0) { + // Offsets too large for ld instructions. Use bias. + __ add_const_optimized(OSR_buf, OSR_buf, locals_space); + monitor_offset -= locals_space; + use_OSR_bias = true; + } + // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in // the OSR buffer using 2 word entries: first the lock and then // the oop. @@ -157,9 +168,14 @@ void LIR_Assembler::osr_entry() { mo = frame_map()->address_for_monitor_object(i); assert(ml.index() == noreg && mo.index() == noreg, "sanity"); __ ld(R0, slot_offset + 0, OSR_buf); - __ std(R0, ml.disp(), ml.base()); + __ std(R0, ml); __ ld(R0, slot_offset + 1*BytesPerWord, OSR_buf); - __ std(R0, mo.disp(), mo.base()); + __ std(R0, mo); + } + + if (use_OSR_bias) { + // Restore. + __ sub_const_optimized(OSR_buf, OSR_buf, locals_space); } } } @@ -213,7 +229,11 @@ int LIR_Assembler::emit_unwind_handler() { if (method()->is_synchronized()) { monitor_address(0, FrameMap::R4_opr); stub = new MonitorExitStub(FrameMap::R4_opr, true, 0); - __ unlock_object(R5, R6, R4, *stub->entry()); + if (LockingMode == LM_MONITOR) { + __ b(*stub->entry()); + } else { + __ unlock_object(R5, R6, R4, *stub->entry()); + } __ bind(*stub->continuation()); } @@ -581,7 +601,7 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { __ fcmpu(CCR0, rsrc, rsrc); if (dst_in_memory) { __ li(R0, 0); // 0 in case of NAN - __ std(R0, addr.disp(), addr.base()); + __ std(R0, addr); } else { __ li(dst->as_register(), 0); } @@ -605,7 +625,7 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { __ fcmpu(CCR0, rsrc, rsrc); if (dst_in_memory) { __ li(R0, 0); // 0 in case of NAN - __ std(R0, addr.disp(), addr.base()); + __ std(R0, addr); } else { __ li(dst->as_register_lo(), 0); } @@ -873,20 +893,20 @@ void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) { int value = c->as_jint_bits(); __ load_const_optimized(src_reg, value); Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); - __ stw(src_reg, addr.disp(), addr.base()); + __ stw(src_reg, addr); break; } case T_ADDRESS: { int value = c->as_jint_bits(); __ load_const_optimized(src_reg, value); Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); - __ std(src_reg, addr.disp(), addr.base()); + __ std(src_reg, addr); break; } case T_OBJECT: { jobject2reg(c->as_jobject(), src_reg); Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); - __ std(src_reg, addr.disp(), addr.base()); + __ std(src_reg, addr); break; } case T_LONG: @@ -894,7 +914,7 @@ void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) { int value = c->as_jlong_bits(); __ load_const_optimized(src_reg, value); Address addr = frame_map()->address_for_double_slot(dest->double_stack_ix()); - __ std(src_reg, addr.disp(), addr.base()); + __ std(src_reg, addr); break; } default: @@ -1070,24 +1090,24 @@ void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { case T_FLOAT: { Address from = frame_map()->address_for_slot(src->single_stack_ix()); Address to = frame_map()->address_for_slot(dest->single_stack_ix()); - __ lwz(tmp, from.disp(), from.base()); - __ stw(tmp, to.disp(), to.base()); + __ lwz(tmp, from); + __ stw(tmp, to); break; } case T_ADDRESS: case T_OBJECT: { Address from = frame_map()->address_for_slot(src->single_stack_ix()); Address to = frame_map()->address_for_slot(dest->single_stack_ix()); - __ ld(tmp, from.disp(), from.base()); - __ std(tmp, to.disp(), to.base()); + __ ld(tmp, from); + __ std(tmp, to); break; } case T_LONG: case T_DOUBLE: { Address from = frame_map()->address_for_double_slot(src->double_stack_ix()); Address to = frame_map()->address_for_double_slot(dest->double_stack_ix()); - __ ld(tmp, from.disp(), from.base()); - __ std(tmp, to.disp(), to.base()); + __ ld(tmp, from); + __ std(tmp, to); break; } @@ -2274,6 +2294,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { } __ lbz(op->tmp1()->as_register(), in_bytes(InstanceKlass::init_state_offset()), op->klass()->as_register()); + // acquire barrier included in membar_storestore() which follows the allocation immediately. __ cmpwi(CCR0, op->tmp1()->as_register(), InstanceKlass::fully_initialized); __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *op->stub()->entry()); } diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 83fad376d292a..ea4d76e200fc2 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -114,6 +114,8 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox /*check without membar and ldarx first*/true); // If compare/exchange succeeded we found an unlocked object and we now have locked it // hence we are done. + } else { + assert(false, "Unhandled LockingMode:%d", LockingMode); } b(done); @@ -168,6 +170,8 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb MacroAssembler::cmpxchgx_hint_release_lock(), noreg, &slow_int); + } else { + assert(false, "Unhandled LockingMode:%d", LockingMode); } b(done); bind(slow_int); diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index 4c1ffeb0d768e..eb16af5e9db1b 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -117,9 +117,9 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - common_abi* sender_abi = (common_abi*) fp; + volatile common_abi* sender_abi = (common_abi*) fp; // May get updated concurrently by deoptimization! intptr_t* sender_sp = (intptr_t*) fp; - address sender_pc = (address) sender_abi->lr;; + address sender_pc = (address) sender_abi->lr; if (Continuation::is_return_barrier_entry(sender_pc)) { // If our sender_pc is the return barrier, then our "real" sender is the continuation entry @@ -134,9 +134,18 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } + intptr_t* unextended_sender_sp = is_interpreted_frame() ? interpreter_frame_sender_sp() : sender_sp; + + // If the sender is a deoptimized nmethod we need to check if the original pc is valid. + nmethod* sender_nm = sender_blob->as_nmethod_or_null(); + if (sender_nm != nullptr && sender_nm->is_deopt_pc(sender_pc)) { + address orig_pc = *(address*)((address)unextended_sender_sp + sender_nm->orig_pc_offset()); + if (!sender_nm->insts_contains_inclusive(orig_pc)) return false; + } + // It should be safe to construct the sender though it might not be valid. - frame sender(sender_sp, sender_pc, nullptr /* unextended_sp */, nullptr /* fp */, sender_blob); + frame sender(sender_sp, sender_pc, unextended_sender_sp, nullptr /* fp */, sender_blob); // Do we have a valid fp? address sender_fp = (address) sender.fp(); diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp index 7d230d301c22b..39693bdf925bf 100644 --- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp @@ -41,10 +41,20 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> +static void generate_marking_inactive_test(MacroAssembler* masm) { + int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbz(R0, active_offset, R16_thread); // tmp1 := *(mark queue active address) + __ cmpwi(CCR0, R0, 0); +} + void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register from, Register to, Register count, Register preserve1, Register preserve2) { @@ -58,13 +68,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm Label filtered; // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ lwz(R0, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread); - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbz(R0, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread); - } - __ cmpdi(CCR0, R0, 0); + generate_marking_inactive_test(masm); __ beq(CCR0, filtered); __ save_LR(R0); @@ -109,35 +113,48 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ restore_LR(R0); } +static void generate_queue_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register value, const Register temp) { + assert_different_registers(value, temp); + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + __ ld(temp, in_bytes(index_offset), R16_thread); // temp := *(index address) + __ cmpdi(CCR0, temp, 0); // jump to runtime if index == 0 (full buffer) + __ beq(CCR0, runtime); + // The buffer is not full, store value into it. + __ ld(R0, in_bytes(buffer_offset), R16_thread); // R0 := buffer address + __ addi(temp, temp, -wordSize); // temp := next index + __ std(temp, in_bytes(index_offset), R16_thread); // *(index address) := next index + __ stdx(value, temp, R0); // *(buffer address + next index) := value +} + void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, DecoratorSet decorators, Register obj, RegisterOrConstant ind_or_offs, Register pre_val, Register tmp1, Register tmp2, MacroAssembler::PreservationLevel preservation_level) { + assert_different_registers(pre_val, tmp1, tmp2); + bool not_null = (decorators & IS_NOT_NULL) != 0, preloaded = obj == noreg; Register nv_save = noreg; - if (preloaded) { + // Determine necessary runtime invocation preservation measures + const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR; + const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS; + const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS; + int nbytes_save = 0; + + if (pre_val->is_volatile() && preloaded && !preserve_gp_registers) { // We are not loading the previous value so make // sure that we don't trash the value in pre_val // with the code below. - assert_different_registers(pre_val, tmp1, tmp2); - if (pre_val->is_volatile()) { - nv_save = !tmp1->is_volatile() ? tmp1 : tmp2; - assert(!nv_save->is_volatile(), "need one nv temp register if pre_val lives in volatile register"); - } + nv_save = !tmp1->is_volatile() ? tmp1 : tmp2; + assert(!nv_save->is_volatile(), "need one nv temp register if pre_val lives in volatile register"); } Label runtime, filtered; - // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ lwz(tmp1, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread); - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbz(tmp1, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread); - } - __ cmpdi(CCR0, tmp1, 0); + generate_marking_inactive_test(masm); __ beq(CCR0, filtered); // Do we need to load the previous value? @@ -175,28 +192,12 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator // Can we store original value in the thread's buffer? // Is index == 0? // (The index field is typed as size_t.) - const Register Rbuffer = tmp1, Rindex = tmp2; - - __ ld(Rindex, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()), R16_thread); - __ cmpdi(CCR0, Rindex, 0); - __ beq(CCR0, runtime); // If index == 0, goto runtime. - __ ld(Rbuffer, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()), R16_thread); - - __ addi(Rindex, Rindex, -wordSize); // Decrement index. - __ std(Rindex, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()), R16_thread); - - // Record the previous value. - __ stdx(pre_val, Rbuffer, Rindex); + generate_queue_insertion(masm, G1ThreadLocalData::satb_mark_queue_index_offset(), G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, pre_val, tmp1); __ b(filtered); __ bind(runtime); - // Determine necessary runtime invocation preservation measures - const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR; - const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS; - const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS; - int nbytes_save = 0; - // May need to preserve LR. Also needed if current frame is not compatible with C calling convention. if (needs_frame) { if (preserve_gp_registers) { @@ -210,11 +211,11 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator __ push_frame_reg_args(nbytes_save, tmp2); } - if (pre_val->is_volatile() && preloaded && !preserve_gp_registers) { + if (nv_save != noreg) { __ mr(nv_save, pre_val); // Save pre_val across C call if it was preloaded. } __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, R16_thread); - if (pre_val->is_volatile() && preloaded && !preserve_gp_registers) { + if (nv_save != noreg) { __ mr(pre_val, nv_save); // restore } @@ -230,6 +231,26 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator __ bind(filtered); } +static void generate_region_crossing_test(MacroAssembler* masm, const Register store_addr, const Register new_val) { + __ xorr(R0, store_addr, new_val); // tmp1 := store address ^ new value + __ srdi_(R0, R0, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes) +} + +static Address generate_card_young_test(MacroAssembler* masm, const Register store_addr, const Register tmp1, const Register tmp2) { + CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); + __ load_const_optimized(tmp1, (address)(ct->card_table()->byte_map_base()), tmp2); + __ srdi(tmp2, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base + __ lbzx(R0, tmp1, tmp2); // tmp1 := card address + __ cmpwi(CCR0, R0, (int)G1CardTable::g1_young_card_val()); + return Address(tmp1, tmp2); // return card address +} + +static void generate_card_dirty_test(MacroAssembler* masm, Address card_addr) { + __ membar(Assembler::StoreLoad); // Must reload after StoreLoad membar due to concurrent refinement + __ lbzx(R0, card_addr.base(), card_addr.index()); // tmp2 := card + __ cmpwi(CCR0, R0, (int)G1CardTable::dirty_card_val()); // tmp2 := card == dirty_card_val? +} + void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators, Register store_addr, Register new_val, Register tmp1, Register tmp2, Register tmp3, @@ -241,9 +262,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); - // Does store cross heap regions? - __ xorr(tmp1, store_addr, new_val); - __ srdi_(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); + generate_region_crossing_test(masm, store_addr, new_val); __ beq(CCR0, filtered); // Crosses regions, storing null? @@ -257,43 +276,22 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato __ beq(CCR0, filtered); } - // Storing region crossing non-null, is card already dirty? - const Register Rcard_addr = tmp1; - Register Rbase = tmp2; - __ load_const_optimized(Rbase, (address)(ct->card_table()->byte_map_base()), /*temp*/ tmp3); - - __ srdi(Rcard_addr, store_addr, CardTable::card_shift()); - - // Get the address of the card. - __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr); - __ cmpwi(CCR0, tmp3, (int)G1CardTable::g1_young_card_val()); + Address card_addr = generate_card_young_test(masm, store_addr, tmp1, tmp2); __ beq(CCR0, filtered); - __ membar(Assembler::StoreLoad); - __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr); // Reload after membar. - __ cmpwi(CCR0, tmp3 /* card value */, (int)G1CardTable::dirty_card_val()); + generate_card_dirty_test(masm, card_addr); __ beq(CCR0, filtered); - // Storing a region crossing, non-null oop, card is clean. - // Dirty card and log. - __ li(tmp3, (int)G1CardTable::dirty_card_val()); - //release(); // G1: oops are allowed to get visible after dirty marking. - __ stbx(tmp3, Rbase, Rcard_addr); - - __ add(Rcard_addr, Rbase, Rcard_addr); // This is the address which needs to get enqueued. - Rbase = noreg; // end of lifetime + __ li(R0, (int)G1CardTable::dirty_card_val()); + __ stbx(R0, card_addr.base(), card_addr.index()); // *(card address) := dirty_card_val - const Register Rqueue_index = tmp2, - Rqueue_buf = tmp3; - __ ld(Rqueue_index, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()), R16_thread); - __ cmpdi(CCR0, Rqueue_index, 0); - __ beq(CCR0, runtime); // index == 0 then jump to runtime - __ ld(Rqueue_buf, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()), R16_thread); + Register Rcard_addr = tmp3; + __ add(Rcard_addr, card_addr.base(), card_addr.index()); // This is the address which needs to get enqueued. - __ addi(Rqueue_index, Rqueue_index, -wordSize); // decrement index - __ std(Rqueue_index, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()), R16_thread); - - __ stdx(Rcard_addr, Rqueue_buf, Rqueue_index); // store card + generate_queue_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, Rcard_addr, tmp1); __ b(filtered); __ bind(runtime); @@ -392,6 +390,142 @@ void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value __ bind(done); } +#ifdef COMPILER2 + +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { + SaveLiveRegisters save_registers(masm, stub); + __ call_VM_leaf(runtime_path, arg, R16_thread); +} + +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* stub) { + assert_different_registers(obj, tmp1, tmp2, R0); + assert_different_registers(pre_val, tmp1, R0); + assert(!UseCompressedOops || tmp2 != noreg, "tmp2 needed with CompressedOops"); + + stub->initialize_registers(obj, pre_val, R16_thread, tmp1, tmp2); + + generate_marking_inactive_test(masm); + __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *stub->entry()); + + __ bind(*stub->continuation()); +} + +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register tmp1 = stub->tmp1(); + + __ bind(*stub->entry()); + + if (obj != noreg) { + // Note: C2 currently doesn't use implicit null checks with barriers. + // Otherwise, obj could be null and the following instruction would raise a SIGSEGV. + if (UseCompressedOops) { + __ lwz(pre_val, 0, obj); + } else { + __ ld(pre_val, 0, obj); + } + } + __ cmpdi(CCR0, pre_val, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), *stub->continuation()); + + Register pre_val_decoded = pre_val; + if (UseCompressedOops) { + pre_val_decoded = __ decode_heap_oop_not_null(stub->tmp2(), pre_val); + } + + generate_queue_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, pre_val_decoded, tmp1); + __ b(*stub->continuation()); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, pre_val_decoded, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); + __ b(*stub->continuation()); +} + +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* stub, + bool decode_new_val) { + assert_different_registers(store_addr, new_val, tmp1, R0); + assert_different_registers(store_addr, tmp1, tmp2, R0); + + stub->initialize_registers(R16_thread, tmp1, tmp2); + + bool null_check_required = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; + Register new_val_decoded = new_val; + + if (decode_new_val) { + assert(UseCompressedOops, "or should not be here"); + if (null_check_required && CompressedOops::base() != nullptr) { + // We prefer doing the null check after the region crossing check. + // Only compressed oop modes with base != null require a null check here. + __ cmpwi(CCR0, new_val, 0); + __ beq(CCR0, *stub->continuation()); + null_check_required = false; + } + new_val_decoded = __ decode_heap_oop_not_null(tmp2, new_val); + } + + generate_region_crossing_test(masm, store_addr, new_val_decoded); + __ beq(CCR0, *stub->continuation()); + + // crosses regions, storing null? + if (null_check_required) { + __ cmpdi(CCR0, new_val_decoded, 0); + __ beq(CCR0, *stub->continuation()); + } + + Address card_addr = generate_card_young_test(masm, store_addr, tmp1, tmp2); + assert(card_addr.base() == tmp1 && card_addr.index() == tmp2, "needed by post barrier stub"); + __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *stub->entry()); + + __ bind(*stub->continuation()); +} + +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Address card_addr(stub->tmp1(), stub->tmp2()); // See above. + + __ bind(*stub->entry()); + + generate_card_dirty_test(masm, card_addr); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), *stub->continuation()); + + __ li(R0, (int)G1CardTable::dirty_card_val()); + __ stbx(R0, card_addr.base(), card_addr.index()); // *(card address) := dirty_card_val + + Register Rcard_addr = stub->tmp1(); + __ add(Rcard_addr, card_addr.base(), card_addr.index()); // This is the address which needs to get enqueued. + + generate_queue_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, Rcard_addr, stub->tmp2()); + __ b(*stub->continuation()); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, Rcard_addr, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); + __ b(*stub->continuation()); +} + +#endif // COMPILER2 + #ifdef COMPILER1 #undef __ @@ -470,13 +604,7 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* __ std(tmp2, -24, R1_SP); // Is marking still active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ lwz(tmp, satb_q_active_byte_offset, R16_thread); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbz(tmp, satb_q_active_byte_offset, R16_thread); - } - __ cmpdi(CCR0, tmp, 0); + generate_marking_inactive_test(sasm); __ beq(CCR0, marking_not_active); __ bind(restart); diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp index d9a252ff6eaee..1c9fe8a5d106f 100644 --- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp @@ -30,10 +30,16 @@ #include "gc/shared/modRefBarrierSetAssembler.hpp" #include "utilities/macros.hpp" +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif + class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -59,6 +65,25 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { MacroAssembler::PreservationLevel preservation_level); public: +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* c2_stub, + bool decode_new_val); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif #ifdef COMPILER1 void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); diff --git a/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad b/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad new file mode 100644 index 0000000000000..f4163242cad7b --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad @@ -0,0 +1,684 @@ +// +// 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. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_ppc.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void pre_write_barrier(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2 = noreg, // only needed with CompressedOops when pre_val needs to be preserved + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, tmp1, (tmp2 != noreg) ? tmp2 : pre_val, stub); +} + +static void post_write_barrier(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + bool decode_new_val = false) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, tmp2, stub, decode_new_val); +} + +%} + +instruct g1StoreP(indirect mem, iRegPsrc src, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "std $mem, $src\t# ptr" %} + ins_encode %{ + pre_write_barrier(masm, this, + $mem$$Register, + $tmp1$$Register, + $tmp2$$Register, + noreg, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ std($src$$Register, 0, $mem$$Register); + post_write_barrier(masm, this, + $mem$$Register, + $src$$Register /* new_val */, + $tmp1$$Register, + $tmp2$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1StoreN(indirect mem, iRegNsrc src, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "stw $mem, $src\t# ptr" %} + ins_encode %{ + pre_write_barrier(masm, this, + $mem$$Register, + $tmp1$$Register, + $tmp2$$Register, + noreg, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ stw($src$$Register, 0, $mem$$Register); + post_write_barrier(masm, this, + $mem$$Register, + $src$$Register /* new_val */, + $tmp1$$Register, + $tmp2$$Register, + true /* decode_new_val */); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1EncodePAndStoreN(indirect mem, iRegPsrc src, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "encode_heap_oop $src\n\t" + "stw $mem, $src\t# ptr" %} + ins_encode %{ + pre_write_barrier(masm, this, + $mem$$Register, + $tmp1$$Register, + $tmp2$$Register, + noreg, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + Register encoded_oop = noreg; + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + encoded_oop = __ encode_heap_oop($tmp2$$Register, $src$$Register); + } else { + encoded_oop = __ encode_heap_oop_not_null($tmp2$$Register, $src$$Register); + } + __ stw(encoded_oop, 0, $mem$$Register); + post_write_barrier(masm, this, + $mem$$Register, + $src$$Register /* new_val */, + $tmp1$$Register, + $tmp2$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndExchangeP(iRegPdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndExchangeNode*)n)->order() != MemNode::acquire && ((CompareAndExchangeNode*)n)->order() != MemNode::seqcst)); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "cmpxchgd $newval, $mem" %} + ins_encode %{ + Label no_update; + __ cmpxchgd(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndExchangeP_acq(iRegPdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndExchangeNode*)n)->order() == MemNode::acquire || ((CompareAndExchangeNode*)n)->order() == MemNode::seqcst)); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "cmpxchgd acq $newval, $mem" %} + ins_encode %{ + Label no_update; + __ cmpxchgd(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register); + __ bind(no_update); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndExchangeN(iRegNdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndExchangeNode*)n)->order() != MemNode::acquire && ((CompareAndExchangeNode*)n)->order() != MemNode::seqcst)); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "cmpxchgw $newval, $mem" %} + ins_encode %{ + Label no_update; + __ cmpxchgw(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register, + true /* decode_new_val */); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndExchangeN_acq(iRegNdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndExchangeNode*)n)->order() == MemNode::acquire || ((CompareAndExchangeNode*)n)->order() == MemNode::seqcst)); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "cmpxchgw acq $newval, $mem" %} + ins_encode %{ + Label no_update; + __ cmpxchgw(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register, + true /* decode_new_val */); + __ bind(no_update); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndSwapP(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst)); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "CMPXCHGD $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */); + __ li($res$$Register, 1); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndSwapP_acq(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "CMPXCHGD acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */); + __ li($res$$Register, 1); + __ bind(no_update); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndSwapN(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst)); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "CMPXCHGW $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */, + true /* decode_new_val */); + __ li($res$$Register, 1); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndSwapN_acq(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "CMPXCHGW acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */, + true /* decode_new_val */); + __ li($res$$Register, 1); + __ bind(no_update); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct weakG1CompareAndSwapP(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst)); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "weak CMPXCHGD $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */); + __ li($res$$Register, 1); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct weakG1CompareAndSwapP_acq(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "weak CMPXCHGD acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */); + __ li($res$$Register, 1); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + __ bind(no_update); // weak version requires no memory barrier on failure + %} + ins_pipe(pipe_class_default); +%} + +instruct weakG1CompareAndSwapN(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst)); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "weak CMPXCHGW $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */, + true /* decode_new_val */); + __ li($res$$Register, 1); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct weakG1CompareAndSwapN_acq(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "weak CMPXCHGW acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */, + true /* decode_new_val */); + __ li($res$$Register, 1); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + __ bind(no_update); // weak version requires no memory barrier on failure + %} + ins_pipe(pipe_class_default); +%} + +instruct g1GetAndSetP(iRegPdst res, indirect mem, iRegPsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (GetAndSetP mem newval)); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "GetAndSetP $newval, $mem" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + __ getandsetd($res$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::cmpxchgx_hint_atomic_update()); + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg /* obj */, + $res$$Register /* res */, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct g1GetAndSetN(iRegNdst res, indirect mem, iRegNsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (GetAndSetN mem newval)); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "GetAndSetN $newval, $mem" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + __ getandsetw($res$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::cmpxchgx_hint_atomic_update()); + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg /* obj */, + $res$$Register /* res */, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register, + true /* decode_new_val */); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct g1LoadP(iRegPdst dst, memoryAlg4 mem, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_Load()->is_unordered() && n->as_Load()->barrier_data() != 0); + // This instruction does not need an acquiring counterpart because it is only + // used for reference loading (Reference::get()). + match(Set dst (LoadP mem)); + effect(TEMP_DEF dst, TEMP tmp, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "ld $dst, $mem\t# ptr" %} + ins_encode %{ + __ ld($dst$$Register, $mem$$disp, $mem$$base$$Register); + pre_write_barrier(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1LoadN(iRegNdst dst, memoryAlg4 mem, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_Load()->is_unordered() && n->as_Load()->barrier_data() != 0); + // This instruction does not need an acquiring counterpart because it is only + // used for reference loading (Reference::get()). + match(Set dst (LoadN mem)); + effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "lwz $dst, $mem\t# ptr" %} + ins_encode %{ + __ lwz($dst$$Register, $mem$$disp, $mem$$base$$Register); + pre_write_barrier(masm, this, + noreg /* obj */, + $dst$$Register, + $tmp1$$Register, + $tmp2$$Register); + %} + ins_pipe(pipe_class_default); +%} diff --git a/src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.cpp deleted file mode 100644 index ca826e47352b5..0000000000000 --- a/src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, 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. - */ - -#include "precompiled.hpp" -#include "asm/register.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/codeBlob.hpp" -#include "code/vmreg.inline.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xBarrierSet.hpp" -#include "gc/x/xBarrierSetAssembler.hpp" -#include "gc/x/xBarrierSetRuntime.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "memory/resourceArea.hpp" -#include "register_ppc.hpp" -#include "runtime/sharedRuntime.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" -#ifdef COMPILER1 -#include "c1/c1_LIRAssembler.hpp" -#include "c1/c1_MacroAssembler.hpp" -#include "gc/x/c1/xBarrierSetC1.hpp" -#endif // COMPILER1 -#ifdef COMPILER2 -#include "gc/x/c2/xBarrierSetC2.hpp" -#endif // COMPILER2 - -#undef __ -#define __ masm-> - -void XBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register base, RegisterOrConstant ind_or_offs, Register dst, - Register tmp1, Register tmp2, - MacroAssembler::PreservationLevel preservation_level, Label *L_handle_null) { - __ block_comment("load_at (zgc) {"); - - // Check whether a special gc barrier is required for this particular load - // (e.g. whether it's a reference load or not) - if (!XBarrierSet::barrier_needed(decorators, type)) { - BarrierSetAssembler::load_at(masm, decorators, type, base, ind_or_offs, dst, - tmp1, tmp2, preservation_level, L_handle_null); - return; - } - - if (ind_or_offs.is_register()) { - assert_different_registers(base, ind_or_offs.as_register(), tmp1, tmp2, R0, noreg); - assert_different_registers(dst, ind_or_offs.as_register(), tmp1, tmp2, R0, noreg); - } else { - assert_different_registers(base, tmp1, tmp2, R0, noreg); - assert_different_registers(dst, tmp1, tmp2, R0, noreg); - } - - /* ==== Load the pointer using the standard implementation for the actual heap access - and the decompression of compressed pointers ==== */ - // Result of 'load_at' (standard implementation) will be written back to 'dst'. - // As 'base' is required for the C-call, it must be reserved in case of a register clash. - Register saved_base = base; - if (base == dst) { - __ mr(tmp2, base); - saved_base = tmp2; - } - - BarrierSetAssembler::load_at(masm, decorators, type, base, ind_or_offs, dst, - tmp1, noreg, preservation_level, L_handle_null); - - /* ==== Check whether pointer is dirty ==== */ - Label skip_barrier; - - // Load bad mask into scratch register. - __ ld(tmp1, (intptr_t) XThreadLocalData::address_bad_mask_offset(), R16_thread); - - // The color bits of the to-be-tested pointer do not have to be equivalent to the 'bad_mask' testing bits. - // A pointer is classified as dirty if any of the color bits that also match the bad mask is set. - // Conversely, it follows that the logical AND of the bad mask and the pointer must be zero - // if the pointer is not dirty. - // Only dirty pointers must be processed by this barrier, so we can skip it in case the latter condition holds true. - __ and_(tmp1, tmp1, dst); - __ beq(CCR0, skip_barrier); - - /* ==== Invoke barrier ==== */ - int nbytes_save = 0; - - const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR; - const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS; - const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS; - - const bool preserve_R3 = dst != R3_ARG1; - - if (needs_frame) { - if (preserve_gp_registers) { - nbytes_save = (preserve_fp_registers - ? MacroAssembler::num_volatile_gp_regs + MacroAssembler::num_volatile_fp_regs - : MacroAssembler::num_volatile_gp_regs) * BytesPerWord; - nbytes_save -= preserve_R3 ? 0 : BytesPerWord; - __ save_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers, preserve_R3); - } - - __ save_LR(tmp1); - __ push_frame_reg_args(nbytes_save, tmp1); - } - - // Setup arguments - if (saved_base != R3_ARG1) { - __ mr_if_needed(R3_ARG1, dst); - __ add(R4_ARG2, ind_or_offs, saved_base); - } else if (dst != R4_ARG2) { - __ add(R4_ARG2, ind_or_offs, saved_base); - __ mr(R3_ARG1, dst); - } else { - __ add(R0, ind_or_offs, saved_base); - __ mr(R3_ARG1, dst); - __ mr(R4_ARG2, R0); - } - - __ call_VM_leaf(XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators)); - - Register result = R3_RET; - if (needs_frame) { - __ pop_frame(); - __ restore_LR(tmp1); - - if (preserve_R3) { - __ mr(R0, R3_RET); - result = R0; - } - - if (preserve_gp_registers) { - __ restore_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers, preserve_R3); - } - } - __ mr_if_needed(dst, result); - - __ bind(skip_barrier); - __ block_comment("} load_at (zgc)"); -} - -#ifdef ASSERT -// The Z store barrier only verifies the pointers it is operating on and is thus a sole debugging measure. -void XBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register base, RegisterOrConstant ind_or_offs, Register val, - Register tmp1, Register tmp2, Register tmp3, - MacroAssembler::PreservationLevel preservation_level) { - __ block_comment("store_at (zgc) {"); - - // If the 'val' register is 'noreg', the to-be-stored value is a null pointer. - if (is_reference_type(type) && val != noreg) { - __ ld(tmp1, in_bytes(XThreadLocalData::address_bad_mask_offset()), R16_thread); - __ and_(tmp1, tmp1, val); - __ asm_assert_eq("Detected dirty pointer on the heap in Z store barrier"); - } - - // Store value - BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, preservation_level); - - __ block_comment("} store_at (zgc)"); -} -#endif // ASSERT - -void XBarrierSetAssembler::arraycopy_prologue(MacroAssembler *masm, DecoratorSet decorators, BasicType component_type, - Register src, Register dst, Register count, - Register preserve1, Register preserve2) { - __ block_comment("arraycopy_prologue (zgc) {"); - - /* ==== Check whether a special gc barrier is required for this particular load ==== */ - if (!is_reference_type(component_type)) { - return; - } - - Label skip_barrier; - - // Fast path: Array is of length zero - __ cmpdi(CCR0, count, 0); - __ beq(CCR0, skip_barrier); - - /* ==== Ensure register sanity ==== */ - Register tmp_R11 = R11_scratch1; - - assert_different_registers(src, dst, count, tmp_R11, noreg); - if (preserve1 != noreg) { - // Not technically required, but unlikely being intended. - assert_different_registers(preserve1, preserve2); - } - - /* ==== Invoke barrier (slowpath) ==== */ - int nbytes_save = 0; - - { - assert(!noreg->is_volatile(), "sanity"); - - if (preserve1->is_volatile()) { - __ std(preserve1, -BytesPerWord * ++nbytes_save, R1_SP); - } - - if (preserve2->is_volatile() && preserve1 != preserve2) { - __ std(preserve2, -BytesPerWord * ++nbytes_save, R1_SP); - } - - __ std(src, -BytesPerWord * ++nbytes_save, R1_SP); - __ std(dst, -BytesPerWord * ++nbytes_save, R1_SP); - __ std(count, -BytesPerWord * ++nbytes_save, R1_SP); - - __ save_LR(tmp_R11); - __ push_frame_reg_args(nbytes_save, tmp_R11); - } - - // XBarrierSetRuntime::load_barrier_on_oop_array_addr(src, count) - if (count == R3_ARG1) { - if (src == R4_ARG2) { - // Arguments are provided in reverse order - __ mr(tmp_R11, count); - __ mr(R3_ARG1, src); - __ mr(R4_ARG2, tmp_R11); - } else { - __ mr(R4_ARG2, count); - __ mr(R3_ARG1, src); - } - } else { - __ mr_if_needed(R3_ARG1, src); - __ mr_if_needed(R4_ARG2, count); - } - - __ call_VM_leaf(XBarrierSetRuntime::load_barrier_on_oop_array_addr()); - - __ pop_frame(); - __ restore_LR(tmp_R11); - - { - __ ld(count, -BytesPerWord * nbytes_save--, R1_SP); - __ ld(dst, -BytesPerWord * nbytes_save--, R1_SP); - __ ld(src, -BytesPerWord * nbytes_save--, R1_SP); - - if (preserve2->is_volatile() && preserve1 != preserve2) { - __ ld(preserve2, -BytesPerWord * nbytes_save--, R1_SP); - } - - if (preserve1->is_volatile()) { - __ ld(preserve1, -BytesPerWord * nbytes_save--, R1_SP); - } - } - - __ bind(skip_barrier); - - __ block_comment("} arraycopy_prologue (zgc)"); -} - -void XBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env, - Register obj, Register tmp, Label& slowpath) { - __ block_comment("try_resolve_jobject_in_native (zgc) {"); - - assert_different_registers(jni_env, obj, tmp); - - // Resolve the pointer using the standard implementation for weak tag handling and pointer verification. - BarrierSetAssembler::try_resolve_jobject_in_native(masm, dst, jni_env, obj, tmp, slowpath); - - // Check whether pointer is dirty. - __ ld(tmp, - in_bytes(XThreadLocalData::address_bad_mask_offset() - JavaThread::jni_environment_offset()), - jni_env); - - __ and_(tmp, obj, tmp); - __ bne(CCR0, slowpath); - - __ block_comment("} try_resolve_jobject_in_native (zgc)"); -} - -#undef __ - -#ifdef COMPILER1 -#define __ ce->masm()-> - -// Code emitted by LIR node "LIR_OpXLoadBarrierTest" which in turn is emitted by XBarrierSetC1::load_barrier. -// The actual compare and branch instructions are represented as stand-alone LIR nodes. -void XBarrierSetAssembler::generate_c1_load_barrier_test(LIR_Assembler* ce, - LIR_Opr ref) const { - __ block_comment("load_barrier_test (zgc) {"); - - __ ld(R0, in_bytes(XThreadLocalData::address_bad_mask_offset()), R16_thread); - __ andr(R0, R0, ref->as_pointer_register()); - __ cmpdi(CCR5 /* as mandated by LIR node */, R0, 0); - - __ block_comment("} load_barrier_test (zgc)"); -} - -// Code emitted by code stub "XLoadBarrierStubC1" which in turn is emitted by XBarrierSetC1::load_barrier. -// Invokes the runtime stub which is defined just below. -void XBarrierSetAssembler::generate_c1_load_barrier_stub(LIR_Assembler* ce, - XLoadBarrierStubC1* stub) const { - __ block_comment("c1_load_barrier_stub (zgc) {"); - - __ bind(*stub->entry()); - - /* ==== Determine relevant data registers and ensure register sanity ==== */ - Register ref = stub->ref()->as_register(); - Register ref_addr = noreg; - - // Determine reference address - if (stub->tmp()->is_valid()) { - // 'tmp' register is given, so address might have an index or a displacement. - ce->leal(stub->ref_addr(), stub->tmp()); - ref_addr = stub->tmp()->as_pointer_register(); - } else { - // 'tmp' register is not given, so address must have neither an index nor a displacement. - // The address' base register is thus usable as-is. - assert(stub->ref_addr()->as_address_ptr()->disp() == 0, "illegal displacement"); - assert(!stub->ref_addr()->as_address_ptr()->index()->is_valid(), "illegal index"); - - ref_addr = stub->ref_addr()->as_address_ptr()->base()->as_pointer_register(); - } - - assert_different_registers(ref, ref_addr, R0, noreg); - - /* ==== Invoke stub ==== */ - // Pass arguments via stack. The stack pointer will be bumped by the stub. - __ std(ref, (intptr_t) -1 * BytesPerWord, R1_SP); - __ std(ref_addr, (intptr_t) -2 * BytesPerWord, R1_SP); - - __ load_const_optimized(R0, stub->runtime_stub()); - __ call_stub(R0); - - // The runtime stub passes the result via the R0 register, overriding the previously-loaded stub address. - __ mr_if_needed(ref, R0); - __ b(*stub->continuation()); - - __ block_comment("} c1_load_barrier_stub (zgc)"); -} - -#undef __ -#define __ sasm-> - -// Code emitted by runtime code stub which in turn is emitted by XBarrierSetC1::generate_c1_runtime_stubs. -void XBarrierSetAssembler::generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, - DecoratorSet decorators) const { - __ block_comment("c1_load_barrier_runtime_stub (zgc) {"); - - const int stack_parameters = 2; - const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_parameters) * BytesPerWord; - - __ save_volatile_gprs(R1_SP, -nbytes_save); - __ save_LR(R0); - - // Load arguments back again from the stack. - __ ld(R3_ARG1, (intptr_t) -1 * BytesPerWord, R1_SP); // ref - __ ld(R4_ARG2, (intptr_t) -2 * BytesPerWord, R1_SP); // ref_addr - - __ push_frame_reg_args(nbytes_save, R0); - - __ call_VM_leaf(XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators)); - - __ verify_oop(R3_RET, "Bad pointer after barrier invocation"); - __ mr(R0, R3_RET); - - __ pop_frame(); - __ restore_LR(R3_RET); - __ restore_volatile_gprs(R1_SP, -nbytes_save); - - __ blr(); - - __ block_comment("} c1_load_barrier_runtime_stub (zgc)"); -} - -#undef __ -#endif // COMPILER1 - -#ifdef COMPILER2 - -OptoReg::Name XBarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) const { - if (!OptoReg::is_reg(opto_reg)) { - return OptoReg::Bad; - } - - VMReg vm_reg = OptoReg::as_VMReg(opto_reg); - if ((vm_reg->is_Register() || vm_reg ->is_FloatRegister()) && (opto_reg & 1) != 0) { - return OptoReg::Bad; - } - - return opto_reg; -} - -#define __ _masm-> - -class XSaveLiveRegisters { - MacroAssembler* _masm; - RegMask _reg_mask; - Register _result_reg; - int _frame_size; - - public: - XSaveLiveRegisters(MacroAssembler *masm, XLoadBarrierStubC2 *stub) - : _masm(masm), _reg_mask(stub->live()), _result_reg(stub->ref()) { - - const int register_save_size = iterate_over_register_mask(ACTION_COUNT_ONLY) * BytesPerWord; - _frame_size = align_up(register_save_size, frame::alignment_in_bytes) - + frame::native_abi_reg_args_size; - - __ save_LR_CR(R0); - __ push_frame(_frame_size, R0); - - iterate_over_register_mask(ACTION_SAVE, _frame_size); - } - - ~XSaveLiveRegisters() { - iterate_over_register_mask(ACTION_RESTORE, _frame_size); - - __ addi(R1_SP, R1_SP, _frame_size); - __ restore_LR_CR(R0); - } - - private: - enum IterationAction : int { - ACTION_SAVE, - ACTION_RESTORE, - ACTION_COUNT_ONLY - }; - - int iterate_over_register_mask(IterationAction action, int offset = 0) { - int reg_save_index = 0; - RegMaskIterator live_regs_iterator(_reg_mask); - - while(live_regs_iterator.has_next()) { - const OptoReg::Name opto_reg = live_regs_iterator.next(); - - // Filter out stack slots (spilled registers, i.e., stack-allocated registers). - if (!OptoReg::is_reg(opto_reg)) { - continue; - } - - const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); - if (vm_reg->is_Register()) { - Register std_reg = vm_reg->as_Register(); - - // '_result_reg' will hold the end result of the operation. Its content must thus not be preserved. - if (std_reg == _result_reg) { - continue; - } - - if (std_reg->encoding() >= R2->encoding() && std_reg->encoding() <= R12->encoding()) { - reg_save_index++; - - if (action == ACTION_SAVE) { - _masm->std(std_reg, offset - reg_save_index * BytesPerWord, R1_SP); - } else if (action == ACTION_RESTORE) { - _masm->ld(std_reg, offset - reg_save_index * BytesPerWord, R1_SP); - } else { - assert(action == ACTION_COUNT_ONLY, "Sanity"); - } - } - } else if (vm_reg->is_FloatRegister()) { - FloatRegister fp_reg = vm_reg->as_FloatRegister(); - if (fp_reg->encoding() >= F0->encoding() && fp_reg->encoding() <= F13->encoding()) { - reg_save_index++; - - if (action == ACTION_SAVE) { - _masm->stfd(fp_reg, offset - reg_save_index * BytesPerWord, R1_SP); - } else if (action == ACTION_RESTORE) { - _masm->lfd(fp_reg, offset - reg_save_index * BytesPerWord, R1_SP); - } else { - assert(action == ACTION_COUNT_ONLY, "Sanity"); - } - } - } else if (vm_reg->is_ConditionRegister()) { - // NOP. Conditions registers are covered by save_LR_CR - } else if (vm_reg->is_VectorSRegister()) { - assert(SuperwordUseVSX, "or should not reach here"); - VectorSRegister vs_reg = vm_reg->as_VectorSRegister(); - if (vs_reg->encoding() >= VSR32->encoding() && vs_reg->encoding() <= VSR51->encoding()) { - reg_save_index += 2; - - Register spill_addr = R0; - if (action == ACTION_SAVE) { - _masm->addi(spill_addr, R1_SP, offset - reg_save_index * BytesPerWord); - _masm->stxvd2x(vs_reg, spill_addr); - } else if (action == ACTION_RESTORE) { - _masm->addi(spill_addr, R1_SP, offset - reg_save_index * BytesPerWord); - _masm->lxvd2x(vs_reg, spill_addr); - } else { - assert(action == ACTION_COUNT_ONLY, "Sanity"); - } - } - } else { - if (vm_reg->is_SpecialRegister()) { - fatal("Special registers are unsupported. Found register %s", vm_reg->name()); - } else { - fatal("Register type is not known"); - } - } - } - - return reg_save_index; - } -}; - -#undef __ -#define __ _masm-> - -class XSetupArguments { - MacroAssembler* const _masm; - const Register _ref; - const Address _ref_addr; - - public: - XSetupArguments(MacroAssembler* masm, XLoadBarrierStubC2* stub) : - _masm(masm), - _ref(stub->ref()), - _ref_addr(stub->ref_addr()) { - - // Desired register/argument configuration: - // _ref: R3_ARG1 - // _ref_addr: R4_ARG2 - - // '_ref_addr' can be unspecified. In that case, the barrier will not heal the reference. - if (_ref_addr.base() == noreg) { - assert_different_registers(_ref, R0, noreg); - - __ mr_if_needed(R3_ARG1, _ref); - __ li(R4_ARG2, 0); - } else { - assert_different_registers(_ref, _ref_addr.base(), R0, noreg); - assert(!_ref_addr.index()->is_valid(), "reference addresses must not contain an index component"); - - if (_ref != R4_ARG2) { - // Calculate address first as the address' base register might clash with R4_ARG2 - __ addi(R4_ARG2, _ref_addr.base(), _ref_addr.disp()); - __ mr_if_needed(R3_ARG1, _ref); - } else if (_ref_addr.base() != R3_ARG1) { - __ mr(R3_ARG1, _ref); - __ addi(R4_ARG2, _ref_addr.base(), _ref_addr.disp()); // Clobbering _ref - } else { - // Arguments are provided in inverse order (i.e. _ref == R4_ARG2, _ref_addr == R3_ARG1) - __ mr(R0, _ref); - __ addi(R4_ARG2, _ref_addr.base(), _ref_addr.disp()); - __ mr(R3_ARG1, R0); - } - } - } -}; - -#undef __ -#define __ masm-> - -void XBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, XLoadBarrierStubC2* stub) const { - __ block_comment("generate_c2_load_barrier_stub (zgc) {"); - - __ bind(*stub->entry()); - - Register ref = stub->ref(); - Address ref_addr = stub->ref_addr(); - - assert_different_registers(ref, ref_addr.base()); - - { - XSaveLiveRegisters save_live_registers(masm, stub); - XSetupArguments setup_arguments(masm, stub); - - __ call_VM_leaf(stub->slow_path()); - __ mr_if_needed(ref, R3_RET); - } - - __ b(*stub->continuation()); - - __ block_comment("} generate_c2_load_barrier_stub (zgc)"); -} - -#undef __ -#endif // COMPILER2 diff --git a/src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.hpp deleted file mode 100644 index 8dfd4524dfe5a..0000000000000 --- a/src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2021, 2022, 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. - * - * This code is free software; you can redistribute 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 CPU_PPC_GC_X_XBARRIERSETASSEMBLER_PPC_HPP -#define CPU_PPC_GC_X_XBARRIERSETASSEMBLER_PPC_HPP - -#include "code/vmreg.hpp" -#include "oops/accessDecorators.hpp" -#ifdef COMPILER2 -#include "opto/optoreg.hpp" -#endif // COMPILER2 - -#ifdef COMPILER1 -class LIR_Assembler; -class LIR_Opr; -class StubAssembler; -#endif // COMPILER1 - -#ifdef COMPILER2 -class Node; -#endif // COMPILER2 - -#ifdef COMPILER1 -class XLoadBarrierStubC1; -#endif // COMPILER1 - -#ifdef COMPILER2 -class XLoadBarrierStubC2; -#endif // COMPILER2 - -class XBarrierSetAssembler : public XBarrierSetAssemblerBase { -public: - virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register base, RegisterOrConstant ind_or_offs, Register dst, - Register tmp1, Register tmp2, - MacroAssembler::PreservationLevel preservation_level, Label *L_handle_null = nullptr); - -#ifdef ASSERT - virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register base, RegisterOrConstant ind_or_offs, Register val, - Register tmp1, Register tmp2, Register tmp3, - MacroAssembler::PreservationLevel preservation_level); -#endif // ASSERT - - virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register src, Register dst, Register count, - Register preserve1, Register preserve2); - - virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env, - Register obj, Register tmp, Label& slowpath); - - virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; } - -#ifdef COMPILER1 - void generate_c1_load_barrier_test(LIR_Assembler* ce, - LIR_Opr ref) const; - - void generate_c1_load_barrier_stub(LIR_Assembler* ce, - XLoadBarrierStubC1* stub) const; - - void generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, - DecoratorSet decorators) const; -#endif // COMPILER1 - -#ifdef COMPILER2 - OptoReg::Name refine_register(const Node* node, OptoReg::Name opto_reg) const; - - void generate_c2_load_barrier_stub(MacroAssembler* masm, XLoadBarrierStubC2* stub) const; -#endif // COMPILER2 -}; - -#endif // CPU_PPC_GC_X_XBARRIERSETASSEMBLER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.cpp b/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.cpp deleted file mode 100644 index 3218a765fc703..0000000000000 --- a/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021 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. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xGlobals.hpp" -#include "runtime/globals.hpp" -#include "runtime/os.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/powerOfTwo.hpp" -#include - -#ifdef LINUX -#include -#endif // LINUX - -// -// The overall memory layouts across different power platforms are similar and only differ with regards to -// the position of the highest addressable bit; the position of the metadata bits and the size of the actual -// addressable heap address space are adjusted accordingly. -// -// The following memory schema shows an exemplary layout in which bit '45' is the highest addressable bit. -// It is assumed that this virtual memory address space layout is predominant on the power platform. -// -// Standard Address Space & Pointer Layout -// --------------------------------------- -// -// +--------------------------------+ 0x00007FFFFFFFFFFF (127 TiB - 1) -// . . -// . . -// . . -// +--------------------------------+ 0x0000140000000000 (20 TiB) -// | Remapped View | -// +--------------------------------+ 0x0000100000000000 (16 TiB) -// . . -// +--------------------------------+ 0x00000c0000000000 (12 TiB) -// | Marked1 View | -// +--------------------------------+ 0x0000080000000000 (8 TiB) -// | Marked0 View | -// +--------------------------------+ 0x0000040000000000 (4 TiB) -// . . -// +--------------------------------+ 0x0000000000000000 -// -// 6 4 4 4 4 -// 3 6 5 2 1 0 -// +--------------------+----+-----------------------------------------------+ -// |00000000 00000000 00|1111|11 11111111 11111111 11111111 11111111 11111111| -// +--------------------+----+-----------------------------------------------+ -// | | | -// | | * 41-0 Object Offset (42-bits, 4TB address space) -// | | -// | * 45-42 Metadata Bits (4-bits) 0001 = Marked0 (Address view 4-8TB) -// | 0010 = Marked1 (Address view 8-12TB) -// | 0100 = Remapped (Address view 16-20TB) -// | 1000 = Finalizable (Address view N/A) -// | -// * 63-46 Fixed (18-bits, always zero) -// - -// Maximum value as per spec (Power ISA v2.07): 2 ^ 60 bytes, i.e. 1 EiB (exbibyte) -static const unsigned int MAXIMUM_MAX_ADDRESS_BIT = 60; - -// Most modern power processors provide an address space with not more than 45 bit addressable bit, -// that is an address space of 32 TiB in size. -static const unsigned int DEFAULT_MAX_ADDRESS_BIT = 45; - -// Minimum value returned, if probing fails: 64 GiB -static const unsigned int MINIMUM_MAX_ADDRESS_BIT = 36; - -// Determines the highest addressable bit of the virtual address space (depends on platform) -// by trying to interact with memory in that address range, -// i.e. by syncing existing mappings (msync) or by temporarily mapping the memory area (mmap). -// If one of those operations succeeds, it is proven that the targeted memory area is within the virtual address space. -// -// To reduce the number of required system calls to a bare minimum, the DEFAULT_MAX_ADDRESS_BIT is intentionally set -// lower than what the ABI would theoretically permit. -// Such an avoidance strategy, however, might impose unnecessary limits on processors that exceed this limit. -// If DEFAULT_MAX_ADDRESS_BIT is addressable, the next higher bit will be tested as well to ensure that -// the made assumption does not artificially restrict the memory availability. -static unsigned int probe_valid_max_address_bit(size_t init_bit, size_t min_bit) { - assert(init_bit >= min_bit, "Sanity"); - assert(init_bit <= MAXIMUM_MAX_ADDRESS_BIT, "Test bit is outside the assumed address space range"); - -#ifdef LINUX - unsigned int max_valid_address_bit = 0; - void* last_allocatable_address = nullptr; - - const size_t page_size = os::vm_page_size(); - - for (size_t i = init_bit; i >= min_bit; --i) { - void* base_addr = (void*) (((unsigned long) 1U) << i); - - /* ==== Try msync-ing already mapped memory page ==== */ - if (msync(base_addr, page_size, MS_ASYNC) == 0) { - // The page of the given address was synced by the linux kernel and must thus be both, mapped and valid. - max_valid_address_bit = i; - break; - } - if (errno != ENOMEM) { - // An unexpected error occurred, i.e. an error not indicating that the targeted memory page is unmapped, - // but pointing out another type of issue. - // Even though this should never happen, those issues may come up due to undefined behavior. -#ifdef ASSERT - fatal("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno)); -#else // ASSERT - log_warning_p(gc)("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno)); -#endif // ASSERT - continue; - } - - /* ==== Try mapping memory page on our own ==== */ - last_allocatable_address = mmap(base_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); - if (last_allocatable_address != MAP_FAILED) { - munmap(last_allocatable_address, page_size); - } - - if (last_allocatable_address == base_addr) { - // As the linux kernel mapped exactly the page we have requested, the address must be valid. - max_valid_address_bit = i; - break; - } - - log_info_p(gc, init)("Probe failed for bit '%zu'", i); - } - - if (max_valid_address_bit == 0) { - // Probing did not bring up any usable address bit. - // As an alternative, the VM evaluates the address returned by mmap as it is expected that the reserved page - // will be close to the probed address that was out-of-range. - // As per mmap(2), "the kernel [will take] [the address] as a hint about where to - // place the mapping; on Linux, the mapping will be created at a nearby page boundary". - // It should thus be a "close enough" approximation to the real virtual memory address space limit. - // - // This recovery strategy is only applied in production builds. - // In debug builds, an assertion in 'XPlatformAddressOffsetBits' will bail out the VM to indicate that - // the assumed address space is no longer up-to-date. - if (last_allocatable_address != MAP_FAILED) { - const unsigned int bitpos = BitsPerSize_t - count_leading_zeros((size_t) last_allocatable_address) - 1; - log_info_p(gc, init)("Did not find any valid addresses within the range, using address '%u' instead", bitpos); - return bitpos; - } - -#ifdef ASSERT - fatal("Available address space can not be determined"); -#else // ASSERT - log_warning_p(gc)("Cannot determine available address space. Falling back to default value."); - return DEFAULT_MAX_ADDRESS_BIT; -#endif // ASSERT - } else { - if (max_valid_address_bit == init_bit) { - // An usable address bit has been found immediately. - // To ensure that the entire virtual address space is exploited, the next highest bit will be tested as well. - log_info_p(gc, init)("Hit valid address '%u' on first try, retrying with next higher bit", max_valid_address_bit); - return MAX2(max_valid_address_bit, probe_valid_max_address_bit(init_bit + 1, init_bit + 1)); - } - } - - log_info_p(gc, init)("Found valid address '%u'", max_valid_address_bit); - return max_valid_address_bit; -#else // LINUX - return DEFAULT_MAX_ADDRESS_BIT; -#endif // LINUX -} - -size_t XPlatformAddressOffsetBits() { - const static unsigned int valid_max_address_offset_bits = - probe_valid_max_address_bit(DEFAULT_MAX_ADDRESS_BIT, MINIMUM_MAX_ADDRESS_BIT) + 1; - assert(valid_max_address_offset_bits >= MINIMUM_MAX_ADDRESS_BIT, - "Highest addressable bit is outside the assumed address space range"); - - const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; - const size_t min_address_offset_bits = max_address_offset_bits - 2; - const size_t address_offset = round_up_power_of_2(MaxHeapSize * XVirtualToPhysicalRatio); - const size_t address_offset_bits = log2i_exact(address_offset); - - return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); -} - -size_t XPlatformAddressMetadataShift() { - return XPlatformAddressOffsetBits(); -} diff --git a/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.hpp b/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.hpp deleted file mode 100644 index be88b05b02a82..0000000000000 --- a/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021 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 CPU_PPC_GC_X_XGLOBALS_PPC_HPP -#define CPU_PPC_GC_X_XGLOBALS_PPC_HPP - -#include "globalDefinitions_ppc.hpp" - -const size_t XPlatformHeapViews = 3; -const size_t XPlatformCacheLineSize = DEFAULT_CACHE_LINE_SIZE; - -size_t XPlatformAddressOffsetBits(); -size_t XPlatformAddressMetadataShift(); - -#endif // CPU_PPC_GC_X_XGLOBALS_PPC_HPP diff --git a/src/hotspot/cpu/ppc/gc/x/x_ppc.ad b/src/hotspot/cpu/ppc/gc/x/x_ppc.ad deleted file mode 100644 index b206b6593fb45..0000000000000 --- a/src/hotspot/cpu/ppc/gc/x/x_ppc.ad +++ /dev/null @@ -1,298 +0,0 @@ -// -// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2021 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. -// - -source_hpp %{ - -#include "gc/shared/gc_globals.hpp" -#include "gc/x/c2/xBarrierSetC2.hpp" -#include "gc/x/xThreadLocalData.hpp" - -%} - -source %{ - -static void x_load_barrier(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref, - Register tmp, uint8_t barrier_data) { - if (barrier_data == XLoadBarrierElided) { - return; - } - - XLoadBarrierStubC2* const stub = XLoadBarrierStubC2::create(node, ref_addr, ref, tmp, barrier_data); - __ ld(tmp, in_bytes(XThreadLocalData::address_bad_mask_offset()), R16_thread); - __ and_(tmp, tmp, ref); - __ bne_far(CCR0, *stub->entry(), MacroAssembler::bc_far_optimize_on_relocate); - __ bind(*stub->continuation()); -} - -static void x_load_barrier_slow_path(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref, - Register tmp) { - XLoadBarrierStubC2* const stub = XLoadBarrierStubC2::create(node, ref_addr, ref, tmp, XLoadBarrierStrong); - __ b(*stub->entry()); - __ bind(*stub->continuation()); -} - -static void x_compare_and_swap(MacroAssembler* masm, const MachNode* node, - Register res, Register mem, Register oldval, Register newval, - Register tmp_xchg, Register tmp_mask, - bool weak, bool acquire) { - // z-specific load barrier requires strong CAS operations. - // Weak CAS operations are thus only emitted if the barrier is elided. - __ cmpxchgd(CCR0, tmp_xchg, oldval, newval, mem, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), res, nullptr, true, - weak && node->barrier_data() == XLoadBarrierElided); - - if (node->barrier_data() != XLoadBarrierElided) { - Label skip_barrier; - - __ ld(tmp_mask, in_bytes(XThreadLocalData::address_bad_mask_offset()), R16_thread); - __ and_(tmp_mask, tmp_mask, tmp_xchg); - __ beq(CCR0, skip_barrier); - - // CAS must have failed because pointer in memory is bad. - x_load_barrier_slow_path(masm, node, Address(mem), tmp_xchg, res /* used as tmp */); - - __ cmpxchgd(CCR0, tmp_xchg, oldval, newval, mem, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), res, nullptr, true, weak); - - __ bind(skip_barrier); - } - - if (acquire) { - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - // Uses the isync instruction as an acquire barrier. - // This exploits the compare and the branch in the z load barrier (load, compare and branch, isync). - __ isync(); - } else { - __ sync(); - } - } -} - -static void x_compare_and_exchange(MacroAssembler* masm, const MachNode* node, - Register res, Register mem, Register oldval, Register newval, Register tmp, - bool weak, bool acquire) { - // z-specific load barrier requires strong CAS operations. - // Weak CAS operations are thus only emitted if the barrier is elided. - __ cmpxchgd(CCR0, res, oldval, newval, mem, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, nullptr, true, - weak && node->barrier_data() == XLoadBarrierElided); - - if (node->barrier_data() != XLoadBarrierElided) { - Label skip_barrier; - __ ld(tmp, in_bytes(XThreadLocalData::address_bad_mask_offset()), R16_thread); - __ and_(tmp, tmp, res); - __ beq(CCR0, skip_barrier); - - x_load_barrier_slow_path(masm, node, Address(mem), res, tmp); - - __ cmpxchgd(CCR0, res, oldval, newval, mem, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, nullptr, true, weak); - - __ bind(skip_barrier); - } - - if (acquire) { - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - // Uses the isync instruction as an acquire barrier. - // This exploits the compare and the branch in the z load barrier (load, compare and branch, isync). - __ isync(); - } else { - __ sync(); - } - } -} - -%} - -instruct xLoadP(iRegPdst dst, memoryAlg4 mem, iRegPdst tmp, flagsRegCR0 cr0) -%{ - match(Set dst (LoadP mem)); - effect(TEMP_DEF dst, TEMP tmp, KILL cr0); - ins_cost(MEMORY_REF_COST); - - predicate((UseZGC && !ZGenerational && n->as_Load()->barrier_data() != 0) - && (n->as_Load()->is_unordered() || followed_by_acquire(n))); - - format %{ "LD $dst, $mem" %} - ins_encode %{ - assert($mem$$index == 0, "sanity"); - __ ld($dst$$Register, $mem$$disp, $mem$$base$$Register); - x_load_barrier(masm, this, Address($mem$$base$$Register, $mem$$disp), $dst$$Register, $tmp$$Register, barrier_data()); - %} - ins_pipe(pipe_class_default); -%} - -// Load Pointer Volatile -instruct xLoadP_acq(iRegPdst dst, memoryAlg4 mem, iRegPdst tmp, flagsRegCR0 cr0) -%{ - match(Set dst (LoadP mem)); - effect(TEMP_DEF dst, TEMP tmp, KILL cr0); - ins_cost(3 * MEMORY_REF_COST); - - // Predicate on instruction order is implicitly present due to the predicate of the cheaper zLoadP operation - predicate(UseZGC && !ZGenerational && n->as_Load()->barrier_data() != 0); - - format %{ "LD acq $dst, $mem" %} - ins_encode %{ - __ ld($dst$$Register, $mem$$disp, $mem$$base$$Register); - x_load_barrier(masm, this, Address($mem$$base$$Register, $mem$$disp), $dst$$Register, $tmp$$Register, barrier_data()); - - // Uses the isync instruction as an acquire barrier. - // This exploits the compare and the branch in the z load barrier (load, compare and branch, isync). - __ isync(); - %} - ins_pipe(pipe_class_default); -%} - -instruct xCompareAndSwapP(iRegIdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, - iRegPdst tmp_xchg, iRegPdst tmp_mask, flagsRegCR0 cr0) %{ - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - effect(TEMP_DEF res, TEMP tmp_xchg, TEMP tmp_mask, KILL cr0); - - predicate((UseZGC && !ZGenerational && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong) - && (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*) n)->order() != MemNode::seqcst)); - - format %{ "CMPXCHG $res, $mem, $oldval, $newval; as bool; ptr" %} - ins_encode %{ - x_compare_and_swap(masm, this, - $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, - $tmp_xchg$$Register, $tmp_mask$$Register, - false /* weak */, false /* acquire */); - %} - ins_pipe(pipe_class_default); -%} - -instruct xCompareAndSwapP_acq(iRegIdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, - iRegPdst tmp_xchg, iRegPdst tmp_mask, flagsRegCR0 cr0) %{ - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - effect(TEMP_DEF res, TEMP tmp_xchg, TEMP tmp_mask, KILL cr0); - - predicate((UseZGC && !ZGenerational && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong) - && (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*) n)->order() == MemNode::seqcst)); - - format %{ "CMPXCHG acq $res, $mem, $oldval, $newval; as bool; ptr" %} - ins_encode %{ - x_compare_and_swap(masm, this, - $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, - $tmp_xchg$$Register, $tmp_mask$$Register, - false /* weak */, true /* acquire */); - %} - ins_pipe(pipe_class_default); -%} - -instruct xCompareAndSwapPWeak(iRegIdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, - iRegPdst tmp_xchg, iRegPdst tmp_mask, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - effect(TEMP_DEF res, TEMP tmp_xchg, TEMP tmp_mask, KILL cr0); - - predicate((UseZGC && !ZGenerational && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong) - && ((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*) n)->order() != MemNode::seqcst); - - format %{ "weak CMPXCHG $res, $mem, $oldval, $newval; as bool; ptr" %} - ins_encode %{ - x_compare_and_swap(masm, this, - $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, - $tmp_xchg$$Register, $tmp_mask$$Register, - true /* weak */, false /* acquire */); - %} - ins_pipe(pipe_class_default); -%} - -instruct xCompareAndSwapPWeak_acq(iRegIdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, - iRegPdst tmp_xchg, iRegPdst tmp_mask, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - effect(TEMP_DEF res, TEMP tmp_xchg, TEMP tmp_mask, KILL cr0); - - predicate((UseZGC && !ZGenerational && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong) - && (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*) n)->order() == MemNode::seqcst)); - - format %{ "weak CMPXCHG acq $res, $mem, $oldval, $newval; as bool; ptr" %} - ins_encode %{ - x_compare_and_swap(masm, this, - $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, - $tmp_xchg$$Register, $tmp_mask$$Register, - true /* weak */, true /* acquire */); - %} - ins_pipe(pipe_class_default); -%} - -instruct xCompareAndExchangeP(iRegPdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, - iRegPdst tmp, flagsRegCR0 cr0) %{ - match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - effect(TEMP_DEF res, TEMP tmp, KILL cr0); - - predicate((UseZGC && !ZGenerational && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong) - && ( - ((CompareAndSwapNode*)n)->order() != MemNode::acquire - && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst - )); - - format %{ "CMPXCHG $res, $mem, $oldval, $newval; as ptr; ptr" %} - ins_encode %{ - x_compare_and_exchange(masm, this, - $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, $tmp$$Register, - false /* weak */, false /* acquire */); - %} - ins_pipe(pipe_class_default); -%} - -instruct xCompareAndExchangeP_acq(iRegPdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, - iRegPdst tmp, flagsRegCR0 cr0) %{ - match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - effect(TEMP_DEF res, TEMP tmp, KILL cr0); - - predicate((UseZGC && !ZGenerational && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong) - && ( - ((CompareAndSwapNode*)n)->order() == MemNode::acquire - || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst - )); - - format %{ "CMPXCHG acq $res, $mem, $oldval, $newval; as ptr; ptr" %} - ins_encode %{ - x_compare_and_exchange(masm, this, - $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, $tmp$$Register, - false /* weak */, true /* acquire */); - %} - ins_pipe(pipe_class_default); -%} - -instruct xGetAndSetP(iRegPdst res, iRegPdst mem, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0) %{ - match(Set res (GetAndSetP mem newval)); - effect(TEMP_DEF res, TEMP tmp, KILL cr0); - - predicate(UseZGC && !ZGenerational && n->as_LoadStore()->barrier_data() != 0); - - format %{ "GetAndSetP $res, $mem, $newval" %} - ins_encode %{ - __ getandsetd($res$$Register, $newval$$Register, $mem$$Register, MacroAssembler::cmpxchgx_hint_atomic_update()); - x_load_barrier(masm, this, Address(noreg, (intptr_t) 0), $res$$Register, $tmp$$Register, barrier_data()); - - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ isync(); - } else { - __ sync(); - } - %} - ins_pipe(pipe_class_default); -%} diff --git a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp index 89ab1b1edeeb4..b9ea67dabe3d6 100644 --- a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp @@ -610,14 +610,14 @@ void ZBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, R // Resolve global handle __ ld(dst, 0, dst); - __ ld(tmp, load_bad_mask.disp(), load_bad_mask.base()); + __ ld(tmp, load_bad_mask); __ b(check_color); __ bind(weak_tagged); // Resolve weak handle __ ld(dst, 0, dst); - __ ld(tmp, mark_bad_mask.disp(), mark_bad_mask.base()); + __ ld(tmp, mark_bad_mask); __ bind(check_color); __ and_(tmp, tmp, dst); @@ -943,6 +943,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, __ call_VM_leaf(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr(), R3_ARG1); } else if (stub->is_atomic()) { __ call_VM_leaf(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr(), R3_ARG1); + } else if (stub->is_nokeepalive()) { + __ call_VM_leaf(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr(), R3_ARG1); } else { __ call_VM_leaf(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr(), R3_ARG1); } diff --git a/src/hotspot/cpu/ppc/gc/z/z_ppc.ad b/src/hotspot/cpu/ppc/gc/z/z_ppc.ad index 017574d40ff8b..97b49bc1b026e 100644 --- a/src/hotspot/cpu/ppc/gc/z/z_ppc.ad +++ b/src/hotspot/cpu/ppc/gc/z/z_ppc.ad @@ -83,7 +83,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Register z_color(masm, rnew_zpointer, rnew_zaddress); } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; - ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, Address(ref_base, disp), rnew_zaddress, rnew_zpointer, is_native, is_atomic); + bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0; + ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, Address(ref_base, disp), rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive); ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler(); bs_asm->store_barrier_fast(masm, ref_base, disp, rnew_zaddress, rnew_zpointer, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation()); } @@ -142,7 +143,7 @@ instruct zLoadP(iRegPdst dst, memoryAlg4 mem, flagsRegCR0 cr0) effect(TEMP_DEF dst, KILL cr0); ins_cost(MEMORY_REF_COST); - predicate((UseZGC && ZGenerational && n->as_Load()->barrier_data() != 0) + predicate((UseZGC && n->as_Load()->barrier_data() != 0) && (n->as_Load()->is_unordered() || followed_by_acquire(n))); format %{ "LD $dst, $mem" %} @@ -162,7 +163,7 @@ instruct zLoadP_acq(iRegPdst dst, memoryAlg4 mem, flagsRegCR0 cr0) ins_cost(3 * MEMORY_REF_COST); // Predicate on instruction order is implicitly present due to the predicate of the cheaper zLoadP operation - predicate(UseZGC && ZGenerational && n->as_Load()->barrier_data() != 0); + predicate(UseZGC && n->as_Load()->barrier_data() != 0); format %{ "LD acq $dst, $mem" %} ins_encode %{ @@ -180,7 +181,7 @@ instruct zLoadP_acq(iRegPdst dst, memoryAlg4 mem, flagsRegCR0 cr0) // Store Pointer instruct zStoreP(memoryAlg4 mem, iRegPsrc src, iRegPdst tmp, flagsRegCR0 cr0) %{ - predicate(UseZGC && ZGenerational && n->as_Store()->barrier_data() != 0); + predicate(UseZGC && n->as_Store()->barrier_data() != 0); match(Set mem (StoreP mem src)); effect(TEMP tmp, KILL cr0); ins_cost(2 * MEMORY_REF_COST); @@ -194,7 +195,7 @@ instruct zStoreP(memoryAlg4 mem, iRegPsrc src, iRegPdst tmp, flagsRegCR0 cr0) instruct zStorePNull(memoryAlg4 mem, immP_0 zero, iRegPdst tmp, flagsRegCR0 cr0) %{ - predicate(UseZGC && ZGenerational && n->as_Store()->barrier_data() != 0); + predicate(UseZGC && n->as_Store()->barrier_data() != 0); match(Set mem (StoreP mem zero)); effect(TEMP tmp, KILL cr0); ins_cost(MEMORY_REF_COST); @@ -212,7 +213,7 @@ instruct zCompareAndSwapP(iRegIdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); - predicate((UseZGC && ZGenerational && n->as_LoadStore()->barrier_data() != 0) + predicate((UseZGC && n->as_LoadStore()->barrier_data() != 0) && (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*) n)->order() != MemNode::seqcst)); format %{ "CMPXCHG $res, $mem, $oldval, $newval; as bool; ptr" %} @@ -231,7 +232,7 @@ instruct zCompareAndSwapP_acq(iRegIdst res, iRegPdst mem, iRegPsrc oldval, iRegP match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); - predicate((UseZGC && ZGenerational && n->as_LoadStore()->barrier_data() != 0) + predicate((UseZGC && n->as_LoadStore()->barrier_data() != 0) && (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*) n)->order() == MemNode::seqcst)); format %{ "CMPXCHG acq $res, $mem, $oldval, $newval; as bool; ptr" %} @@ -249,7 +250,7 @@ instruct zCompareAndExchangeP(iRegPdst res, iRegPdst mem, iRegPsrc oldval, iRegP match(Set res (CompareAndExchangeP mem (Binary oldval newval))); effect(TEMP_DEF res, TEMP tmp, KILL cr0); - predicate((UseZGC && ZGenerational && n->as_LoadStore()->barrier_data() != 0) + predicate((UseZGC && n->as_LoadStore()->barrier_data() != 0) && ( ((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst @@ -269,7 +270,7 @@ instruct zCompareAndExchangeP_acq(iRegPdst res, iRegPdst mem, iRegPsrc oldval, i match(Set res (CompareAndExchangeP mem (Binary oldval newval))); effect(TEMP_DEF res, TEMP tmp, KILL cr0); - predicate((UseZGC && ZGenerational && n->as_LoadStore()->barrier_data() != 0) + predicate((UseZGC && n->as_LoadStore()->barrier_data() != 0) && ( ((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst @@ -288,7 +289,7 @@ instruct zGetAndSetP(iRegPdst res, iRegPdst mem, iRegPsrc newval, iRegPdst tmp, match(Set res (GetAndSetP mem newval)); effect(TEMP_DEF res, TEMP tmp, KILL cr0); - predicate(UseZGC && ZGenerational && n->as_LoadStore()->barrier_data() != 0); + predicate(UseZGC && n->as_LoadStore()->barrier_data() != 0); format %{ "GetAndSetP $res, $mem, $newval" %} ins_encode %{ diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 8d8e39b8bbc00..c7adbfb52f068 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2410,7 +2410,7 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fast_path, Label* L_slow_path) { assert(L_fast_path != nullptr || L_slow_path != nullptr, "at least one is required"); - Label L_fallthrough; + Label L_check_thread, L_fallthrough; if (L_fast_path == nullptr) { L_fast_path = &L_fallthrough; } else if (L_slow_path == nullptr) { @@ -2419,10 +2419,14 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa // Fast path check: class is fully initialized lbz(R0, in_bytes(InstanceKlass::init_state_offset()), klass); + // acquire by cmp-branch-isync if fully_initialized cmpwi(CCR0, R0, InstanceKlass::fully_initialized); - beq(CCR0, *L_fast_path); + bne(CCR0, L_check_thread); + isync(); + b(*L_fast_path); // Fast path check: current thread is initializer thread + bind(L_check_thread); ld(R0, in_bytes(InstanceKlass::init_thread_offset()), klass); cmpd(CCR0, thread, R0); if (L_slow_path == &L_fallthrough) { @@ -2647,7 +2651,19 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register // flag == NE indicates failure bind(success); inc_held_monitor_count(temp); +#ifdef ASSERT + // Check that unlocked label is reached with flag == EQ. + Label flag_correct; + beq(flag, flag_correct); + stop("compiler_fast_lock_object: Flag != EQ"); +#endif bind(failure); +#ifdef ASSERT + // Check that slow_path label is reached with flag == NE. + bne(flag, flag_correct); + stop("compiler_fast_lock_object: Flag != NE"); + bind(flag_correct); +#endif } void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box, @@ -2697,17 +2713,12 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe bind(object_has_monitor); STATIC_ASSERT(markWord::monitor_value <= INT_MAX); addi(current_header, current_header, -(int)markWord::monitor_value); // monitor - ld(temp, in_bytes(ObjectMonitor::owner_offset()), current_header); - - // In case of LM_LIGHTWEIGHT, we may reach here with (temp & ObjectMonitor::ANONYMOUS_OWNER) != 0. - // This is handled like owner thread mismatches: We take the slow path. - cmpd(flag, temp, R16_thread); - bne(flag, failure); ld(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header); - addic_(displaced_header, displaced_header, -1); blt(CCR0, notRecursive); // Not recursive if negative after decrement. + + // Recursive unlock std(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header); if (flag == CCR0) { // Otherwise, flag is already EQ, here. crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); // Set CCR0 EQ @@ -2725,7 +2736,7 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe // StoreLoad achieves this. membar(StoreLoad); - // Check if the entry lists are empty. + // Check if the entry lists are empty (EntryList first - by convention). ld(temp, in_bytes(ObjectMonitor::EntryList_offset()), current_header); ld(displaced_header, in_bytes(ObjectMonitor::cxq_offset()), current_header); orr(temp, temp, displaced_header); // Will be 0 if both are 0. @@ -2735,20 +2746,32 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe // Check if there is a successor. ld(temp, in_bytes(ObjectMonitor::succ_offset()), current_header); cmpdi(flag, temp, 0); - bne(flag, success); // If so we are done. + // Invert equal bit + crnand(flag, Assembler::equal, flag, Assembler::equal); + beq(flag, success); // If there is a successor we are done. // Save the monitor pointer in the current thread, so we can try // to reacquire the lock in SharedRuntime::monitor_exit_helper(). std(current_header, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread); - - crxor(flag, Assembler::equal, flag, Assembler::equal); // Set flag = NE => slow path - b(failure); + b(failure); // flag == NE // flag == EQ indicates success, decrement held monitor count // flag == NE indicates failure bind(success); dec_held_monitor_count(temp); +#ifdef ASSERT + // Check that unlocked label is reached with flag == EQ. + Label flag_correct; + beq(flag, flag_correct); + stop("compiler_fast_unlock_object: Flag != EQ"); +#endif bind(failure); +#ifdef ASSERT + // Check that slow_path label is reached with flag == NE. + bne(flag, flag_correct); + stop("compiler_fast_unlock_object: Flag != NE"); + bind(flag_correct); +#endif } void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister flag, Register obj, Register box, @@ -3049,7 +3072,6 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f bind(not_recursive); - Label set_eq_unlocked; const Register t2 = tmp2; // Set owner to null. @@ -3061,7 +3083,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f // StoreLoad achieves this. membar(StoreLoad); - // Check if the entry lists are empty. + // Check if the entry lists are empty (EntryList first - by convention). ld(t, in_bytes(ObjectMonitor::EntryList_offset()), monitor); ld(t2, in_bytes(ObjectMonitor::cxq_offset()), monitor); orr(t, t, t2); @@ -3071,17 +3093,14 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f // Check if there is a successor. ld(t, in_bytes(ObjectMonitor::succ_offset()), monitor); cmpdi(CCR0, t, 0); - bne(CCR0, set_eq_unlocked); // If so we are done. + // Invert equal bit + crnand(flag, Assembler::equal, flag, Assembler::equal); + beq(CCR0, unlocked); // If there is a successor we are done. // Save the monitor pointer in the current thread, so we can try // to reacquire the lock in SharedRuntime::monitor_exit_helper(). std(monitor, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread); - - crxor(CCR0, Assembler::equal, CCR0, Assembler::equal); // Set flag = NE => slow path - b(slow_path); - - bind(set_eq_unlocked); - crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); // Set flag = EQ => fast path + b(slow_path); // flag == NE } bind(unlocked); @@ -4600,23 +4619,6 @@ void MacroAssembler::zap_from_to(Register low, int before, Register high, int af #endif // !PRODUCT -void SkipIfEqualZero::skip_to_label_if_equal_zero(MacroAssembler* masm, Register temp, - const bool* flag_addr, Label& label) { - int simm16_offset = masm->load_const_optimized(temp, (address)flag_addr, R0, true); - assert(sizeof(bool) == 1, "PowerPC ABI"); - masm->lbz(temp, simm16_offset, temp); - masm->cmpwi(CCR0, temp, 0); - masm->beq(CCR0, label); -} - -SkipIfEqualZero::SkipIfEqualZero(MacroAssembler* masm, Register temp, const bool* flag_addr) : _masm(masm), _label() { - skip_to_label_if_equal_zero(masm, temp, flag_addr, _label); -} - -SkipIfEqualZero::~SkipIfEqualZero() { - _masm->bind(_label); -} - void MacroAssembler::cache_wb(Address line) { assert(line.index() == noreg, "index should be noreg"); assert(line.disp() == 0, "displacement should be 0"); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 224e7bff99541..f0e7c6445354c 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -960,23 +960,4 @@ class MacroAssembler: public Assembler { void zap_from_to(Register low, int before, Register high, int after, Register val, Register addr) PRODUCT_RETURN; }; -// class SkipIfEqualZero: -// -// Instantiating this class will result in assembly code being output that will -// jump around any code emitted between the creation of the instance and it's -// automatic destruction at the end of a scope block, depending on the value of -// the flag passed to the constructor, which will be checked at run-time. -class SkipIfEqualZero : public StackObj { - private: - MacroAssembler* _masm; - Label _label; - - public: - // 'Temp' is a temp register that this object can use (and trash). - explicit SkipIfEqualZero(MacroAssembler*, Register temp, const bool* flag_addr); - static void skip_to_label_if_equal_zero(MacroAssembler*, Register temp, - const bool* flag_addr, Label& label); - ~SkipIfEqualZero(); -}; - #endif // CPU_PPC_MACROASSEMBLER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp index 9520f6a94f2a4..f61328fc7360c 100644 --- a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp @@ -92,10 +92,10 @@ address NativeCall::destination() const { // 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. +// during code generation, where no 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()) || + (CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index ca9abfa3719b4..6d3daa025e8d2 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -1000,6 +1000,10 @@ int MachNode::compute_padding(int current_offset) const { // Should the matcher clone input 'm' of node 'n'? bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { + if (is_encode_and_store_pattern(n, m)) { + mstack.push(m, Visit); + return true; + } return false; } @@ -2150,10 +2154,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return nullptr; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return nullptr; -} - // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { return false; @@ -5407,7 +5407,7 @@ instruct loadRange(iRegIdst dst, memory mem) %{ // Load Compressed Pointer instruct loadN(iRegNdst dst, memory mem) %{ match(Set dst (LoadN mem)); - predicate(n->as_Load()->is_unordered() || followed_by_acquire(n)); + predicate((n->as_Load()->is_unordered() || followed_by_acquire(n)) && n->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); format %{ "LWZ $dst, $mem \t// load compressed ptr" %} @@ -5419,6 +5419,7 @@ instruct loadN(iRegNdst dst, memory mem) %{ // Load Compressed Pointer acquire. instruct loadN_ac(iRegNdst dst, memory mem) %{ match(Set dst (LoadN mem)); + predicate(n->as_Load()->barrier_data() == 0); ins_cost(3*MEMORY_REF_COST); format %{ "LWZ $dst, $mem \t// load acquire compressed ptr\n\t" @@ -5432,7 +5433,7 @@ instruct loadN_ac(iRegNdst dst, memory mem) %{ // Load Compressed Pointer and decode it if narrow_oop_shift == 0. instruct loadN2P_unscaled(iRegPdst dst, memory mem) %{ match(Set dst (DecodeN (LoadN mem))); - predicate(_kids[0]->_leaf->as_Load()->is_unordered() && CompressedOops::shift() == 0); + predicate(_kids[0]->_leaf->as_Load()->is_unordered() && CompressedOops::shift() == 0 && _kids[0]->_leaf->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); format %{ "LWZ $dst, $mem \t// DecodeN (unscaled)" %} @@ -6423,6 +6424,7 @@ instruct reinterpretX(vecX dst) %{ // Store Compressed Oop instruct storeN(memory dst, iRegN_P2N src) %{ match(Set dst (StoreN dst src)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); format %{ "STW $src, $dst \t// compressed oop" %} @@ -6476,23 +6478,6 @@ instruct storeD(memory mem, regD src) %{ ins_pipe(pipe_class_memory); %} -//----------Store Instructions With Zeros-------------------------------------- - -instruct storeCM(memory mem, immI_0 zero) %{ - match(Set mem (StoreCM mem zero)); - ins_cost(MEMORY_REF_COST); - - format %{ "STB #0, $mem \t// CMS card-mark byte store" %} - size(8); - ins_encode %{ - __ li(R0, 0); - // No release barrier: Oops are allowed to get visible after marking. - guarantee($mem$$base$$Register != R1_SP, "use frame_slots_bias"); - __ stb(R0, $mem$$disp, $mem$$base$$Register); - %} - ins_pipe(pipe_class_memory); -%} - // Convert oop pointer into compressed form. // Nodes for postalloc expand. @@ -7477,6 +7462,7 @@ instruct compareAndSwapI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc instruct compareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapN mem_ptr (Binary src1 src2))); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ @@ -7676,7 +7662,7 @@ instruct weakCompareAndSwapI_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, instruct weakCompareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (WeakCompareAndSwapN mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "weak CMPXCHGW $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ @@ -7690,7 +7676,7 @@ instruct weakCompareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iReg instruct weakCompareAndSwapN_acq_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (WeakCompareAndSwapN mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst); + predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "weak CMPXCHGW acq $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ @@ -7939,7 +7925,7 @@ instruct compareAndExchangeI_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, instruct compareAndExchangeN_regP_regN_regN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeN mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as narrow oop" %} ins_encode %{ @@ -7953,7 +7939,7 @@ instruct compareAndExchangeN_regP_regN_regN(iRegNdst res, iRegPdst mem_ptr, iReg instruct compareAndExchangeN_acq_regP_regN_regN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeN mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst); + predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); format %{ "CMPXCHGW acq $res, $mem_ptr, $src1, $src2; as narrow oop" %} ins_encode %{ @@ -8262,6 +8248,7 @@ instruct getAndSetP(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src, flagsRegCR0 cr instruct getAndSetN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndSetN mem_ptr src)); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); format %{ "GetAndSetN $res, $mem_ptr, $src" %} ins_encode %{ @@ -12281,7 +12268,7 @@ instruct string_equalsL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst %} instruct array_equalsB(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result, - iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{ + iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR1 cr1) %{ predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (AryEq ary1 ary2)); effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1); @@ -12296,7 +12283,7 @@ instruct array_equalsB(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result, %} instruct array_equalsC(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result, - iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{ + iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR1 cr1) %{ predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); match(Set result (AryEq ary1 ary2)); effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1); diff --git a/src/hotspot/cpu/ppc/register_ppc.hpp b/src/hotspot/cpu/ppc/register_ppc.hpp index 302d49884fae3..b7ba4f053b5d6 100644 --- a/src/hotspot/cpu/ppc/register_ppc.hpp +++ b/src/hotspot/cpu/ppc/register_ppc.hpp @@ -27,6 +27,7 @@ #define CPU_PPC_REGISTER_PPC_HPP #include "asm/register.hpp" +#include "utilities/count_trailing_zeros.hpp" // forward declaration class VMRegImpl; @@ -555,4 +556,12 @@ constexpr Register R29_TOC = R29; constexpr Register R11_scratch1 = R11; constexpr Register R12_scratch2 = R12; +template <> +inline Register AbstractRegSet::first() { + if (_bitset == 0) { return noreg; } + return as_Register(count_trailing_zeros(_bitset)); +} + +typedef AbstractRegSet RegSet; + #endif // CPU_PPC_REGISTER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index ee3f1911e2082..b3ace8898ad63 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -49,7 +49,6 @@ #include "utilities/align.hpp" #include "utilities/powerOfTwo.hpp" #if INCLUDE_ZGC -#include "gc/x/xBarrierSetAssembler.hpp" #include "gc/z/zBarrierSetAssembler.hpp" #endif @@ -1976,7 +1975,7 @@ class StubGenerator: public StubCodeGenerator { generate_conjoint_int_copy_core(aligned); } else { #if INCLUDE_ZGC - if (UseZGC && ZGenerational) { + if (UseZGC) { ZBarrierSetAssembler *zbs = (ZBarrierSetAssembler*)bs; zbs->generate_conjoint_oop_copy(_masm, dest_uninitialized); } else @@ -2019,7 +2018,7 @@ class StubGenerator: public StubCodeGenerator { generate_disjoint_int_copy_core(aligned); } else { #if INCLUDE_ZGC - if (UseZGC && ZGenerational) { + if (UseZGC) { ZBarrierSetAssembler *zbs = (ZBarrierSetAssembler*)bs; zbs->generate_disjoint_oop_copy(_masm, dest_uninitialized); } else @@ -2137,7 +2136,7 @@ class StubGenerator: public StubCodeGenerator { } else { __ bind(store_null); #if INCLUDE_ZGC - if (UseZGC && ZGenerational) { + if (UseZGC) { __ store_heap_oop(R10_oop, R8_offset, R4_to, R11_scratch1, R12_tmp, noreg, MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS, dest_uninitialized ? IS_DEST_UNINITIALIZED : 0); @@ -2153,7 +2152,7 @@ class StubGenerator: public StubCodeGenerator { // ======== loop entry is here ======== __ bind(load_element); #if INCLUDE_ZGC - if (UseZGC && ZGenerational) { + if (UseZGC) { __ load_heap_oop(R10_oop, R8_offset, R3_from, R11_scratch1, R12_tmp, MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS, @@ -4587,6 +4586,30 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { return start; } + // load Method* target of MethodHandle + // R3_ARG1 = jobject receiver + // R19_method = result Method* + address generate_upcall_stub_load_target() { + + StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target"); + address start = __ pc(); + + __ resolve_global_jobject(R3_ARG1, R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS); + // Load target method from receiver + __ load_heap_oop(R19_method, java_lang_invoke_MethodHandle::form_offset(), R3_ARG1, + R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL); + __ load_heap_oop(R19_method, java_lang_invoke_LambdaForm::vmentry_offset(), R19_method, + R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL); + __ load_heap_oop(R19_method, java_lang_invoke_MemberName::method_offset(), R19_method, + R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL); + __ ld(R19_method, java_lang_invoke_ResolvedMethodName::vmtarget_offset(), R19_method); + __ std(R19_method, in_bytes(JavaThread::callee_target_offset()), R16_thread); // just in case callee is deoptimized + + __ blr(); + + return start; + } + // Initialization void generate_initial_stubs() { // Generates all stubs and initializes the entry points @@ -4651,6 +4674,7 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { } StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); } void generate_compiler_stubs() { diff --git a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp index b60fd4f16d163..635bab900d157 100644 --- a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp +++ b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "classfile/javaClasses.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "prims/upcallLinker.hpp" @@ -118,7 +119,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; // arg save & restore + move -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, @@ -221,7 +222,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry), R0); __ addi(R3_ARG1, R1_SP, frame_data_offset); - __ load_const_optimized(R4_ARG2, (intptr_t)receiver, R0); __ call_c(call_target_address); __ mr(R16_thread, R3_RET); __ block_comment("} on_entry"); @@ -236,12 +236,12 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, arg_shuffle.generate(_masm, as_VMStorage(callerSP), frame::native_abi_minframe_size, frame::jit_out_preserve_size); __ block_comment("} argument shuffle"); - __ block_comment("{ receiver "); - __ get_vm_result(R3_ARG1); - __ block_comment("} receiver "); - - __ load_const_optimized(R19_method, (intptr_t)entry); - __ std(R19_method, in_bytes(JavaThread::callee_target_offset()), R16_thread); + __ block_comment("{ load target "); + __ load_const_optimized(call_target_address, StubRoutines::upcall_stub_load_target(), R0); + __ load_const_optimized(R3_ARG1, (intptr_t)receiver, R0); + __ mtctr(call_target_address); + __ bctrl(); // loads target Method* into R19_method + __ block_comment("} load target "); __ push_cont_fastpath(); @@ -326,7 +326,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, #ifndef PRODUCT stringStream ss; - ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + ss.print("upcall_stub_%s", signature->as_C_string()); const char* name = _masm->code_string(ss.as_string()); #else // PRODUCT const char* name = "upcall_stub"; diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index d1021d9e283d2..7334ec675e31f 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -46,8 +46,10 @@ class Argument { public: enum { - n_int_register_parameters_c = 8, // x10, x11, ... x17 (c_rarg0, c_rarg1, ...) - n_float_register_parameters_c = 8, // f10, f11, ... f17 (c_farg0, c_farg1, ... ) + // check more info at https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc + n_int_register_parameters_c = 8, // x10, x11, ... x17 (c_rarg0, c_rarg1, ...) + n_float_register_parameters_c = 8, // f10, f11, ... f17 (c_farg0, c_farg1, ... ) + n_vector_register_parameters_c = 16, // v8, v9, ... v23 n_int_register_parameters_j = 8, // x11, ... x17, x10 (j_rarg0, j_rarg1, ...) n_float_register_parameters_j = 8 // f10, f11, ... f17 (j_farg0, j_farg1, ...) @@ -143,6 +145,10 @@ constexpr Register x19_sender_sp = x19; // Sender's SP while in interpreter constexpr Register t0 = x5; constexpr Register t1 = x6; constexpr Register t2 = x7; +constexpr Register t3 = x28; +constexpr Register t4 = x29; +constexpr Register t5 = x30; +constexpr Register t6 = x31; const Register g_INTArgReg[Argument::n_int_register_parameters_c] = { c_rarg0, c_rarg1, c_rarg2, c_rarg3, c_rarg4, c_rarg5, c_rarg6, c_rarg7 @@ -1956,6 +1962,13 @@ enum Nf { INSN(vbrev8_v, 0b1010111, 0b010, 0b01000, 0b010010); // reverse bits in every byte of element INSN(vrev8_v, 0b1010111, 0b010, 0b01001, 0b010010); // reverse bytes in every elememt + // Vector AES instructions (Zvkned extension) + INSN(vaesem_vv, 0b1110111, 0b010, 0b00010, 0b101000); + INSN(vaesef_vv, 0b1110111, 0b010, 0b00011, 0b101000); + + INSN(vaesdm_vv, 0b1110111, 0b010, 0b00000, 0b101000); + INSN(vaesdf_vv, 0b1110111, 0b010, 0b00001, 0b101000); + INSN(vclz_v, 0b1010111, 0b010, 0b01100, 0b010010); // count leading zeros INSN(vctz_v, 0b1010111, 0b010, 0b01101, 0b010010); // count trailing zeros @@ -2886,8 +2899,9 @@ enum Nf { // Unconditional branch instructions // -------------------------- protected: - // All calls and jumps must go via MASM. + // All calls and jumps must go via MASM. Only use x1 (aka ra) as link register for now. void jalr(Register Rd, Register Rs, const int32_t offset) { + assert(Rd != x5 && Rs != x5, "Register x5 must not be used for calls/jumps."); /* jalr -> c.jr/c.jalr */ if (do_compress() && (offset == 0 && Rs != x0)) { if (Rd == x1) { @@ -2902,6 +2916,7 @@ enum Nf { } void jal(Register Rd, const int32_t offset) { + assert(Rd != x5, "Register x5 must not be used for calls/jumps."); /* jal -> c.j, note c.jal is RV32C only */ if (do_compress() && Rd == x0 && @@ -2909,7 +2924,6 @@ enum Nf { c_j(offset); return; } - _jal(Rd, offset); } diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp index fb81082072610..0be1252f57f8a 100644 --- a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp @@ -43,9 +43,7 @@ void C1SafepointPollStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); InternalAddress safepoint_pc(__ pc() - __ offset() + safepoint_offset()); __ relocate(safepoint_pc.rspec(), [&] { - int32_t offset; - __ la(t0, safepoint_pc.target(), offset); - __ addi(t0, t0, offset); + __ la(t0, safepoint_pc.target()); }); __ sd(t0, Address(xthread, JavaThread::saved_exception_pc_offset())); @@ -93,7 +91,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { stub_id = C1StubId::throw_range_check_failed_id; } // t0 and t1 are used as args in generate_exception_throw, - // so use ra as the tmp register for rt_call. + // so use x1/ra as the tmp register for rt_call. __ rt_call(Runtime1::entry_for(stub_id), ra); ce->add_call_info_here(_info); ce->verify_oop_map(_info); @@ -275,7 +273,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { if (_obj->is_cpu_register()) { __ mv(t0, _obj->as_register()); } - __ far_call(RuntimeAddress(Runtime1::entry_for(_stub)), t1); + __ far_call(RuntimeAddress(Runtime1::entry_for(_stub))); ce->add_call_info_here(_info); debug_only(__ should_not_reach_here()); } diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 940706b0a7376..21bf089118b45 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -838,10 +838,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch __ decode_heap_oop(dest->as_register()); } - if (!(UseZGC && !ZGenerational)) { - // Load barrier has not yet been applied, so ZGC can't verify the oop here - __ verify_oop(dest->as_register()); - } + __ verify_oop(dest->as_register()); } } @@ -980,6 +977,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { if (op->init_check()) { __ lbu(t0, Address(op->klass()->as_register(), InstanceKlass::init_state_offset())); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ mv(t1, (u1)InstanceKlass::fully_initialized); add_debug_info_for_null_check_here(op->stub()->info()); __ bne(t0, t1, *op->stub()->entry(), /* is_far */ true); @@ -1405,9 +1403,7 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit int pc_for_athrow_offset = __ offset(); InternalAddress pc_for_athrow(__ pc()); __ relocate(pc_for_athrow.rspec(), [&] { - int32_t offset; - __ la(exceptionPC->as_register(), pc_for_athrow.target(), offset); - __ addi(exceptionPC->as_register(), exceptionPC->as_register(), offset); + __ la(exceptionPC->as_register(), pc_for_athrow.target()); }); add_call_info(pc_for_athrow_offset, info); // for exception handler diff --git a/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp index 7995750aba96b..320093ee0e332 100644 --- a/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp @@ -33,7 +33,7 @@ #define __ masm. int C2SafepointPollStub::max_size() const { - return 13 * 4; + return 5 * NativeInstruction::instruction_size; } void C2SafepointPollStub::emit(C2_MacroAssembler& masm) { @@ -45,58 +45,31 @@ void C2SafepointPollStub::emit(C2_MacroAssembler& masm) { __ bind(entry()); InternalAddress safepoint_pc(__ pc() - __ offset() + _safepoint_offset); __ relocate(safepoint_pc.rspec(), [&] { - int32_t offset; - __ la(t0, safepoint_pc.target(), offset); - __ addi(t0, t0, offset); + // emits auipc + addi for address inside code cache + __ la(t0, safepoint_pc.target()); }); __ sd(t0, Address(xthread, JavaThread::saved_exception_pc_offset())); + // emits auipc + jr for address inside code cache __ far_jump(callback_addr); } int C2EntryBarrierStub::max_size() const { // 4 bytes for alignment - return 8 * 4 + 4; + return 3 * NativeInstruction::instruction_size + 4 + 4; } void C2EntryBarrierStub::emit(C2_MacroAssembler& masm) { __ bind(entry()); - __ rt_call(StubRoutines::method_entry_barrier()); + // emits auipc + jalr for address inside code cache + __ far_call(StubRoutines::method_entry_barrier()); __ j(continuation()); - // make guard value 4-byte aligned so that it can be accessed by atomic instructions on RISC-V + // make guard value 4-byte aligned so that it can be accessed atomically __ align(4); __ bind(guard()); __ relocate(entry_guard_Relocation::spec()); __ emit_int32(0); // nmethod guard value } -int C2HandleAnonOMOwnerStub::max_size() const { - // Max size of stub has been determined by testing with 0 without using RISC-V compressed - // instruction-set extension, in which case C2CodeStubList::emit() will throw an assertion - // and report the actual size that is needed. - return 20 DEBUG_ONLY(+8); -} - -void C2HandleAnonOMOwnerStub::emit(C2_MacroAssembler& masm) { - __ bind(entry()); - Register mon = monitor(); - Register t = tmp(); - assert(t != noreg, "need tmp register"); - - // Fix owner to be the current thread. - __ sd(xthread, Address(mon, ObjectMonitor::owner_offset())); - - // Pop owner object from lock-stack. - __ lwu(t, Address(xthread, JavaThread::lock_stack_top_offset())); - __ subw(t, t, oopSize); -#ifdef ASSERT - __ add(t0, xthread, t); - __ sd(zr, Address(t0, 0)); -#endif - __ sw(t, Address(xthread, JavaThread::lock_stack_top_offset())); - - __ j(continuation()); -} - #undef __ diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 75f87e35adf41..0ffdcbca72307 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -234,7 +234,7 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, // StoreLoad achieves this. membar(StoreLoad); - // Check if the entry lists are empty. + // Check if the entry lists are empty (EntryList first - by convention). ld(t0, Address(tmp, ObjectMonitor::EntryList_offset())); ld(tmp1Reg, Address(tmp, ObjectMonitor::cxq_offset())); orr(t0, t0, tmp1Reg); @@ -566,7 +566,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, // StoreLoad achieves this. membar(StoreLoad); - // Check if the entry lists are empty. + // Check if the entry lists are empty (EntryList first - by convention). ld(t0, Address(tmp1_monitor, ObjectMonitor::EntryList_offset())); ld(tmp3_t, Address(tmp1_monitor, ObjectMonitor::cxq_offset())); orr(t0, t0, tmp3_t); diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp index 062f80290626f..5493882be7264 100644 --- a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,10 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> @@ -96,6 +99,55 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ pop_reg(saved_regs, sp); } +static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register thread, const Register value, const Register tmp1, const Register tmp2) { + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + __ ld(tmp1, Address(thread, in_bytes(index_offset))); // tmp1 := *(index address) + __ beqz(tmp1, runtime); // jump to runtime if index == 0 (full buffer) + // The buffer is not full, store value into it. + __ sub(tmp1, tmp1, wordSize); // tmp1 := next index + __ sd(tmp1, Address(thread, in_bytes(index_offset))); // *(index address) := next index + __ ld(tmp2, Address(thread, in_bytes(buffer_offset))); // tmp2 := buffer address + __ add(tmp2, tmp2, tmp1); + __ sd(value, Address(tmp2)); // *(buffer address + next index) := value +} + +static void generate_pre_barrier_fast_path(MacroAssembler* masm, + const Register thread, + const Register tmp1) { + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ lwu(tmp1, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbu(tmp1, in_progress); + } +} + +static void generate_pre_barrier_slow_path(MacroAssembler* masm, + const Register obj, + const Register pre_val, + const Register thread, + const Register tmp1, + const Register tmp2, + Label& done, + Label& runtime) { + // Do we need to load the previous value? + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + } + // Is the previous value null? + __ beqz(pre_val, done, true); + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, + thread, pre_val, tmp1, tmp2); + __ j(done); +} + void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, @@ -116,43 +168,10 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, assert_different_registers(obj, pre_val, tmp1, tmp2); assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - - // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { // 4-byte width - __ lwu(tmp1, in_progress); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbu(tmp1, in_progress); - } + generate_pre_barrier_fast_path(masm, thread, tmp1); + // If marking is not active (*(mark queue active address) == 0), jump to done __ beqz(tmp1, done); - - // Do we need to load the previous value? - if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); - } - - // Is the previous value null? - __ beqz(pre_val, done); - - // Can we store original value in the thread's buffer? - // Is index == 0? - // (The index field is typed as size_t.) - - __ ld(tmp1, index); // tmp := *index_adr - __ beqz(tmp1, runtime); // tmp == 0? - // If yes, goto runtime - - __ sub(tmp1, tmp1, wordSize); // tmp := tmp - wordSize - __ sd(tmp1, index); // *index_adr := tmp - __ ld(tmp2, buffer); - __ add(tmp1, tmp1, tmp2); // tmp := tmp + *buffer_adr - - // Record the previous value - __ sd(pre_val, Address(tmp1, 0)); - __ j(done); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, done, runtime); __ bind(runtime); @@ -171,6 +190,49 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, } +static void generate_post_barrier_fast_path(MacroAssembler* masm, + const Register store_addr, + const Register new_val, + const Register tmp1, + const Register tmp2, + Label& done, + bool new_val_may_be_null) { + // Does store cross heap regions? + __ xorr(tmp1, store_addr, new_val); // tmp1 := store address ^ new value + __ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes) + __ beqz(tmp1, done); + // Crosses regions, storing null? + if (new_val_may_be_null) { + __ beqz(new_val, done); + } + // Storing region crossing non-null, is card young? + __ srli(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base + __ load_byte_map_base(tmp2); // tmp2 := card table base address + __ add(tmp1, tmp1, tmp2); // tmp1 := card address + __ lbu(tmp2, Address(tmp1)); // tmp2 := card +} + +static void generate_post_barrier_slow_path(MacroAssembler* masm, + const Register thread, + const Register tmp1, + const Register tmp2, + Label& done, + Label& runtime) { + __ membar(MacroAssembler::StoreLoad); // StoreLoad membar + __ lbu(tmp2, Address(tmp1)); // tmp2 := card + __ beqz(tmp2, done, true); + // Storing a region crossing, non-null oop, card is clean. + // Dirty card and log. + STATIC_ASSERT(CardTable::dirty_card_val() == 0); + __ sb(zr, Address(tmp1)); // *(card address) := dirty_card_val + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, + thread, tmp1, tmp2, t0); + __ j(done); +} + void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, @@ -179,73 +241,119 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register tmp2) { assert(thread == xthread, "must be"); assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, t0); - assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && - tmp2 != noreg, "expecting a register"); - - Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - BarrierSet* bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); + assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, + "expecting a register"); Label done; Label runtime; - // Does store cross heap regions? + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */); + // If card is young, jump to done (tmp2 holds the card value) + __ mv(t0, (int)G1CardTable::g1_young_card_val()); + __ beq(tmp2, t0, done); // card == young_card_val? + generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime); - __ xorr(tmp1, store_addr, new_val); - __ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); - __ beqz(tmp1, done); + __ bind(runtime); + // save the live input values + RegSet saved = RegSet::of(store_addr); + __ push_reg(saved, sp); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread); + __ pop_reg(saved, sp); - // crosses regions, storing null? + __ bind(done); +} - __ beqz(new_val, done); +#if defined(COMPILER2) - // storing region crossing non-null, is card already dirty? +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { + SaveLiveRegisters save_registers(masm, stub); + if (c_rarg0 != arg) { + __ mv(c_rarg0, arg); + } + __ mv(c_rarg1, xthread); + __ mv(t1, runtime_path); + __ jalr(t1); +} - const Register card_addr = tmp1; +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* stub) { + assert(thread == xthread, "must be"); + assert_different_registers(obj, pre_val, tmp1, tmp2); + assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - __ srli(card_addr, store_addr, CardTable::card_shift()); + stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2); - // get the address of the card - __ load_byte_map_base(tmp2); - __ add(card_addr, card_addr, tmp2); - __ lbu(tmp2, Address(card_addr)); - __ mv(t0, (int)G1CardTable::g1_young_card_val()); - __ beq(tmp2, t0, done); + generate_pre_barrier_fast_path(masm, thread, tmp1); + // If marking is active (*(mark queue active address) != 0), jump to stub (slow path) + __ bnez(tmp1, *stub->entry(), true); - assert((int)CardTable::dirty_card_val() == 0, "must be 0"); + __ bind(*stub->continuation()); +} - __ membar(MacroAssembler::StoreLoad); +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); + Register tmp2 = stub->tmp2(); - __ lbu(tmp2, Address(card_addr)); - __ beqz(tmp2, done); + __ bind(*stub->entry()); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, *stub->continuation(), runtime); - // storing a region crossing, non-null oop, card is clean. - // dirty card and log. + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); + __ j(*stub->continuation()); +} - __ sb(zr, Address(card_addr)); +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* stub) { + assert(thread == xthread, "must be"); + assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, t0); + assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, + "expecting a register"); - __ ld(t0, queue_index); - __ beqz(t0, runtime); - __ sub(t0, t0, wordSize); - __ sd(t0, queue_index); + stub->initialize_registers(thread, tmp1, tmp2); - __ ld(tmp2, buffer); - __ add(t0, tmp2, t0); - __ sd(card_addr, Address(t0, 0)); - __ j(done); + bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null); + // If card is not young, jump to stub (slow path) (tmp2 holds the card value) + __ mv(t0, (int)G1CardTable::g1_young_card_val()); + __ bne(tmp2, t0, *stub->entry(), true); - __ bind(runtime); - // save the live input values - RegSet saved = RegSet::of(store_addr); - __ push_reg(saved, sp); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); - __ pop_reg(saved, sp); + __ bind(*stub->continuation()); +} - __ bind(done); +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); // tmp1 holds the card address. + Register tmp2 = stub->tmp2(); + + __ bind(*stub->entry()); + generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); + __ j(*stub->continuation()); } +#endif // COMPILER2 + void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp2) { bool on_oop = is_reference_type(type); diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp index 96568994079dd..c7bee2ef6f3a8 100644 --- a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,8 @@ class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -72,6 +74,27 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); #endif +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* c2_stub); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif + void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp2); }; diff --git a/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad new file mode 100644 index 0000000000000..7a525323021dd --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad @@ -0,0 +1,564 @@ +// +// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2024, Huawei Technologies Co., Ltd. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute 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. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_riscv.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void write_barrier_pre(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2, + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, xthread, tmp1, tmp2, stub); +} + +static void write_barrier_post(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, xthread, tmp1, tmp2, stub); +} + +%} + +instruct g1StoreP(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(STORE_COST); + format %{ "sd $src, $mem\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ sd($src$$Register, Address($mem$$Register)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +instruct g1StoreN(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(STORE_COST); + format %{ "sw $src, $mem\t# compressed ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ sw($src$$Register, Address($mem$$Register)); + if ((barrier_data() & G1C2BarrierPost) != 0) { + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ decode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + } + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(STORE_COST); + format %{ "encode_heap_oop $tmp1, $src\n\t" + "sw $tmp1, $mem\t# compressed ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ encode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + __ sw($tmp1$$Register, Address($mem$$Register)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +instruct g1CompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $res = $mem, $oldval, $newval\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP and its Acq variant. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP and its Acq variant. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $res = $mem, $oldval, $newval\t# narrow oop" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# narrow oop" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndSwapP(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $mem, $oldval, $newval\t# (ptr)\n\t" + "mv $res, $res == $oldval" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (ptr)\n\t" + "mv $res, $res == $oldval" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndSwapN(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $mem, $oldval, $newval\t# (narrow oop)\n\t" + "mv $res, $res == $oldval" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (narrow oop)\n\t" + "mv $res, $res == $oldval" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1GetAndSetP(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "atomic_xchg $preval, $newval, [$mem]" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchg($preval$$Register, $newval$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +instruct g1GetAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "atomic_xchg_acq $preval, $newval, [$mem]" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgal($preval$$Register, $newval$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +instruct g1GetAndSetN(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetN mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "atomic_xchgwu $preval, $newval, [$mem]" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgwu($preval$$Register, $newval$$Register, $mem$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +instruct g1GetAndSetNAcq(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetN mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "atomic_xchgwu_acq $preval, $newval, [$mem]" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgalwu($preval$$Register, $newval$$Register, $mem$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(LOAD_COST + BRANCH_COST); + format %{ "ld $dst, $mem\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + __ ld($dst$$Register, Address($mem$$Register)); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(iload_reg_mem); +%} + +instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadN mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(LOAD_COST + BRANCH_COST); + format %{ "lwu $dst, $mem\t# compressed ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + __ lwu($dst$$Register, Address($mem$$Register)); + if ((barrier_data() & G1C2BarrierPre) != 0) { + __ decode_heap_oop($tmp1$$Register, $dst$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + } + %} + ins_pipe(iload_reg_mem); +%} diff --git a/src/hotspot/cpu/riscv/gc/x/xBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/x/xBarrierSetAssembler_riscv.cpp deleted file mode 100644 index 7306492970b81..0000000000000 --- a/src/hotspot/cpu/riscv/gc/x/xBarrierSetAssembler_riscv.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (c) 2019, 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. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/codeBlob.hpp" -#include "code/vmreg.inline.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xBarrierSet.hpp" -#include "gc/x/xBarrierSetAssembler.hpp" -#include "gc/x/xBarrierSetRuntime.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/sharedRuntime.hpp" -#include "utilities/macros.hpp" -#ifdef COMPILER1 -#include "c1/c1_LIRAssembler.hpp" -#include "c1/c1_MacroAssembler.hpp" -#include "gc/x/c1/xBarrierSetC1.hpp" -#endif // COMPILER1 -#ifdef COMPILER2 -#include "gc/x/c2/xBarrierSetC2.hpp" -#endif // COMPILER2 - -#ifdef PRODUCT -#define BLOCK_COMMENT(str) /* nothing */ -#else -#define BLOCK_COMMENT(str) __ block_comment(str) -#endif - -#undef __ -#define __ masm-> - -void XBarrierSetAssembler::load_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Register dst, - Address src, - Register tmp1, - Register tmp2) { - if (!XBarrierSet::barrier_needed(decorators, type)) { - // Barrier not needed - BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2); - return; - } - - assert_different_registers(t1, src.base()); - assert_different_registers(t0, t1, dst); - - Label done; - - // Load bad mask into temp register. - __ la(t0, src); - __ ld(t1, address_bad_mask_from_thread(xthread)); - __ ld(dst, Address(t0)); - - // Test reference against bad mask. If mask bad, then we need to fix it up. - __ andr(t1, dst, t1); - __ beqz(t1, done); - - __ enter(); - - __ push_call_clobbered_registers_except(RegSet::of(dst)); - - if (c_rarg0 != dst) { - __ mv(c_rarg0, dst); - } - - __ mv(c_rarg1, t0); - - __ call_VM_leaf(XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), 2); - - // Make sure dst has the return value. - if (dst != x10) { - __ mv(dst, x10); - } - - __ pop_call_clobbered_registers_except(RegSet::of(dst)); - __ leave(); - - __ bind(done); -} - -#ifdef ASSERT - -void XBarrierSetAssembler::store_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Address dst, - Register val, - Register tmp1, - Register tmp2, - Register tmp3) { - // Verify value - if (is_reference_type(type)) { - // Note that src could be noreg, which means we - // are storing null and can skip verification. - if (val != noreg) { - Label done; - - // tmp1, tmp2 and tmp3 are often set to noreg. - RegSet savedRegs = RegSet::of(t0); - __ push_reg(savedRegs, sp); - - __ ld(t0, address_bad_mask_from_thread(xthread)); - __ andr(t0, val, t0); - __ beqz(t0, done); - __ stop("Verify oop store failed"); - __ should_not_reach_here(); - __ bind(done); - __ pop_reg(savedRegs, sp); - } - } - - // Store value - BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, noreg); -} - -#endif // ASSERT - -void XBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, - DecoratorSet decorators, - bool is_oop, - Register src, - Register dst, - Register count, - RegSet saved_regs) { - if (!is_oop) { - // Barrier not needed - return; - } - - BLOCK_COMMENT("XBarrierSetAssembler::arraycopy_prologue {"); - - assert_different_registers(src, count, t0); - - __ push_reg(saved_regs, sp); - - if (count == c_rarg0 && src == c_rarg1) { - // exactly backwards!! - __ xorr(c_rarg0, c_rarg0, c_rarg1); - __ xorr(c_rarg1, c_rarg0, c_rarg1); - __ xorr(c_rarg0, c_rarg0, c_rarg1); - } else { - __ mv(c_rarg0, src); - __ mv(c_rarg1, count); - } - - __ call_VM_leaf(XBarrierSetRuntime::load_barrier_on_oop_array_addr(), 2); - - __ pop_reg(saved_regs, sp); - - BLOCK_COMMENT("} XBarrierSetAssembler::arraycopy_prologue"); -} - -void XBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, - Register jni_env, - Register robj, - Register tmp, - Label& slowpath) { - BLOCK_COMMENT("XBarrierSetAssembler::try_resolve_jobject_in_native {"); - - assert_different_registers(jni_env, robj, tmp); - - // Resolve jobject - BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, robj, tmp, slowpath); - - // Compute the offset of address bad mask from the field of jni_environment - long int bad_mask_relative_offset = (long int) (in_bytes(XThreadLocalData::address_bad_mask_offset()) - - in_bytes(JavaThread::jni_environment_offset())); - - // Load the address bad mask - __ ld(tmp, Address(jni_env, bad_mask_relative_offset)); - - // Check address bad mask - __ andr(tmp, robj, tmp); - __ bnez(tmp, slowpath); - - BLOCK_COMMENT("} XBarrierSetAssembler::try_resolve_jobject_in_native"); -} - -#ifdef COMPILER2 - -OptoReg::Name XBarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) { - if (!OptoReg::is_reg(opto_reg)) { - return OptoReg::Bad; - } - - const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); - if (vm_reg->is_FloatRegister()) { - return opto_reg & ~1; - } - - return opto_reg; -} - -#undef __ -#define __ _masm-> - -class XSaveLiveRegisters { -private: - MacroAssembler* const _masm; - RegSet _gp_regs; - FloatRegSet _fp_regs; - VectorRegSet _vp_regs; - -public: - void initialize(XLoadBarrierStubC2* stub) { - // Record registers that needs to be saved/restored - RegMaskIterator rmi(stub->live()); - while (rmi.has_next()) { - const OptoReg::Name opto_reg = rmi.next(); - if (OptoReg::is_reg(opto_reg)) { - const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); - if (vm_reg->is_Register()) { - _gp_regs += RegSet::of(vm_reg->as_Register()); - } else if (vm_reg->is_FloatRegister()) { - _fp_regs += FloatRegSet::of(vm_reg->as_FloatRegister()); - } else if (vm_reg->is_VectorRegister()) { - const VMReg vm_reg_base = OptoReg::as_VMReg(opto_reg & ~(VectorRegister::max_slots_per_register - 1)); - _vp_regs += VectorRegSet::of(vm_reg_base->as_VectorRegister()); - } else { - fatal("Unknown register type"); - } - } - } - - // Remove C-ABI SOE registers, tmp regs and _ref register that will be updated - _gp_regs -= RegSet::range(x18, x27) + RegSet::of(x2) + RegSet::of(x8, x9) + RegSet::of(x5, stub->ref()); - } - - XSaveLiveRegisters(MacroAssembler* masm, XLoadBarrierStubC2* stub) : - _masm(masm), - _gp_regs(), - _fp_regs(), - _vp_regs() { - // Figure out what registers to save/restore - initialize(stub); - - // Save registers - __ push_reg(_gp_regs, sp); - __ push_fp(_fp_regs, sp); - __ push_v(_vp_regs, sp); - } - - ~XSaveLiveRegisters() { - // Restore registers - __ pop_v(_vp_regs, sp); - __ pop_fp(_fp_regs, sp); - __ pop_reg(_gp_regs, sp); - } -}; - -class XSetupArguments { -private: - MacroAssembler* const _masm; - const Register _ref; - const Address _ref_addr; - -public: - XSetupArguments(MacroAssembler* masm, XLoadBarrierStubC2* stub) : - _masm(masm), - _ref(stub->ref()), - _ref_addr(stub->ref_addr()) { - - // Setup arguments - if (_ref_addr.base() == noreg) { - // No self healing - if (_ref != c_rarg0) { - __ mv(c_rarg0, _ref); - } - __ mv(c_rarg1, zr); - } else { - // Self healing - if (_ref == c_rarg0) { - // _ref is already at correct place - __ la(c_rarg1, _ref_addr); - } else if (_ref != c_rarg1) { - // _ref is in wrong place, but not in c_rarg1, so fix it first - __ la(c_rarg1, _ref_addr); - __ mv(c_rarg0, _ref); - } else if (_ref_addr.base() != c_rarg0) { - assert(_ref == c_rarg1, "Mov ref first, vacating c_rarg0"); - __ mv(c_rarg0, _ref); - __ la(c_rarg1, _ref_addr); - } else { - assert(_ref == c_rarg1, "Need to vacate c_rarg1 and _ref_addr is using c_rarg0"); - if (_ref_addr.base() == c_rarg0) { - __ mv(t1, c_rarg1); - __ la(c_rarg1, _ref_addr); - __ mv(c_rarg0, t1); - } else { - ShouldNotReachHere(); - } - } - } - } - - ~XSetupArguments() { - // Transfer result - if (_ref != x10) { - __ mv(_ref, x10); - } - } -}; - -#undef __ -#define __ masm-> - -void XBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, XLoadBarrierStubC2* stub) const { - BLOCK_COMMENT("XLoadBarrierStubC2"); - - // Stub entry - __ bind(*stub->entry()); - - { - XSaveLiveRegisters save_live_registers(masm, stub); - XSetupArguments setup_arguments(masm, stub); - - __ mv(t0, stub->slow_path()); - __ jalr(t0); - } - - // Stub exit - __ j(*stub->continuation()); -} - -#endif // COMPILER2 - -#ifdef COMPILER1 -#undef __ -#define __ ce->masm()-> - -void XBarrierSetAssembler::generate_c1_load_barrier_test(LIR_Assembler* ce, - LIR_Opr ref) const { - assert_different_registers(xthread, ref->as_register(), t1); - __ ld(t1, address_bad_mask_from_thread(xthread)); - __ andr(t1, t1, ref->as_register()); -} - -void XBarrierSetAssembler::generate_c1_load_barrier_stub(LIR_Assembler* ce, - XLoadBarrierStubC1* stub) const { - // Stub entry - __ bind(*stub->entry()); - - Register ref = stub->ref()->as_register(); - Register ref_addr = noreg; - Register tmp = noreg; - - if (stub->tmp()->is_valid()) { - // Load address into tmp register - ce->leal(stub->ref_addr(), stub->tmp()); - ref_addr = tmp = stub->tmp()->as_pointer_register(); - } else { - // Address already in register - ref_addr = stub->ref_addr()->as_address_ptr()->base()->as_pointer_register(); - } - - assert_different_registers(ref, ref_addr, noreg); - - // Save x10 unless it is the result or tmp register - // Set up SP to accommodate parameters and maybe x10. - if (ref != x10 && tmp != x10) { - __ sub(sp, sp, 32); - __ sd(x10, Address(sp, 16)); - } else { - __ sub(sp, sp, 16); - } - - // Setup arguments and call runtime stub - ce->store_parameter(ref_addr, 1); - ce->store_parameter(ref, 0); - - __ far_call(stub->runtime_stub()); - - // Verify result - __ verify_oop(x10); - - - // Move result into place - if (ref != x10) { - __ mv(ref, x10); - } - - // Restore x10 unless it is the result or tmp register - if (ref != x10 && tmp != x10) { - __ ld(x10, Address(sp, 16)); - __ add(sp, sp, 32); - } else { - __ add(sp, sp, 16); - } - - // Stub exit - __ j(*stub->continuation()); -} - -#undef __ -#define __ sasm-> - -void XBarrierSetAssembler::generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, - DecoratorSet decorators) const { - __ prologue("zgc_load_barrier stub", false); - - __ push_call_clobbered_registers_except(RegSet::of(x10)); - - // Setup arguments - __ load_parameter(0, c_rarg0); - __ load_parameter(1, c_rarg1); - - __ call_VM_leaf(XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), 2); - - __ pop_call_clobbered_registers_except(RegSet::of(x10)); - - __ epilogue(); -} - -#endif // COMPILER1 - -#undef __ -#define __ masm-> - -void XBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) { - // Check if mask is good. - // verifies that XAddressBadMask & obj == 0 - __ ld(tmp2, Address(xthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(tmp1, obj, tmp2); - __ bnez(tmp1, error); - - BarrierSetAssembler::check_oop(masm, obj, tmp1, tmp2, error); -} - -#undef __ diff --git a/src/hotspot/cpu/riscv/gc/x/xBarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/x/xBarrierSetAssembler_riscv.hpp deleted file mode 100644 index cbf5077999bfb..0000000000000 --- a/src/hotspot/cpu/riscv/gc/x/xBarrierSetAssembler_riscv.hpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 CPU_RISCV_GC_X_XBARRIERSETASSEMBLER_RISCV_HPP -#define CPU_RISCV_GC_X_XBARRIERSETASSEMBLER_RISCV_HPP - -#include "code/vmreg.hpp" -#include "oops/accessDecorators.hpp" -#ifdef COMPILER2 -#include "opto/optoreg.hpp" -#endif // COMPILER2 - -#ifdef COMPILER1 -class LIR_Assembler; -class LIR_Opr; -class StubAssembler; -#endif // COMPILER1 - -#ifdef COMPILER2 -class Node; -#endif // COMPILER2 - -#ifdef COMPILER1 -class XLoadBarrierStubC1; -#endif // COMPILER1 - -#ifdef COMPILER2 -class XLoadBarrierStubC2; -#endif // COMPILER2 - -class XBarrierSetAssembler : public XBarrierSetAssemblerBase { -public: - virtual void load_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Register dst, - Address src, - Register tmp1, - Register tmp2); - -#ifdef ASSERT - virtual void store_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Address dst, - Register val, - Register tmp1, - Register tmp2, - Register tmp3); -#endif // ASSERT - - virtual void arraycopy_prologue(MacroAssembler* masm, - DecoratorSet decorators, - bool is_oop, - Register src, - Register dst, - Register count, - RegSet saved_regs); - - virtual void try_resolve_jobject_in_native(MacroAssembler* masm, - Register jni_env, - Register robj, - Register tmp, - Label& slowpath); - - virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; } - -#ifdef COMPILER1 - void generate_c1_load_barrier_test(LIR_Assembler* ce, - LIR_Opr ref) const; - - void generate_c1_load_barrier_stub(LIR_Assembler* ce, - XLoadBarrierStubC1* stub) const; - - void generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, - DecoratorSet decorators) const; -#endif // COMPILER1 - -#ifdef COMPILER2 - OptoReg::Name refine_register(const Node* node, - OptoReg::Name opto_reg); - - void generate_c2_load_barrier_stub(MacroAssembler* masm, - XLoadBarrierStubC2* stub) const; -#endif // COMPILER2 - - void check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error); -}; - -#endif // CPU_RISCV_GC_X_XBARRIERSETASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.cpp b/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.cpp deleted file mode 100644 index 602dab5674738..0000000000000 --- a/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xGlobals.hpp" -#include "runtime/globals.hpp" -#include "runtime/os.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/powerOfTwo.hpp" - -#ifdef LINUX -#include -#endif // LINUX - -// -// The heap can have three different layouts, depending on the max heap size. -// -// Address Space & Pointer Layout 1 -// -------------------------------- -// -// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) -// . . -// . . -// . . -// +--------------------------------+ 0x0000014000000000 (20TB) -// | Remapped View | -// +--------------------------------+ 0x0000010000000000 (16TB) -// . . -// +--------------------------------+ 0x00000c0000000000 (12TB) -// | Marked1 View | -// +--------------------------------+ 0x0000080000000000 (8TB) -// | Marked0 View | -// +--------------------------------+ 0x0000040000000000 (4TB) -// . . -// +--------------------------------+ 0x0000000000000000 -// -// 6 4 4 4 4 -// 3 6 5 2 1 0 -// +--------------------+----+-----------------------------------------------+ -// |00000000 00000000 00|1111|11 11111111 11111111 11111111 11111111 11111111| -// +--------------------+----+-----------------------------------------------+ -// | | | -// | | * 41-0 Object Offset (42-bits, 4TB address space) -// | | -// | * 45-42 Metadata Bits (4-bits) 0001 = Marked0 (Address view 4-8TB) -// | 0010 = Marked1 (Address view 8-12TB) -// | 0100 = Remapped (Address view 16-20TB) -// | 1000 = Finalizable (Address view N/A) -// | -// * 63-46 Fixed (18-bits, always zero) -// -// -// Address Space & Pointer Layout 2 -// -------------------------------- -// -// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) -// . . -// . . -// . . -// +--------------------------------+ 0x0000280000000000 (40TB) -// | Remapped View | -// +--------------------------------+ 0x0000200000000000 (32TB) -// . . -// +--------------------------------+ 0x0000180000000000 (24TB) -// | Marked1 View | -// +--------------------------------+ 0x0000100000000000 (16TB) -// | Marked0 View | -// +--------------------------------+ 0x0000080000000000 (8TB) -// . . -// +--------------------------------+ 0x0000000000000000 -// -// 6 4 4 4 4 -// 3 7 6 3 2 0 -// +------------------+-----+------------------------------------------------+ -// |00000000 00000000 0|1111|111 11111111 11111111 11111111 11111111 11111111| -// +-------------------+----+------------------------------------------------+ -// | | | -// | | * 42-0 Object Offset (43-bits, 8TB address space) -// | | -// | * 46-43 Metadata Bits (4-bits) 0001 = Marked0 (Address view 8-16TB) -// | 0010 = Marked1 (Address view 16-24TB) -// | 0100 = Remapped (Address view 32-40TB) -// | 1000 = Finalizable (Address view N/A) -// | -// * 63-47 Fixed (17-bits, always zero) -// -// -// Address Space & Pointer Layout 3 -// -------------------------------- -// -// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) -// . . -// . . -// . . -// +--------------------------------+ 0x0000500000000000 (80TB) -// | Remapped View | -// +--------------------------------+ 0x0000400000000000 (64TB) -// . . -// +--------------------------------+ 0x0000300000000000 (48TB) -// | Marked1 View | -// +--------------------------------+ 0x0000200000000000 (32TB) -// | Marked0 View | -// +--------------------------------+ 0x0000100000000000 (16TB) -// . . -// +--------------------------------+ 0x0000000000000000 -// -// 6 4 4 4 4 -// 3 8 7 4 3 0 -// +------------------+----+-------------------------------------------------+ -// |00000000 00000000 |1111|1111 11111111 11111111 11111111 11111111 11111111| -// +------------------+----+-------------------------------------------------+ -// | | | -// | | * 43-0 Object Offset (44-bits, 16TB address space) -// | | -// | * 47-44 Metadata Bits (4-bits) 0001 = Marked0 (Address view 16-32TB) -// | 0010 = Marked1 (Address view 32-48TB) -// | 0100 = Remapped (Address view 64-80TB) -// | 1000 = Finalizable (Address view N/A) -// | -// * 63-48 Fixed (16-bits, always zero) -// - -// Default value if probing is not implemented for a certain platform: 128TB -static const size_t DEFAULT_MAX_ADDRESS_BIT = 47; -// Minimum value returned, if probing fails: 64GB -static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; - -static size_t probe_valid_max_address_bit() { -#ifdef LINUX - size_t max_address_bit = 0; - const size_t page_size = os::vm_page_size(); - for (size_t i = DEFAULT_MAX_ADDRESS_BIT; i > MINIMUM_MAX_ADDRESS_BIT; --i) { - const uintptr_t base_addr = ((uintptr_t) 1U) << i; - if (msync((void*)base_addr, page_size, MS_ASYNC) == 0) { - // msync succeeded, the address is valid, and maybe even already mapped. - max_address_bit = i; - break; - } - if (errno != ENOMEM) { - // Some error occurred. This should never happen, but msync - // has some undefined behavior, hence ignore this bit. -#ifdef ASSERT - fatal("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno)); -#else // ASSERT - log_warning_p(gc)("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno)); -#endif // ASSERT - continue; - } - // Since msync failed with ENOMEM, the page might not be mapped. - // Try to map it, to see if the address is valid. - void* const result_addr = mmap((void*) base_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); - if (result_addr != MAP_FAILED) { - munmap(result_addr, page_size); - } - if ((uintptr_t) result_addr == base_addr) { - // address is valid - max_address_bit = i; - break; - } - } - if (max_address_bit == 0) { - // probing failed, allocate a very high page and take that bit as the maximum - const uintptr_t high_addr = ((uintptr_t) 1U) << DEFAULT_MAX_ADDRESS_BIT; - void* const result_addr = mmap((void*) high_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); - if (result_addr != MAP_FAILED) { - max_address_bit = BitsPerSize_t - count_leading_zeros((size_t) result_addr) - 1; - munmap(result_addr, page_size); - } - } - log_info_p(gc, init)("Probing address space for the highest valid bit: " SIZE_FORMAT, max_address_bit); - return MAX2(max_address_bit, MINIMUM_MAX_ADDRESS_BIT); -#else // LINUX - return DEFAULT_MAX_ADDRESS_BIT; -#endif // LINUX -} - -size_t XPlatformAddressOffsetBits() { - const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; - const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; - const size_t min_address_offset_bits = max_address_offset_bits - 2; - const size_t address_offset = round_up_power_of_2(MaxHeapSize * XVirtualToPhysicalRatio); - const size_t address_offset_bits = log2i_exact(address_offset); - return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); -} - -size_t XPlatformAddressMetadataShift() { - return XPlatformAddressOffsetBits(); -} diff --git a/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.hpp b/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.hpp deleted file mode 100644 index 836dc7aac0d1d..0000000000000 --- a/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 CPU_RISCV_GC_X_XGLOBALS_RISCV_HPP -#define CPU_RISCV_GC_X_XGLOBALS_RISCV_HPP - -const size_t XPlatformHeapViews = 3; -const size_t XPlatformCacheLineSize = 64; - -size_t XPlatformAddressOffsetBits(); -size_t XPlatformAddressMetadataShift(); - -#endif // CPU_RISCV_GC_X_XGLOBALS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/x/x_riscv.ad b/src/hotspot/cpu/riscv/gc/x/x_riscv.ad deleted file mode 100644 index ef02f301c6aeb..0000000000000 --- a/src/hotspot/cpu/riscv/gc/x/x_riscv.ad +++ /dev/null @@ -1,229 +0,0 @@ -// -// Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. -// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -// -// This code is free software; you can redistribute 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. -// - -source_hpp %{ - -#include "gc/shared/gc_globals.hpp" -#include "gc/x/c2/xBarrierSetC2.hpp" -#include "gc/x/xThreadLocalData.hpp" - -%} - -source %{ - -static void x_load_barrier(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref, Register tmp, int barrier_data) { - if (barrier_data == XLoadBarrierElided) { - return; - } - XLoadBarrierStubC2* const stub = XLoadBarrierStubC2::create(node, ref_addr, ref, tmp, barrier_data); - __ ld(tmp, Address(xthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(tmp, tmp, ref); - __ bnez(tmp, *stub->entry(), true /* far */); - __ bind(*stub->continuation()); -} - -static void x_load_barrier_slow_path(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref, Register tmp) { - XLoadBarrierStubC2* const stub = XLoadBarrierStubC2::create(node, ref_addr, ref, tmp, XLoadBarrierStrong); - __ j(*stub->entry()); - __ bind(*stub->continuation()); -} - -%} - -// Load Pointer -instruct xLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp) -%{ - match(Set dst (LoadP mem)); - predicate(UseZGC && !ZGenerational && (n->as_Load()->barrier_data() != 0)); - effect(TEMP dst, TEMP tmp); - - ins_cost(4 * DEFAULT_COST); - - format %{ "ld $dst, $mem, #@zLoadP" %} - - ins_encode %{ - const Address ref_addr (as_Register($mem$$base), $mem$$disp); - __ ld($dst$$Register, ref_addr); - x_load_barrier(masm, this, ref_addr, $dst$$Register, $tmp$$Register /* tmp */, barrier_data()); - %} - - ins_pipe(iload_reg_mem); -%} - -instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{ - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(TEMP_DEF res, TEMP tmp); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ "cmpxchg $mem, $oldval, $newval, #@zCompareAndSwapP\n\t" - "mv $res, $res == $oldval" %} - - ins_encode %{ - Label failed; - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, - Assembler::relaxed /* acquire */, Assembler::rl /* release */, $tmp$$Register); - __ sub(t0, $tmp$$Register, $oldval$$Register); - __ seqz($res$$Register, t0); - if (barrier_data() != XLoadBarrierElided) { - Label good; - __ ld(t0, Address(xthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(t0, t0, $tmp$$Register); - __ beqz(t0, good); - x_load_barrier_slow_path(masm, this, Address($mem$$Register), $tmp$$Register /* ref */, $res$$Register /* tmp */); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, - Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, - true /* result_as_bool */); - __ bind(good); - } - %} - - ins_pipe(pipe_slow); -%} - -instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{ - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == XLoadBarrierStrong)); - effect(TEMP_DEF res, TEMP tmp); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ "cmpxchg $mem, $oldval, $newval, #@zCompareAndSwapPAcq\n\t" - "mv $res, $res == $oldval" %} - - ins_encode %{ - Label failed; - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, - Assembler::aq /* acquire */, Assembler::rl /* release */, $tmp$$Register); - __ sub(t0, $tmp$$Register, $oldval$$Register); - __ seqz($res$$Register, t0); - if (barrier_data() != XLoadBarrierElided) { - Label good; - __ ld(t0, Address(xthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(t0, t0, $tmp$$Register); - __ beqz(t0, good); - x_load_barrier_slow_path(masm, this, Address($mem$$Register), $tmp$$Register /* ref */, $res$$Register /* tmp */); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, - Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register, - true /* result_as_bool */); - __ bind(good); - } - %} - - ins_pipe(pipe_slow); -%} - -instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{ - match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(TEMP_DEF res, TEMP tmp); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ "cmpxchg $res = $mem, $oldval, $newval, #@zCompareAndExchangeP" %} - - ins_encode %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, - Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register); - if (barrier_data() != XLoadBarrierElided) { - Label good; - __ ld(t0, Address(xthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(t0, t0, $res$$Register); - __ beqz(t0, good); - x_load_barrier_slow_path(masm, this, Address($mem$$Register), $res$$Register /* ref */, $tmp$$Register /* tmp */); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, - Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register); - __ bind(good); - } - %} - - ins_pipe(pipe_slow); -%} - -instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{ - match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(TEMP_DEF res, TEMP tmp); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ "cmpxchg $res = $mem, $oldval, $newval, #@zCompareAndExchangePAcq" %} - - ins_encode %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, - Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register); - if (barrier_data() != XLoadBarrierElided) { - Label good; - __ ld(t0, Address(xthread, XThreadLocalData::address_bad_mask_offset())); - __ andr(t0, t0, $res$$Register); - __ beqz(t0, good); - x_load_barrier_slow_path(masm, this, Address($mem$$Register), $res$$Register /* ref */, $tmp$$Register /* tmp */); - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, - Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register); - __ bind(good); - } - %} - - ins_pipe(pipe_slow); -%} - -instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ - match(Set prev (GetAndSetP mem newv)); - predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP_DEF prev, TEMP tmp); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ "atomic_xchg $prev, $newv, [$mem], #@zGetAndSetP" %} - - ins_encode %{ - __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base)); - x_load_barrier(masm, this, Address(noreg, 0), $prev$$Register, $tmp$$Register /* tmp */, barrier_data()); - %} - - ins_pipe(pipe_serial); -%} - -instruct xGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ - match(Set prev (GetAndSetP mem newv)); - predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() != 0)); - effect(TEMP_DEF prev, TEMP tmp); - - ins_cost(VOLATILE_REF_COST); - - format %{ "atomic_xchg_acq $prev, $newv, [$mem], #@zGetAndSetPAcq" %} - - ins_encode %{ - __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base)); - x_load_barrier(masm, this, Address(noreg, 0), $prev$$Register, $tmp$$Register /* tmp */, barrier_data()); - %} - ins_pipe(pipe_serial); -%} diff --git a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp index cbb918ade00fe..cd83eafcaeba5 100644 --- a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp @@ -724,8 +724,8 @@ void ZBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, Z { SaveLiveRegisters save_live_registers(masm, stub); ZSetupArguments setup_arguments(masm, stub); - __ mv(t0, stub->slow_path()); - __ jalr(t0); + __ mv(t1, stub->slow_path()); + __ jalr(t1); } // Stub exit @@ -758,13 +758,14 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, __ la(c_rarg0, stub->ref_addr()); if (stub->is_native()) { - __ la(t0, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr())); + __ rt_call(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr()); } else if (stub->is_atomic()) { - __ la(t0, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr())); + __ rt_call(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr()); + } else if (stub->is_nokeepalive()) { + __ rt_call(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr()); } else { - __ la(t0, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr())); + __ rt_call(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr()); } - __ jalr(t0); } // Stub exit diff --git a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad index 4c94e504475ee..8e33d514f46cb 100644 --- a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad +++ b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad @@ -82,7 +82,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address z_color(masm, node, rnew_zpointer, rnew_zaddress, tmp); } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; - ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic); + bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0; + ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive); ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler(); bs_asm->store_barrier_fast(masm, ref_addr, rnew_zaddress, rnew_zpointer, tmp, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation()); } @@ -90,11 +91,11 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address %} // Load Pointer -instruct zLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp) +instruct zLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set dst (LoadP mem)); - predicate(UseZGC && ZGenerational && n->as_Load()->barrier_data() != 0); - effect(TEMP dst, TEMP tmp); + predicate(UseZGC && n->as_Load()->barrier_data() != 0); + effect(TEMP dst, TEMP tmp, KILL cr); ins_cost(4 * DEFAULT_COST); @@ -110,11 +111,11 @@ instruct zLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp) %} // Store Pointer -instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2) +instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) %{ - predicate(UseZGC && ZGenerational && n->as_Store()->barrier_data() != 0); + predicate(UseZGC && n->as_Store()->barrier_data() != 0); match(Set mem (StoreP mem src)); - effect(TEMP tmp1, TEMP tmp2); + effect(TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(125); // XXX format %{ "sd $mem, $src\t# ptr" %} @@ -127,11 +128,11 @@ instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2) %} instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, - iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{ + iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res); + predicate(UseZGC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -150,11 +151,11 @@ instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva %} instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, - iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{ + iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res); + predicate(UseZGC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -173,10 +174,10 @@ instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne %} instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, - iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{ + iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{ match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res); + predicate(UseZGC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -195,10 +196,10 @@ instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n %} instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, - iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{ + iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{ match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res); + predicate(UseZGC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -216,10 +217,10 @@ instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg ins_pipe(pipe_slow); %} -instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ +instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set prev (GetAndSetP mem newv)); - predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP_DEF prev, TEMP tmp); + predicate(UseZGC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + effect(TEMP_DEF prev, TEMP tmp, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -234,10 +235,10 @@ instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ ins_pipe(pipe_serial); %} -instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ +instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set prev (GetAndSetP mem newv)); - predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP_DEF prev, TEMP tmp); + predicate(UseZGC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + effect(TEMP_DEF prev, TEMP tmp, KILL cr); ins_cost(2 * VOLATILE_REF_COST); diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index dd31de14704ab..7bd0200f11803 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -112,11 +112,11 @@ define_pd_global(intx, InlineSmallCode, 1000); product(bool, UseZicbom, false, EXPERIMENTAL, "Use Zicbom instructions") \ product(bool, UseZicbop, false, EXPERIMENTAL, "Use Zicbop instructions") \ product(bool, UseZicboz, false, EXPERIMENTAL, "Use Zicboz instructions") \ - product(bool, UseZtso, false, EXPERIMENTAL, "Assume Ztso memory model") \ product(bool, UseZihintpause, false, EXPERIMENTAL, \ "Use Zihintpause instructions") \ + product(bool, UseZtso, false, EXPERIMENTAL, "Assume Ztso memory model") \ product(bool, UseZvbb, false, EXPERIMENTAL, "Use Zvbb instructions") \ - product(bool, UseZvfh, false, EXPERIMENTAL, "Use Zvfh instructions") \ + product(bool, UseZvfh, false, "Use Zvfh instructions") \ product(bool, UseZvkn, false, EXPERIMENTAL, \ "Use Zvkn group extension, Zvkned, Zvknhb, Zvkb, Zvkt") \ product(bool, UseRVVForBigIntegerShiftIntrinsics, true, \ diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index 3eb7abb5ee3b9..f383557e43fc5 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -193,9 +193,7 @@ void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp(Register reg, i void InterpreterMacroAssembler::get_dispatch() { ExternalAddress target((address)Interpreter::dispatch_table()); relocate(target.rspec(), [&] { - int32_t offset; - la(xdispatch, target.target(), offset); - addi(xdispatch, xdispatch, offset); + la(xdispatch, target.target()); }); } @@ -421,13 +419,13 @@ void InterpreterMacroAssembler::jump_from_interpreted(Register method) { // interp_only_mode if these events CAN be enabled. lwu(t0, Address(xthread, JavaThread::interp_only_mode_offset())); beqz(t0, run_compiled_code); - ld(t0, Address(method, Method::interpreter_entry_offset())); - jr(t0); + ld(t1, Address(method, Method::interpreter_entry_offset())); + jr(t1); bind(run_compiled_code); } - ld(t0, Address(method, Method::from_interpreted_offset())); - jr(t0); + ld(t1, Address(method, Method::from_interpreted_offset())); + jr(t1); } // The following two routines provide a hook so that an implementation diff --git a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp index f7d702c631069..2b4a8b87e5404 100644 --- a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp +++ b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp @@ -75,9 +75,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { Address target(SafepointSynchronize::safepoint_counter_addr()); __ relocate(target.rspec(), [&] { - int32_t offset; - __ la(rcounter_addr, target.target(), offset); - __ addi(rcounter_addr, rcounter_addr, offset); + __ la(rcounter_addr, target.target()); }); Label slow; diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b99ba542423a1..b58590e790fac 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -454,12 +454,7 @@ void MacroAssembler::call_VM_base(Register oop_result, ld(t0, Address(java_thread, in_bytes(Thread::pending_exception_offset()))); Label ok; beqz(t0, ok); - RuntimeAddress target(StubRoutines::forward_exception_entry()); - relocate(target.rspec(), [&] { - int32_t offset; - la(t0, target.target(), offset); - jr(t0, offset); - }); + j(RuntimeAddress(StubRoutines::forward_exception_entry())); bind(ok); } @@ -493,6 +488,7 @@ void MacroAssembler::clinit_barrier(Register klass, Register tmp, Label* L_fast_ // Fast path check: class is fully initialized lbu(tmp, Address(klass, InstanceKlass::init_state_offset())); + membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); sub(tmp, tmp, InstanceKlass::fully_initialized); beqz(tmp, *L_fast_path); @@ -534,7 +530,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, movptr(t0, (address) b); } - // call indirectly to solve generation ordering problem + // Call indirectly to solve generation ordering problem RuntimeAddress target(StubRoutines::verify_oop_subroutine_entry_address()); relocate(target.rspec(), [&] { int32_t offset; @@ -579,7 +575,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f movptr(t0, (address) b); } - // call indirectly to solve generation ordering problem + // Call indirectly to solve generation ordering problem RuntimeAddress target(StubRoutines::verify_oop_subroutine_entry_address()); relocate(target.rspec(), [&] { int32_t offset; @@ -759,21 +755,21 @@ void MacroAssembler::emit_static_call_stub() { // Jump to the entry point of the c2i stub. int32_t offset = 0; - movptr(t0, 0, offset, t1); // lui + lui + slli + add - jr(t0, offset); + movptr(t1, 0, offset, t0); // lui + lui + slli + add + jr(t1, offset); } void MacroAssembler::call_VM_leaf_base(address entry_point, int number_of_arguments, Label *retaddr) { int32_t offset = 0; - push_reg(RegSet::of(t0, xmethod), sp); // push << t0 & xmethod >> to sp - mv(t0, entry_point, offset); - jalr(t0, offset); + push_reg(RegSet::of(t1, xmethod), sp); // push << t1 & xmethod >> to sp + mv(t1, entry_point, offset); + jalr(t1, offset); if (retaddr != nullptr) { bind(*retaddr); } - pop_reg(RegSet::of(t0, xmethod), sp); // pop << t0 & xmethod >> from sp + pop_reg(RegSet::of(t1, xmethod), sp); // pop << t1 & xmethod >> from sp } void MacroAssembler::call_VM_leaf(address entry_point, int number_of_arguments) { @@ -940,6 +936,7 @@ void MacroAssembler::li(Register Rd, int64_t imm) { void MacroAssembler::load_link_jump(const address source, Register temp) { assert(temp != noreg && temp != x0, "expecting a register"); + assert(temp != x5, "temp register must not be x5."); assert_cond(source != nullptr); int64_t distance = source - pc(); assert(is_simm32(distance), "Must be"); @@ -967,24 +964,27 @@ void MacroAssembler::j(const address dest, Register temp) { if (is_simm21(distance) && ((distance % 2) == 0)) { Assembler::jal(x0, distance); } else { - assert(temp != noreg && temp != x0, "expecting a register"); + assert(temp != noreg && temp != x0, "Expecting a register"); + assert(temp != x1 && temp != x5, "temp register must not be x1/x5."); int32_t offset = 0; la(temp, dest, offset); jr(temp, offset); } } -void MacroAssembler::j(const Address &adr, Register temp) { - switch (adr.getMode()) { +void MacroAssembler::j(const Address &dest, Register temp) { + switch (dest.getMode()) { case Address::literal: { - relocate(adr.rspec(), [&] { - j(adr.target(), temp); + relocate(dest.rspec(), [&] { + int32_t offset; + la(temp, dest.target(), offset); + jr(temp, offset); }); break; } case Address::base_plus_offset: { - int32_t offset = ((int32_t)adr.offset() << 20) >> 20; - la(temp, Address(adr.base(), adr.offset() - offset)); + int32_t offset = ((int32_t)dest.offset() << 20) >> 20; + la(temp, Address(dest.base(), dest.offset() - offset)); jr(temp, offset); break; } @@ -1005,12 +1005,14 @@ void MacroAssembler::j(Label &lab, Register temp) { void MacroAssembler::jr(Register Rd, int32_t offset) { assert(Rd != noreg, "expecting a register"); + assert(Rd != x1 && Rd != x5, "Rd register must not be x1/x5."); Assembler::jalr(x0, Rd, offset); } void MacroAssembler::call(const address dest, Register temp) { assert_cond(dest != nullptr); assert(temp != noreg, "expecting a register"); + assert(temp != x5, "temp register must not be x5."); int32_t offset = 0; la(temp, dest, offset); jalr(temp, offset); @@ -1018,10 +1020,12 @@ void MacroAssembler::call(const address dest, Register temp) { void MacroAssembler::jalr(Register Rs, int32_t offset) { assert(Rs != noreg, "expecting a register"); + assert(Rs != x5, "Rs register must not be x5."); Assembler::jalr(x1, Rs, offset); } void MacroAssembler::rt_call(address dest, Register tmp) { + assert(tmp != x5, "tmp register must not be x5."); CodeBlob *cb = CodeCache::find_blob(dest); RuntimeAddress target(dest); if (cb) { @@ -1761,7 +1765,7 @@ void MacroAssembler::pop_CPU_state(bool restore_vectors, int vector_size_in_byte static int patch_offset_in_jal(address branch, int64_t offset) { assert(Assembler::is_simm21(offset) && ((offset % 2) == 0), - "offset is too large to be patched in one jal instruction!\n"); + "offset (%ld) is too large to be patched in one jal instruction!\n", offset); Assembler::patch(branch, 31, 31, (offset >> 20) & 0x1); // offset[20] ==> branch[31] Assembler::patch(branch, 30, 21, (offset >> 1) & 0x3ff); // offset[10:1] ==> branch[30:21] Assembler::patch(branch, 20, 20, (offset >> 11) & 0x1); // offset[11] ==> branch[20] @@ -2565,27 +2569,6 @@ void MacroAssembler::bang_stack_size(Register size, Register tmp) { } } -SkipIfEqual::SkipIfEqual(MacroAssembler* masm, const bool* flag_addr, bool value) { - int32_t offset = 0; - _masm = masm; - ExternalAddress target((address)flag_addr); - _masm->relocate(target.rspec(), [&] { - int32_t offset; - _masm->la(t0, target.target(), offset); - _masm->lbu(t0, Address(t0, offset)); - }); - if (value) { - _masm->bnez(t0, _label); - } else { - _masm->beqz(t0, _label); - } -} - -SkipIfEqual::~SkipIfEqual() { - _masm->bind(_label); - _masm = nullptr; -} - void MacroAssembler::load_mirror(Register dst, Register method, Register tmp1, Register tmp2) { const int mirror_offset = in_bytes(Klass::java_mirror_offset()); ld(dst, Address(xmethod, Method::const_offset())); @@ -2947,7 +2930,7 @@ int MacroAssembler::corrected_idivq(Register result, Register rs1, Register rs2, return idivq_offset; } -// Look up the method for a megamorpic invkkeinterface call. +// Look up the method for a megamorphic invokeinterface call. // The target method is determined by . // The receiver klass is in recv_klass. // On success, the result will be in method_result, and execution falls through. @@ -2962,9 +2945,9 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, assert_different_registers(recv_klass, intf_klass, scan_tmp); assert_different_registers(method_result, intf_klass, scan_tmp); assert(recv_klass != method_result || !return_method, - "recv_klass can be destroyed when mehtid isn't needed"); + "recv_klass can be destroyed when method isn't needed"); assert(itable_index.is_constant() || itable_index.as_register() == method_result, - "caller must be same register for non-constant itable index as for method"); + "caller must use same register for non-constant itable index as for method"); // Compute start of first itableOffsetEntry (which is at the end of the vtable). int vtable_base = in_bytes(Klass::vtable_start_offset()); @@ -3657,6 +3640,7 @@ void MacroAssembler::far_jump(const Address &entry, Register tmp) { } void MacroAssembler::far_call(const Address &entry, Register tmp) { + assert(tmp != x5, "tmp register must not be x5."); assert(CodeCache::find_blob(entry.target()) != nullptr, "destination of far call not found in code cache"); assert(entry.rspec().type() == relocInfo::external_word_type @@ -4071,7 +4055,7 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, Register tmp1, Register tmp2, Register tmp3) { - assert_different_registers(r_sub_klass, r_super_klass, tmp1, tmp2, tmp3, result, t0); + assert_different_registers(r_sub_klass, r_super_klass, tmp1, tmp2, tmp3, result, t0, t1); const Register r_array_base = tmp1, // X11 @@ -4138,8 +4122,8 @@ void MacroAssembler::get_thread(Register thread) { RegSet::range(x28, x31) + ra - thread; push_reg(saved_regs, sp); - mv(ra, CAST_FROM_FN_PTR(address, Thread::current)); - jalr(ra); + mv(t1, CAST_FROM_FN_PTR(address, Thread::current)); + jalr(t1); if (thread != c_rarg0) { mv(thread, c_rarg0); } @@ -4186,8 +4170,7 @@ void MacroAssembler::reserved_stack_check() { // We have already removed our own frame. // throw_delayed_StackOverflowError will think that it's been // called by our caller. - la(t0, RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry())); - jr(t0); + j(RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry())); should_not_reach_here(); bind(no_reserved_zone_enabling); @@ -4206,7 +4189,7 @@ void MacroAssembler::read_polling_page(Register r, int32_t offset, relocInfo::re }); } -void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { +void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { #ifdef ASSERT { ThreadInVMfromUnknown tiv; @@ -4298,7 +4281,7 @@ address MacroAssembler::load_and_call(Address entry) { } #endif relocate(entry.rspec(), [&] { - load_link_jump(target); + load_link_jump(target, t1); }); postcond(pc() != badAddress); @@ -4308,7 +4291,7 @@ address MacroAssembler::load_and_call(Address entry) { address MacroAssembler::ic_call(address entry, jint method_index) { RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); IncompressibleRegion ir(this); // relocations - movptr(t1, (address)Universe::non_oop_word(), t0); + movptr(t0, (address)Universe::non_oop_word(), t1); assert_cond(entry != nullptr); return reloc_call(Address(entry, rh)); } @@ -4322,9 +4305,9 @@ int MacroAssembler::ic_check_size() { int MacroAssembler::ic_check(int end_alignment) { IncompressibleRegion ir(this); Register receiver = j_rarg0; - Register data = t1; + Register data = t0; - Register tmp1 = t0; // t0 always scratch + Register tmp1 = t1; // scratch // t2 is saved on call, thus should have been saved before this check. // Hence we can clobber it. Register tmp2 = t2; @@ -4422,8 +4405,8 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, // - load the call // - call Label target; - ld(t0, target); // auipc + ld - jr(t0); // jalr + ld(t1, target); // auipc + ld + jr(t1); // jalr bind(target); assert(offset() - stub_start_offset == MacroAssembler::NativeShortCall::trampoline_data_offset, "should be"); @@ -4507,14 +4490,15 @@ void MacroAssembler::decrementw(const Address dst, int32_t value, Register tmp1, sw(tmp1, adr); } -void MacroAssembler::cmpptr(Register src1, Address src2, Label& equal) { - assert_different_registers(src1, t0); +void MacroAssembler::cmpptr(Register src1, const Address &src2, Label& equal, Register tmp) { + assert_different_registers(src1, tmp); + assert(src2.getMode() == Address::literal, "must be applied to a literal address"); relocate(src2.rspec(), [&] { int32_t offset; - la(t0, src2.target(), offset); - ld(t0, Address(t0, offset)); + la(tmp, src2.target(), offset); + ld(tmp, Address(tmp, offset)); }); - beq(src1, t0, equal); + beq(src1, tmp, equal); } void MacroAssembler::load_method_holder_cld(Register result, Register method) { @@ -5147,11 +5131,11 @@ const int MacroAssembler::zero_words_block_size = 8; // ptr: Address of a buffer to be zeroed. // cnt: Count in HeapWords. // -// ptr, cnt, and t0 are clobbered. +// ptr, cnt, t1, and t0 are clobbered. address MacroAssembler::zero_words(Register ptr, Register cnt) { assert(is_power_of_2(zero_words_block_size), "adjust this"); assert(ptr == x28 && cnt == x29, "mismatch in register usage"); - assert_different_registers(cnt, t0); + assert_different_registers(cnt, t0, t1); BLOCK_COMMENT("zero_words {"); @@ -5169,6 +5153,7 @@ address MacroAssembler::zero_words(Register ptr, Register cnt) { return nullptr; } } else { + // Clobbers t1 rt_call(zero_blocks.target()); } } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index fd174f241eb0b..b248db3993379 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -627,7 +627,7 @@ class MacroAssembler: public Assembler { void bgtz(Register Rs, const address dest); private: - void load_link_jump(const address source, Register temp = t0); + void load_link_jump(const address source, Register temp); void jump_link(const address dest, Register temp); public: // We try to follow risc-v asm menomics. @@ -635,18 +635,42 @@ class MacroAssembler: public Assembler { // we often need to resort to movptr, li <48imm>. // https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md + // Hotspot only use the standard calling convention using x1/ra. + // The alternative calling convection using x5/t0 is not used. + // Using x5 as a temp causes the CPU to mispredict returns. + + // JALR, return address stack updates: + // | rd is x1/x5 | rs1 is x1/x5 | rd=rs1 | RAS action + // | ----------- | ------------ | ------ |------------- + // | No | No | — | None + // | No | Yes | — | Pop + // | Yes | No | — | Push + // | Yes | Yes | No | Pop, then push + // | Yes | Yes | Yes | Push + // + // JAL, return address stack updates: + // | rd is x1/x5 | RAS action + // | ----------- | ---------- + // | Yes | Push + // | No | None + // + // JUMPs uses Rd = x0/zero and Rs = x6/t1 or imm + // CALLS uses Rd = x1/ra and Rs = x6/t1 or imm (or x1/ra*) + // RETURNS uses Rd = x0/zero and Rs = x1/ra + // *use of x1/ra should not normally be used, special case only. + // jump: jal x0, offset // For long reach uses temp register for: // la + jr - void j(const address dest, Register temp = t0); - void j(const Address &adr, Register temp = t0); - void j(Label &l, Register temp = t0); + void j(const address dest, Register temp = t1); + void j(const Address &dest, Register temp = t1); + void j(Label &l, Register temp = noreg); // jump register: jalr x0, offset(rs) void jr(Register Rd, int32_t offset = 0); // call: la + jalr x1 - void call(const address dest, Register temp = t0); + void call(const address dest, Register temp = t1); // jalr: jalr x1, offset(rs) void jalr(Register Rs, int32_t offset = 0); @@ -654,7 +678,8 @@ class MacroAssembler: public Assembler { // Emit a runtime call. Only invalidates the tmp register which // is used to keep the entry address for jalr/movptr. // Uses call() for intra code cache, else movptr + jalr. - void rt_call(address dest, Register tmp = t0); + // Clobebrs t1 + void rt_call(address dest, Register tmp = t1); // ret: jalr x0, 0(x1) inline void ret() { @@ -1165,8 +1190,9 @@ class MacroAssembler: public Assembler { // - relocInfo::external_word_type // - relocInfo::runtime_call_type // - relocInfo::none - void far_call(const Address &entry, Register tmp = t0); - void far_jump(const Address &entry, Register tmp = t0); + // Clobbers t1 default. + void far_call(const Address &entry, Register tmp = t1); + void far_jump(const Address &entry, Register tmp = t1); static int far_branch_size() { return 2 * 4; // auipc + jalr, see far_call() & far_jump() @@ -1301,7 +1327,7 @@ class MacroAssembler: public Assembler { void decrement(const Address dst, int64_t value = 1, Register tmp1 = t0, Register tmp2 = t1); void decrementw(const Address dst, int32_t value = 1, Register tmp1 = t0, Register tmp2 = t1); - void cmpptr(Register src1, Address src2, Label& equal); + void cmpptr(Register src1, const Address &src2, Label& equal, Register tmp = t0); void clinit_barrier(Register klass, Register tmp, Label* L_fast_path = nullptr, Label* L_slow_path = nullptr); void load_method_holder_cld(Register result, Register method); @@ -1768,22 +1794,4 @@ class MacroAssembler: public Assembler { inline bool AbstractAssembler::pd_check_instruction_mark() { return false; } #endif -/** - * class SkipIfEqual: - * - * Instantiating this class will result in assembly code being output that will - * jump around any code emitted between the creation of the instance and it's - * automatic destruction at the end of a scope block, depending on the value of - * the flag passed to the constructor, which will be checked at run-time. - */ -class SkipIfEqual { - private: - MacroAssembler* _masm; - Label _label; - - public: - SkipIfEqual(MacroAssembler*, const bool* flag_addr, bool value); - ~SkipIfEqual(); -}; - #endif // CPU_RISCV_MACROASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp index deeb771d83bb8..8ed4b93ad4de9 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.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, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,6 +28,7 @@ #include "asm/macroAssembler.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/vmClasses.hpp" +#include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "memory/allocation.inline.hpp" @@ -37,7 +38,7 @@ #include "runtime/frame.inline.hpp" #include "runtime/stubRoutines.hpp" -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -108,17 +109,17 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth // compiled code in threads for which the event is enabled. Check here for // interp_only_mode if these events CAN be enabled. - __ lwu(t0, Address(xthread, JavaThread::interp_only_mode_offset())); - __ beqz(t0, run_compiled_code); - __ ld(t0, Address(method, Method::interpreter_entry_offset())); - __ jr(t0); + __ lwu(t1, Address(xthread, JavaThread::interp_only_mode_offset())); + __ beqz(t1, run_compiled_code); + __ ld(t1, Address(method, Method::interpreter_entry_offset())); + __ jr(t1); __ BIND(run_compiled_code); } const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : Method::from_interpreted_offset(); - __ ld(t0,Address(method, entry_offset)); - __ jr(t0); + __ ld(t1, Address(method, entry_offset)); + __ jr(t1); __ bind(L_no_such_method); __ far_jump(RuntimeAddress(SharedRuntime::throw_AbstractMethodError_entry())); } @@ -444,7 +445,6 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); } } - } #ifndef PRODUCT diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index 6c9e0986869b6..988a5b7933224 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -91,10 +91,10 @@ bool NativeShortCallTrampolineStub::is_at(address addr) { if (MacroAssembler::is_auipc_at(addr) && MacroAssembler::is_ld_at(addr + instr_size) && MacroAssembler::is_jalr_at(addr + 2 * instr_size) && - (MacroAssembler::extract_rd(addr) == x5) && - (MacroAssembler::extract_rd(addr + instr_size) == x5) && - (MacroAssembler::extract_rs1(addr + instr_size) == x5) && - (MacroAssembler::extract_rs1(addr + 2 * instr_size) == x5) && + (MacroAssembler::extract_rd(addr) == x6) && + (MacroAssembler::extract_rd(addr + instr_size) == x6) && + (MacroAssembler::extract_rs1(addr + instr_size) == x6) && + (MacroAssembler::extract_rs1(addr + 2 * instr_size) == x6) && (Assembler::extract(Assembler::ld_instr(addr + 4), 31, 20) == trampoline_data_offset)) { return true; } @@ -215,10 +215,10 @@ void NativeShortCall::print() { // 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. +// during code generation, where no lock is needed. bool NativeShortCall::set_destination_mt_safe(address dest, bool assert_lock) { assert(!assert_lock || - (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || + (CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(instruction_address()), "concurrent code patching"); @@ -386,7 +386,7 @@ void NativeFarCall::print() { bool NativeFarCall::set_destination_mt_safe(address dest, bool assert_lock) { assert(NativeFarCall::is_at(addr_at(0)), "unexpected code at call site"); assert(!assert_lock || - (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || + (CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); @@ -460,10 +460,10 @@ bool NativeFarCall::is_at(address addr) { if (MacroAssembler::is_auipc_at(addr) && MacroAssembler::is_ld_at(addr + instr_size) && MacroAssembler::is_jalr_at(addr + 2 * instr_size) && - (MacroAssembler::extract_rd(addr) == x5) && - (MacroAssembler::extract_rd(addr + instr_size) == x5) && - (MacroAssembler::extract_rs1(addr + instr_size) == x5) && - (MacroAssembler::extract_rs1(addr + 2 * instr_size) == x5) && + (MacroAssembler::extract_rd(addr) == x6) && + (MacroAssembler::extract_rd(addr + instr_size) == x6) && + (MacroAssembler::extract_rs1(addr + instr_size) == x6) && + (MacroAssembler::extract_rs1(addr + 2 * instr_size) == x6) && (MacroAssembler::extract_rd(addr + 2 * instr_size) == x1)) { return true; } @@ -789,8 +789,8 @@ void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { Assembler::IncompressibleRegion ir(&a); // Fixed length: see NativeGeneralJump::get_instruction_size() int32_t offset = 0; - a.movptr(t0, entry, offset, t1); // lui, lui, slli, add - a.jr(t0, offset); // jalr + a.movptr(t1, entry, offset, t0); // lui, lui, slli, add + a.jr(t1, offset); // jalr ICache::invalidate_range(code_pos, instruction_size); } diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 05f55fd0da7af..864bfddef4caa 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1259,13 +1259,13 @@ int MachCallRuntimeNode::ret_addr_offset() { // jal(addr) // or with far branches // jal(trampoline_stub) - // for real runtime callouts it will be 11 instructions + // for real runtime callouts it will be 9 instructions // see riscv_enc_java_to_runtime - // la(t1, retaddr) -> auipc + addi - // la(t0, RuntimeAddress(addr)) -> lui + addi + slli + addi + slli + addi + // la(t0, retaddr) -> auipc + addi // addi(sp, sp, -2 * wordSize) -> addi - // sd(t1, Address(sp, wordSize)) -> sd - // jalr(t0) -> jalr + // sd(t0, Address(sp, wordSize)) -> sd + // movptr(t1, addr, offset, t0) -> lui + lui + slli + add + // jalr(t1, offset) -> jalr CodeBlob *cb = CodeCache::find_blob(_entry_point); if (cb != nullptr) { if (UseTrampolines) { @@ -1273,7 +1273,7 @@ int MachCallRuntimeNode::ret_addr_offset() { } return 3 * NativeInstruction::instruction_size; } else { - return 11 * NativeInstruction::instruction_size; + return 9 * NativeInstruction::instruction_size; } } @@ -1822,13 +1822,13 @@ void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const assert_cond(st != nullptr); st->print_cr("# MachUEPNode"); if (UseCompressedClassPointers) { - st->print_cr("\tlwu t0, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tlwu t2, [t1 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); + st->print_cr("\tlwu t1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tlwu t2, [t0 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); } else { - st->print_cr("\tld t0, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tld t2, [t1 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); + st->print_cr("\tld t1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tld t2, [t0 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); } - st->print_cr("\tbeq t0, t2, ic_hit"); + st->print_cr("\tbeq t1, t2, ic_hit"); st->print_cr("\tj, SharedRuntime::_ic_miss_stub\t # Inline cache check"); st->print_cr("\tic_hit:"); } @@ -1857,8 +1857,8 @@ uint MachUEPNode::size(PhaseRegAlloc* ra_) const // Emit exception handler code. int HandlerImpl::emit_exception_handler(C2_MacroAssembler* masm) { - // auipc t0, #exception_blob_entry_point - // jr (offset)t0 + // auipc t1, #exception_blob_entry_point + // jr (offset)t1 // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a handler. address base = __ start_a_stub(size_exception_handler()); @@ -1966,18 +1966,18 @@ const RegMask* Matcher::predicate_reg_mask(void) { return &_VMASK_REG_mask; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return new TypeVectMask(elemTy, length); -} - // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { - return false; + return EnableVectorSupport && UseVectorStubs; } OptoRegPair Matcher::vector_return_value(uint ideal_reg) { - Unimplemented(); - return OptoRegPair(0, 0); + assert(EnableVectorSupport && UseVectorStubs, "sanity"); + assert(ideal_reg == Op_VecA, "sanity"); + // check more info at https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc + int lo = V8_num; + int hi = V8_K_num; + return OptoRegPair(hi, lo); } // Is this branch offset short enough that a short branch can be used? @@ -2224,7 +2224,8 @@ bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { assert_cond(m != nullptr); if (is_vshift_con_pattern(n, m) || // ShiftV src (ShiftCntV con) is_vector_bitwise_not_pattern(n, m) || - is_vector_scalar_bitwise_pattern(n, m)) { + is_vector_scalar_bitwise_pattern(n, m) || + is_encode_and_store_pattern(n, m)) { mstack.push(m, Visit); return true; } @@ -2503,12 +2504,14 @@ encode %{ __ post_call_nop(); } else { Label retaddr; - __ la(t1, retaddr); - __ la(t0, RuntimeAddress(entry)); + __ la(t0, retaddr); // Leave a breadcrumb for JavaFrameAnchor::capture_last_Java_pc() __ addi(sp, sp, -2 * wordSize); - __ sd(t1, Address(sp, wordSize)); - __ jalr(t0); + __ sd(t0, Address(sp, wordSize)); + int32_t offset = 0; + // No relocation needed + __ movptr(t1, entry, offset, t0); // lui + lui + slli + add + __ jalr(t1, offset); __ bind(retaddr); __ post_call_nop(); __ addi(sp, sp, 2 * wordSize); @@ -4785,6 +4788,7 @@ instruct loadP(iRegPNoSp dst, memory mem) // Load Compressed Pointer instruct loadN(iRegNNoSp dst, memory mem) %{ + predicate(n->as_Load()->barrier_data() == 0); match(Set dst (LoadN mem)); ins_cost(LOAD_COST); @@ -5033,41 +5037,6 @@ instruct loadConD0(fRegD dst, immD0 con) %{ ins_pipe(fp_load_constant_d); %} -// Store Instructions -// Store CMS card-mark Immediate -instruct storeimmCM0(immI0 zero, memory mem) -%{ - match(Set mem (StoreCM mem zero)); - - ins_cost(STORE_COST); - format %{ "storestore (elided)\n\t" - "sb zr, $mem\t# byte, #@storeimmCM0" %} - - ins_encode %{ - __ sb(zr, Address(as_Register($mem$$base), $mem$$disp)); - %} - - ins_pipe(istore_mem); -%} - -// Store CMS card-mark Immediate with intervening StoreStore -// needed when using CMS with no conditional card marking -instruct storeimmCM0_ordered(immI0 zero, memory mem) -%{ - match(Set mem (StoreCM mem zero)); - - ins_cost(ALU_COST + STORE_COST); - format %{ "membar(StoreStore)\n\t" - "sb zr, $mem\t# byte, #@storeimmCM0_ordered" %} - - ins_encode %{ - __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - __ sb(zr, Address(as_Register($mem$$base), $mem$$disp)); - %} - - ins_pipe(istore_mem); -%} - // Store Byte instruct storeB(iRegIorL2I src, memory mem) %{ @@ -5220,6 +5189,7 @@ instruct storeimmP0(immP0 zero, memory mem) // Store Compressed Pointer instruct storeN(iRegN src, memory mem) %{ + predicate(n->as_Store()->barrier_data() == 0); match(Set mem (StoreN mem src)); ins_cost(STORE_COST); @@ -5234,6 +5204,7 @@ instruct storeN(iRegN src, memory mem) instruct storeImmN0(immN0 zero, memory mem) %{ + predicate(n->as_Store()->barrier_data() == 0); match(Set mem (StoreN mem zero)); ins_cost(STORE_COST); @@ -5424,6 +5395,7 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndSwapN mem (Binary oldval newval))); ins_cost(LOAD_COST + STORE_COST + ALU_COST * 8 + BRANCH_COST * 4); @@ -5545,7 +5517,7 @@ instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP new instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndSwapN mem (Binary oldval newval))); @@ -5653,6 +5625,7 @@ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL ne instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 3); @@ -5786,7 +5759,7 @@ instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); @@ -5914,6 +5887,7 @@ instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL ne instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 4); @@ -6045,7 +6019,7 @@ instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); @@ -6117,6 +6091,8 @@ instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set prev (GetAndSetN mem newv)); ins_cost(ALU_COST); @@ -6182,7 +6158,7 @@ instruct get_and_setLAcq(indirect mem, iRegL newv, iRegLNoSp prev) instruct get_and_setNAcq(indirect mem, iRegN newv, iRegINoSp prev) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0); match(Set prev (GetAndSetN mem newv)); @@ -10015,11 +9991,11 @@ instruct CallStaticJavaDirect(method meth) // Call Java Dynamic Instruction // Note: If this code changes, the corresponding ret_addr_offset() and // compute_padding() functions will have to be adjusted. -instruct CallDynamicJavaDirect(method meth, rFlagsReg cr) +instruct CallDynamicJavaDirect(method meth) %{ match(CallDynamicJava); - effect(USE meth, KILL cr); + effect(USE meth); ins_cost(BRANCH_COST + ALU_COST * 5); @@ -10034,11 +10010,11 @@ instruct CallDynamicJavaDirect(method meth, rFlagsReg cr) // Call Runtime Instruction -instruct CallRuntimeDirect(method meth, rFlagsReg cr) +instruct CallRuntimeDirect(method meth) %{ match(CallRuntime); - effect(USE meth, KILL cr); + effect(USE meth); ins_cost(BRANCH_COST); @@ -10051,11 +10027,11 @@ instruct CallRuntimeDirect(method meth, rFlagsReg cr) // Call Runtime Instruction -instruct CallLeafDirect(method meth, rFlagsReg cr) +instruct CallLeafDirect(method meth) %{ match(CallLeaf); - effect(USE meth, KILL cr); + effect(USE meth); ins_cost(BRANCH_COST); @@ -10066,13 +10042,30 @@ instruct CallLeafDirect(method meth, rFlagsReg cr) ins_pipe(pipe_class_call); %} +// Call Runtime Instruction without safepoint and with vector arguments + +instruct CallLeafDirectVector(method meth) +%{ + match(CallLeafVector); + + effect(USE meth); + + ins_cost(BRANCH_COST); + + format %{ "CALL, runtime leaf vector $meth" %} + + ins_encode(riscv_enc_java_to_runtime(meth)); + + ins_pipe(pipe_class_call); +%} + // Call Runtime Instruction -instruct CallLeafNoFPDirect(method meth, rFlagsReg cr) +instruct CallLeafNoFPDirect(method meth) %{ match(CallLeafNoFP); - effect(USE meth, KILL cr); + effect(USE meth); ins_cost(BRANCH_COST); @@ -10107,11 +10100,11 @@ instruct partialSubtypeCheck(iRegP_R15 result, iRegP_R14 sub, iRegP_R10 super, i %} instruct partialSubtypeCheckConstSuper(iRegP_R14 sub, iRegP_R10 super_reg, immP super_con, iRegP_R15 result, - iRegP_R11 tmpR11, iRegP_R12 tmpR12, iRegP_R13 tmpR13, iRegP_R16 tmpR16) + iRegP_R11 tmpR11, iRegP_R12 tmpR12, iRegP_R13 tmpR13, iRegP_R16 tmpR16, rFlagsReg cr) %{ predicate(UseSecondarySupersTable); match(Set result (PartialSubtypeCheck sub (Binary super_reg super_con))); - effect(TEMP tmpR11, TEMP tmpR12, TEMP tmpR13, TEMP tmpR16); + effect(TEMP tmpR11, TEMP tmpR12, TEMP tmpR13, TEMP tmpR16, KILL cr); ins_cost(7 * DEFAULT_COST); // needs to be less than competing nodes format %{ "partialSubtypeCheck $result, $sub, $super_reg, $super_con" %} @@ -10388,12 +10381,12 @@ instruct stringL_indexof_char(iRegP_R11 str1, iRegI_R12 cnt1, iRegI_R13 ch, // clearing of an array instruct clearArray_reg_reg(iRegL_R29 cnt, iRegP_R28 base, iRegP_R30 tmp1, - iRegP_R31 tmp2, Universe dummy) + iRegP_R31 tmp2, rFlagsReg cr, Universe dummy) %{ // temp registers must match the one used in StubGenerator::generate_zero_blocks() predicate(UseBlockZeroing || !UseRVV); match(Set dummy (ClearArray cnt base)); - effect(USE_KILL cnt, USE_KILL base, TEMP tmp1, TEMP tmp2); + effect(USE_KILL cnt, USE_KILL base, TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(4 * DEFAULT_COST); format %{ "ClearArray $cnt, $base\t#@clearArray_reg_reg" %} diff --git a/src/hotspot/cpu/riscv/runtime_riscv.cpp b/src/hotspot/cpu/riscv/runtime_riscv.cpp index 9e16278c3b547..2f879b07e2694 100644 --- a/src/hotspot/cpu/riscv/runtime_riscv.cpp +++ b/src/hotspot/cpu/riscv/runtime_riscv.cpp @@ -351,7 +351,7 @@ void OptoRuntime::generate_exception_blob() { // x10: exception handler // We have a handler in x10 (could be deopt blob). - __ mv(t0, x10); + __ mv(t1, x10); // Get the exception oop __ ld(x10, Address(xthread, JavaThread::exception_oop_offset())); @@ -365,11 +365,11 @@ void OptoRuntime::generate_exception_blob() { __ sd(zr, Address(xthread, JavaThread::exception_oop_offset())); // x10: exception oop - // t0: exception handler + // t1: exception handler // x14: exception pc // Jump to handler - __ jr(t0); + __ jr(t1); // Make sure all code is generated masm->flush(); diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 27da26d404cc0..29c96112eada8 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -468,8 +468,8 @@ static void gen_c2i_adapter(MacroAssembler *masm, __ mv(esp, sp); // Interp expects args on caller's expression stack - __ ld(t0, Address(xmethod, in_bytes(Method::interpreter_entry_offset()))); - __ jr(t0); + __ ld(t1, Address(xmethod, in_bytes(Method::interpreter_entry_offset()))); + __ jr(t1); } void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, @@ -610,8 +610,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm Label skip_fixup; const Register receiver = j_rarg0; - const Register data = t1; - const Register tmp = t2; // A call-clobbered register not used for arg passing + const Register data = t0; // ------------------------------------------------------------------------- // Generate a C2I adapter. On entry we know xmethod holds the Method* during calls @@ -666,7 +665,20 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm int SharedRuntime::vector_calling_convention(VMRegPair *regs, uint num_bits, uint total_args_passed) { - Unimplemented(); + assert(total_args_passed <= Argument::n_vector_register_parameters_c, "unsupported"); + assert(num_bits >= 64 && num_bits <= 2048 && is_power_of_2(num_bits), "unsupported"); + + // check more info at https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc + static const VectorRegister VEC_ArgReg[Argument::n_vector_register_parameters_c] = { + v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23 + }; + + const int next_reg_val = 3; + for (uint i = 0; i < total_args_passed; i++) { + VMReg vmreg = VEC_ArgReg[i]->as_VMReg(); + regs[i].set_pair(vmreg->next(next_reg_val), vmreg); + } return 0; } @@ -1127,8 +1139,7 @@ static void gen_continuation_yield(MacroAssembler* masm, Label ok; __ beqz(t0, ok); __ leave(); - __ la(t0, RuntimeAddress(StubRoutines::forward_exception_entry())); - __ jr(t0); + __ j(RuntimeAddress(StubRoutines::forward_exception_entry())); __ bind(ok); __ leave(); @@ -1439,8 +1450,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // restoring them except fp. fp is the only callee save register // as far as the interpreter and the compiler(s) are concerned. - - const Register ic_reg = t1; const Register receiver = j_rarg0; __ verify_oop(receiver); @@ -1724,6 +1733,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); __ sw(t0, Address(t1)); + // Clobbers t1 __ rt_call(native_func); __ bind(native_return); @@ -2606,20 +2616,19 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti __ reset_last_Java_frame(false); // check for pending exceptions Label pending; - __ ld(t0, Address(xthread, Thread::pending_exception_offset())); - __ bnez(t0, pending); + __ ld(t1, Address(xthread, Thread::pending_exception_offset())); + __ bnez(t1, pending); // get the returned Method* __ get_vm_result_2(xmethod, xthread); __ sd(xmethod, Address(sp, reg_saver.reg_offset_in_bytes(xmethod))); - // x10 is where we want to jump, overwrite t0 which is saved and temporary - __ sd(x10, Address(sp, reg_saver.reg_offset_in_bytes(t0))); + // x10 is where we want to jump, overwrite t1 which is saved and temporary + __ sd(x10, Address(sp, reg_saver.reg_offset_in_bytes(t1))); reg_saver.restore_live_registers(masm); // We are back to the original state on entry and ready to go. - - __ jr(t0); + __ jr(t1); // Pending exception after the safepoint diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 5970111088fd1..bce0c8f1f3de7 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -508,7 +508,7 @@ class StubGenerator: public StubCodeGenerator { // complete return to VM assert(StubRoutines::_call_stub_return_address != nullptr, "_call_stub_return_address must have been generated before"); - __ j(StubRoutines::_call_stub_return_address); + __ j(RuntimeAddress(StubRoutines::_call_stub_return_address)); return start; } @@ -946,7 +946,7 @@ class StubGenerator: public StubCodeGenerator { // The size of copy32_loop body increases significantly with ZGC GC barriers. // Need conditional far branches to reach a point beyond the loop in this case. - bool is_far = UseZGC && ZGenerational; + bool is_far = UseZGC; __ beqz(count, done, is_far); __ slli(cnt, count, exact_log2(granularity)); @@ -2276,6 +2276,174 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_arrayof_jint_fill = generate_fill(T_INT, true, "arrayof_jint_fill"); } + void generate_aes_loadkeys(const Register &key, VectorRegister *working_vregs, int rounds) { + const int step = 16; + for (int i = 0; i < rounds; i++) { + __ vle32_v(working_vregs[i], key); + // The keys are stored in little-endian array, while we need + // to operate in big-endian. + // So performing an endian-swap here with vrev8.v instruction + __ vrev8_v(working_vregs[i], working_vregs[i]); + __ addi(key, key, step); + } + } + + void generate_aes_encrypt(const VectorRegister &res, VectorRegister *working_vregs, int rounds) { + assert(rounds <= 15, "rounds should be less than or equal to working_vregs size"); + + __ vxor_vv(res, res, working_vregs[0]); + for (int i = 1; i < rounds - 1; i++) { + __ vaesem_vv(res, working_vregs[i]); + } + __ vaesef_vv(res, working_vregs[rounds - 1]); + } + + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // + address generate_aescrypt_encryptBlock() { + assert(UseAESIntrinsics, "need AES instructions (Zvkned extension) support"); + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "aescrypt_encryptBlock"); + + Label L_aes128, L_aes192; + + const Register from = c_rarg0; // source array address + const Register to = c_rarg1; // destination array address + const Register key = c_rarg2; // key array address + const Register keylen = c_rarg3; + + VectorRegister working_vregs[] = { + v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18 + }; + const VectorRegister res = v19; + + address start = __ pc(); + __ enter(); + + __ lwu(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + + __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); + __ vle32_v(res, from); + + __ mv(t2, 52); + __ blt(keylen, t2, L_aes128); + __ beq(keylen, t2, L_aes192); + // Else we fallthrough to the biggest case (256-bit key size) + + // Note: the following function performs key += 15*16 + generate_aes_loadkeys(key, working_vregs, 15); + generate_aes_encrypt(res, working_vregs, 15); + __ vse32_v(res, to); + __ mv(c_rarg0, 0); + __ leave(); + __ ret(); + + __ bind(L_aes192); + // Note: the following function performs key += 13*16 + generate_aes_loadkeys(key, working_vregs, 13); + generate_aes_encrypt(res, working_vregs, 13); + __ vse32_v(res, to); + __ mv(c_rarg0, 0); + __ leave(); + __ ret(); + + __ bind(L_aes128); + // Note: the following function performs key += 11*16 + generate_aes_loadkeys(key, working_vregs, 11); + generate_aes_encrypt(res, working_vregs, 11); + __ vse32_v(res, to); + __ mv(c_rarg0, 0); + __ leave(); + __ ret(); + + return start; + } + + void generate_aes_decrypt(const VectorRegister &res, VectorRegister *working_vregs, int rounds) { + assert(rounds <= 15, "rounds should be less than or equal to working_vregs size"); + + __ vxor_vv(res, res, working_vregs[rounds - 1]); + for (int i = rounds - 2; i > 0; i--) { + __ vaesdm_vv(res, working_vregs[i]); + } + __ vaesdf_vv(res, working_vregs[0]); + } + + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // + address generate_aescrypt_decryptBlock() { + assert(UseAESIntrinsics, "need AES instructions (Zvkned extension) support"); + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "aescrypt_decryptBlock"); + + Label L_aes128, L_aes192; + + const Register from = c_rarg0; // source array address + const Register to = c_rarg1; // destination array address + const Register key = c_rarg2; // key array address + const Register keylen = c_rarg3; + + VectorRegister working_vregs[] = { + v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18 + }; + const VectorRegister res = v19; + + address start = __ pc(); + __ enter(); // required for proper stackwalking of RuntimeStub frame + + __ lwu(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + + __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); + __ vle32_v(res, from); + + __ mv(t2, 52); + __ blt(keylen, t2, L_aes128); + __ beq(keylen, t2, L_aes192); + // Else we fallthrough to the biggest case (256-bit key size) + + // Note: the following function performs key += 15*16 + generate_aes_loadkeys(key, working_vregs, 15); + generate_aes_decrypt(res, working_vregs, 15); + __ vse32_v(res, to); + __ mv(c_rarg0, 0); + __ leave(); + __ ret(); + + __ bind(L_aes192); + // Note: the following function performs key += 13*16 + generate_aes_loadkeys(key, working_vregs, 13); + generate_aes_decrypt(res, working_vregs, 13); + __ vse32_v(res, to); + __ mv(c_rarg0, 0); + __ leave(); + __ ret(); + + __ bind(L_aes128); + // Note: the following function performs key += 11*16 + generate_aes_loadkeys(key, working_vregs, 11); + generate_aes_decrypt(res, working_vregs, 11); + __ vse32_v(res, to); + __ mv(c_rarg0, 0); + __ leave(); + __ ret(); + + return start; + } + // code for comparing 16 bytes of strings with same encoding void compare_string_16_bytes_same(Label &DIFF1, Label &DIFF2) { const Register result = x10, str1 = x11, cnt1 = x12, str2 = x13, tmp1 = x28, tmp2 = x29, tmp4 = x7, tmp5 = x31; @@ -3782,8 +3950,7 @@ class StubGenerator: public StubCodeGenerator { Label thaw_success; // t1 contains the size of the frames to thaw, 0 if overflow or no more frames __ bnez(t1, thaw_success); - __ la(t0, RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); - __ jr(t0); + __ j(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); __ bind(thaw_success); // make room for the thawed frames @@ -4482,7 +4649,7 @@ class StubGenerator: public StubCodeGenerator { RegSet reg_cache_saved_regs = RegSet::of(x24, x25, x26, x27); // s8, s9, s10, s11 RegSet reg_cache_regs; reg_cache_regs += reg_cache_saved_regs; - reg_cache_regs += RegSet::of(x28, x29, x30, x31); // t3, t4, t5, t6 + reg_cache_regs += RegSet::of(t3, t4, t5, t6); BufRegCache reg_cache(_masm, reg_cache_regs); RegSet saved_regs; @@ -5462,8 +5629,8 @@ class StubGenerator: public StubCodeGenerator { Register isMIME = c_rarg6; Register codec = c_rarg7; - Register dstBackup = x31; - Register length = x28; // t3, total length of src data in bytes + Register dstBackup = t6; + Register length = t3; // total length of src data in bytes Label ProcessData, Exit; Label ProcessScalar, ScalarLoop; @@ -5498,7 +5665,7 @@ class StubGenerator: public StubCodeGenerator { Register stepSrcM1 = send; Register stepSrcM2 = doff; Register stepDst = isURL; - Register size = x29; // t4 + Register size = t4; __ mv(size, MaxVectorSize * 2); __ mv(stepSrcM1, MaxVectorSize * 4); @@ -5550,7 +5717,7 @@ class StubGenerator: public StubCodeGenerator { // scalar version { Register byte0 = soff, byte1 = send, byte2 = doff, byte3 = isURL; - Register combined32Bits = x29; // t5 + Register combined32Bits = t4; // encoded: [byte0[5:0] : byte1[5:0] : byte2[5:0]] : byte3[5:0]] => // plain: [byte0[5:0]+byte1[5:4] : byte1[3:0]+byte2[5:2] : byte2[1:0]+byte3[5:0]] @@ -5708,10 +5875,10 @@ class StubGenerator: public StubCodeGenerator { Register nmax = c_rarg4; Register base = c_rarg5; Register count = c_rarg6; - Register temp0 = x28; // t3 - Register temp1 = x29; // t4 - Register temp2 = x30; // t5 - Register temp3 = x31; // t6 + Register temp0 = t3; + Register temp1 = t4; + Register temp2 = t5; + Register temp3 = t6; VectorRegister vzero = v31; VectorRegister vbytes = v8; // group: v8, v9, v10, v11 @@ -6071,6 +6238,58 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } + void generate_vector_math_stubs() { + if (!UseRVV) { + log_info(library)("vector is not supported, skip loading vector math (sleef) library!"); + return; + } + + // Get native vector math stub routine addresses + void* libsleef = nullptr; + char ebuf[1024]; + char dll_name[JVM_MAXPATHLEN]; + if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "sleef")) { + libsleef = os::dll_load(dll_name, ebuf, sizeof ebuf); + } + if (libsleef == nullptr) { + log_info(library)("Failed to load native vector math (sleef) library, %s!", ebuf); + return; + } + + // Method naming convention + // All the methods are named as _ + // + // Where: + // is the operation name, e.g. sin, cos + // is to indicate float/double + // "fx/dx" for vector float/double operation + // is the precision level + // "u10/u05" represents 1.0/0.5 ULP error bounds + // We use "u10" for all operations by default + // But for those functions do not have u10 support, we use "u05" instead + // rvv, indicates riscv vector extension + // + // e.g. sinfx_u10rvv is the method for computing vector float sin using rvv instructions + // + log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "sleef" JNI_LIB_SUFFIX, p2i(libsleef)); + + for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { + int vop = VectorSupport::VECTOR_OP_MATH_START + op; + if (vop == VectorSupport::VECTOR_OP_TANH) { // skip tanh because of performance regression + continue; + } + + // The native library does not support u10 level of "hypot". + const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10"; + + snprintf(ebuf, sizeof(ebuf), "%sfx_%srvv", VectorSupport::mathname[op], ulf); + StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf); + + snprintf(ebuf, sizeof(ebuf), "%sdx_%srvv", VectorSupport::mathname[op], ulf); + StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf); + } + } + #endif // COMPILER2 /** @@ -6102,7 +6321,7 @@ static const int64_t right_3_bits = right_n_bits(3); __ kernel_crc32(crc, buf, len, c_rarg3, c_rarg4, c_rarg5, c_rarg6, // tmp's for tables - c_rarg7, t2, x28, x29, x30, x31); // misc tmps + c_rarg7, t2, t3, t4, t5, t6); // misc tmps __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(); @@ -6124,6 +6343,29 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } + // load Method* target of MethodHandle + // j_rarg0 = jobject receiver + // xmethod = Method* result + address generate_upcall_stub_load_target() { + + StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target"); + address start = __ pc(); + + __ resolve_global_jobject(j_rarg0, t0, t1); + // Load target method from receiver + __ load_heap_oop(xmethod, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), t0, t1); + __ load_heap_oop(xmethod, Address(xmethod, java_lang_invoke_LambdaForm::vmentry_offset()), t0, t1); + __ load_heap_oop(xmethod, Address(xmethod, java_lang_invoke_MemberName::method_offset()), t0, t1); + __ access_load_at(T_ADDRESS, IN_HEAP, xmethod, + Address(xmethod, java_lang_invoke_ResolvedMethodName::vmtarget_offset()), + noreg, noreg); + __ sd(xmethod, Address(xthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized + + __ ret(); + + return start; + } + #undef __ // Initialization @@ -6189,6 +6431,7 @@ static const int64_t right_3_bits = right_n_bits(3); #endif // COMPILER2 StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); StubRoutines::riscv::set_completed(); } @@ -6219,6 +6462,11 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_montgomerySquare = g.generate_square(); } + if (UseAESIntrinsics) { + StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); + StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); + } + if (UsePoly1305Intrinsics) { StubRoutines::_poly1305_processBlocks = generate_poly1305_processBlocks(); } @@ -6267,6 +6515,8 @@ static const int64_t right_3_bits = right_n_bits(3); generate_string_indexof_stubs(); + generate_vector_math_stubs(); + #endif // COMPILER2 } diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index 1f32488777d57..0281c66b97db1 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.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. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -27,6 +27,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "classfile/javaClasses.hpp" +#include "compiler/disassembler.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/bytecodeTracer.hpp" @@ -70,7 +71,7 @@ // Max size with JVMTI int TemplateInterpreter::InterpreterCodeSize = 256 * 1024; -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> //----------------------------------------------------------------------------- @@ -165,7 +166,6 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M address fn = nullptr; address entry_point = nullptr; - Register continuation = ra; switch (kind) { case Interpreter::java_lang_math_abs: entry_point = __ pc(); @@ -184,83 +184,82 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M __ fld(f10, Address(esp)); __ mv(sp, x19_sender_sp); __ mv(x9, ra); - continuation = x9; // The first callee-saved register if (StubRoutines::dsin() == nullptr) { fn = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); } else { fn = CAST_FROM_FN_PTR(address, StubRoutines::dsin()); } __ call(fn); + __ mv(ra, x9); break; case Interpreter::java_lang_math_cos : entry_point = __ pc(); __ fld(f10, Address(esp)); __ mv(sp, x19_sender_sp); __ mv(x9, ra); - continuation = x9; // The first callee-saved register if (StubRoutines::dcos() == nullptr) { fn = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); } else { fn = CAST_FROM_FN_PTR(address, StubRoutines::dcos()); } __ call(fn); + __ mv(ra, x9); break; case Interpreter::java_lang_math_tan : entry_point = __ pc(); __ fld(f10, Address(esp)); __ mv(sp, x19_sender_sp); __ mv(x9, ra); - continuation = x9; // The first callee-saved register if (StubRoutines::dtan() == nullptr) { fn = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); } else { fn = CAST_FROM_FN_PTR(address, StubRoutines::dtan()); } __ call(fn); + __ mv(ra, x9); break; case Interpreter::java_lang_math_log : entry_point = __ pc(); __ fld(f10, Address(esp)); __ mv(sp, x19_sender_sp); __ mv(x9, ra); - continuation = x9; // The first callee-saved register if (StubRoutines::dlog() == nullptr) { fn = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); } else { fn = CAST_FROM_FN_PTR(address, StubRoutines::dlog()); } __ call(fn); + __ mv(ra, x9); break; case Interpreter::java_lang_math_log10 : entry_point = __ pc(); __ fld(f10, Address(esp)); __ mv(sp, x19_sender_sp); __ mv(x9, ra); - continuation = x9; // The first callee-saved register if (StubRoutines::dlog10() == nullptr) { fn = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10); } else { fn = CAST_FROM_FN_PTR(address, StubRoutines::dlog10()); } __ call(fn); + __ mv(ra, x9); break; case Interpreter::java_lang_math_exp : entry_point = __ pc(); __ fld(f10, Address(esp)); __ mv(sp, x19_sender_sp); __ mv(x9, ra); - continuation = x9; // The first callee-saved register if (StubRoutines::dexp() == nullptr) { fn = CAST_FROM_FN_PTR(address, SharedRuntime::dexp); } else { fn = CAST_FROM_FN_PTR(address, StubRoutines::dexp()); } __ call(fn); + __ mv(ra, x9); break; case Interpreter::java_lang_math_pow : entry_point = __ pc(); __ mv(x9, ra); - continuation = x9; __ fld(f10, Address(esp, 2 * Interpreter::stackElementSize)); __ fld(f11, Address(esp)); __ mv(sp, x19_sender_sp); @@ -270,6 +269,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M fn = CAST_FROM_FN_PTR(address, StubRoutines::dpow()); } __ call(fn); + __ mv(ra, x9); break; case Interpreter::java_lang_math_fmaD : if (UseFMA) { @@ -295,7 +295,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M ; } if (entry_point != nullptr) { - __ jr(continuation); + __ ret(); } return entry_point; @@ -421,7 +421,7 @@ address TemplateInterpreterGenerator::generate_exception_handler_common( c_rarg1, c_rarg2); } // throw exception - __ j(address(Interpreter::throw_exception_entry())); + __ j(RuntimeAddress(Interpreter::throw_exception_entry())); return entry; } @@ -1748,13 +1748,21 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address& vep) { assert(t != nullptr && t->is_valid() && t->tos_in() == vtos, "illegal template"); Label L; - aep = __ pc(); __ push_ptr(); __ j(L); - fep = __ pc(); __ push_f(); __ j(L); - dep = __ pc(); __ push_d(); __ j(L); - lep = __ pc(); __ push_l(); __ j(L); - bep = cep = sep = - iep = __ pc(); __ push_i(); - vep = __ pc(); + aep = __ pc(); // atos entry point + __ push_ptr(); + __ j(L); + fep = __ pc(); // ftos entry point + __ push_f(); + __ j(L); + dep = __ pc(); // dtos entry point + __ push_d(); + __ j(L); + lep = __ pc(); // ltos entry point + __ push_l(); + __ j(L); + bep = cep = sep = iep = __ pc(); // [bcsi]tos entry point + __ push_i(); + vep = __ pc(); // vtos entry point __ bind(L); generate_and_dispatch(t); } diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 2e6902180a892..9f37774e29743 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "compiler/disassembler.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/tlab_globals.hpp" @@ -49,7 +50,7 @@ #include "runtime/synchronizer.hpp" #include "utilities/powerOfTwo.hpp" -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> // Address computation: local variables @@ -704,7 +705,7 @@ void TemplateTable::wide_aload() { } void TemplateTable::index_check(Register array, Register index) { - // destroys x11, t0 + // destroys x11, t0, t1 // sign extend index for use by indexed load // check index const Register length = t0; @@ -717,8 +718,8 @@ void TemplateTable::index_check(Register array, Register index) { __ sign_extend(index, index, 32); __ bltu(index, length, ok); __ mv(x13, array); - __ mv(t0, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); - __ jr(t0); + __ mv(t1, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); + __ jr(t1); __ bind(ok); } @@ -1084,7 +1085,7 @@ void TemplateTable::aastore() { // Come here on failure // object is at TOS - __ j(Interpreter::_throw_ArrayStoreException_entry); + __ j(RuntimeAddress(Interpreter::_throw_ArrayStoreException_entry)); // Come here on success __ bind(ok_is_subtype); @@ -1312,8 +1313,8 @@ void TemplateTable::idiv() { // explicitly check for div0 Label no_div0; __ bnez(x10, no_div0); - __ mv(t0, Interpreter::_throw_ArithmeticException_entry); - __ jr(t0); + __ mv(t1, Interpreter::_throw_ArithmeticException_entry); + __ jr(t1); __ bind(no_div0); __ pop_i(x11); // x10 <== x11 idiv x10 @@ -1325,8 +1326,8 @@ void TemplateTable::irem() { // explicitly check for div0 Label no_div0; __ bnez(x10, no_div0); - __ mv(t0, Interpreter::_throw_ArithmeticException_entry); - __ jr(t0); + __ mv(t1, Interpreter::_throw_ArithmeticException_entry); + __ jr(t1); __ bind(no_div0); __ pop_i(x11); // x10 <== x11 irem x10 @@ -1344,8 +1345,8 @@ void TemplateTable::ldiv() { // explicitly check for div0 Label no_div0; __ bnez(x10, no_div0); - __ mv(t0, Interpreter::_throw_ArithmeticException_entry); - __ jr(t0); + __ mv(t1, Interpreter::_throw_ArithmeticException_entry); + __ jr(t1); __ bind(no_div0); __ pop_l(x11); // x10 <== x11 ldiv x10 @@ -1357,8 +1358,8 @@ void TemplateTable::lrem() { // explicitly check for div0 Label no_div0; __ bnez(x10, no_div0); - __ mv(t0, Interpreter::_throw_ArithmeticException_entry); - __ jr(t0); + __ mv(t1, Interpreter::_throw_ArithmeticException_entry); + __ jr(t1); __ bind(no_div0); __ pop_l(x11); // x10 <== x11 lrem x10 @@ -1767,8 +1768,8 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ andi(sp, esp, -16); // and begin the OSR nmethod - __ ld(t0, Address(x9, nmethod::osr_entry_point_offset())); - __ jr(t0); + __ ld(t1, Address(x9, nmethod::osr_entry_point_offset())); + __ jr(t1); } } @@ -2170,7 +2171,7 @@ void TemplateTable::_return(TosState state) { void TemplateTable::resolve_cache_and_index_for_method(int byte_no, Register Rcache, Register index) { - const Register temp = x9; + const Register temp = x9; // s1 assert_different_registers(Rcache, index, temp); assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); @@ -2464,7 +2465,7 @@ void TemplateTable::jvmti_post_field_access(Register cache, Register index, // take the time to call into the VM. Label L1; assert_different_registers(cache, index, x10); - ExternalAddress target((address) JvmtiExport::get_field_access_count_addr()); + ExternalAddress target(JvmtiExport::get_field_access_count_addr()); __ relocate(target.rspec(), [&] { int32_t offset; __ la(t0, target.target(), offset); @@ -2675,7 +2676,7 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is // we take the time to call into the VM. Label L1; assert_different_registers(cache, index, x10); - ExternalAddress target((address)JvmtiExport::get_field_modification_count_addr()); + ExternalAddress target(JvmtiExport::get_field_modification_count_addr()); __ relocate(target.rspec(), [&] { int32_t offset; __ la(t0, target.target(), offset); @@ -2968,7 +2969,7 @@ void TemplateTable::jvmti_post_fast_field_mod() { // Check to see if a field modification watch has been set before // we take the time to call into the VM. Label L2; - ExternalAddress target((address)JvmtiExport::get_field_modification_count_addr()); + ExternalAddress target(JvmtiExport::get_field_modification_count_addr()); __ relocate(target.rspec(), [&] { int32_t offset; __ la(t0, target.target(), offset); @@ -3100,7 +3101,7 @@ void TemplateTable::fast_accessfield(TosState state) { // Check to see if a field access watch has been set before we // take the time to call into the VM. Label L1; - ExternalAddress target((address)JvmtiExport::get_field_access_count_addr()); + ExternalAddress target(JvmtiExport::get_field_access_count_addr()); __ relocate(target.rspec(), [&] { int32_t offset; __ la(t0, target.target(), offset); @@ -3671,7 +3672,7 @@ void TemplateTable::checkcast() { // Come here on failure __ push_reg(x13); // object is at TOS - __ j(Interpreter::_throw_ClassCastException_entry); + __ j(RuntimeAddress(Interpreter::_throw_ClassCastException_entry)); // Come here on success __ bind(ok_is_subtype); @@ -3778,7 +3779,7 @@ void TemplateTable::_breakpoint() { void TemplateTable::athrow() { transition(atos, vtos); __ null_check(x10); - __ j(Interpreter::throw_exception_entry()); + __ j(RuntimeAddress(Interpreter::throw_exception_entry())); } //----------------------------------------------------------------------------- @@ -3961,8 +3962,8 @@ void TemplateTable::wide() { __ load_unsigned_byte(x9, at_bcp(1)); __ mv(t0, (address)Interpreter::_wentry_point); __ shadd(t0, x9, t0, t1, 3); - __ ld(t0, Address(t0)); - __ jr(t0); + __ ld(t1, Address(t0)); + __ jr(t1); } // Multi arrays diff --git a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp index 383f332f8fd94..3b4f26b6dc333 100644 --- a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp +++ b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "classfile/javaClasses.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "prims/upcallLinker.hpp" @@ -117,7 +118,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, @@ -223,7 +224,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ la(c_rarg0, Address(sp, frame_data_offset)); - __ movptr(c_rarg1, (address) receiver); __ rt_call(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry)); __ mv(xthread, x10); __ reinit_heapbase(); @@ -260,17 +260,15 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0); __ block_comment("} argument shuffle"); - __ block_comment("{ receiver "); - __ get_vm_result(j_rarg0, xthread); - __ block_comment("} receiver "); - - __ mov_metadata(xmethod, entry); - __ sd(xmethod, Address(xthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized + __ block_comment("{ load target "); + __ movptr(j_rarg0, (address) receiver); + __ far_call(RuntimeAddress(StubRoutines::upcall_stub_load_target())); // loads Method* into xmethod + __ block_comment("} load target "); __ push_cont_fastpath(xthread); - __ ld(t0, Address(xmethod, Method::from_compiled_offset())); - __ jalr(t0); + __ ld(t1, Address(xmethod, Method::from_compiled_offset())); + __ jalr(t1); __ pop_cont_fastpath(xthread); @@ -338,7 +336,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, #ifndef PRODUCT stringStream ss; - ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + ss.print("upcall_stub_%s", signature->as_C_string()); const char *name = _masm->code_string(ss.as_string()); #else // PRODUCT const char* name = "upcall_stub"; diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index e9c6226f44639..c32d2af993937 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -122,17 +122,6 @@ void VM_Version::common_initialize() { FLAG_SET_DEFAULT(AllocatePrefetchDistance, 0); } - if (UseAES || UseAESIntrinsics) { - if (UseAES && !FLAG_IS_DEFAULT(UseAES)) { - warning("AES instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseAES, false); - } - if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { - warning("AES intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESIntrinsics, false); - } - } - if (UseAESCTRIntrinsics) { warning("AES/CTR intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); @@ -429,6 +418,23 @@ void VM_Version::c2_initialize() { if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA3Intrinsics || UseSHA512Intrinsics)) { FLAG_SET_DEFAULT(UseSHA, false); } + + // AES + if (UseZvkn) { + UseAES = UseAES || FLAG_IS_DEFAULT(UseAES); + UseAESIntrinsics = + UseAESIntrinsics || (UseAES && FLAG_IS_DEFAULT(UseAESIntrinsics)); + if (UseAESIntrinsics && !UseAES) { + warning("UseAESIntrinsics enabled, but UseAES not, enabling"); + UseAES = true; + } + } else if (UseAESIntrinsics || UseAES) { + if (!FLAG_IS_DEFAULT(UseAESIntrinsics) || !FLAG_IS_DEFAULT(UseAES)) { + warning("AES intrinsics require Zvkn extension (not available on this CPU)."); + } + FLAG_SET_DEFAULT(UseAES, false); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } } #endif // COMPILER2 diff --git a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp index 5d945dbc32309..ce6d9c2f38f5c 100644 --- a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp @@ -131,8 +131,8 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { // xmethod: Method* // x12: receiver address ame_addr = __ pc(); - __ ld(t0, Address(xmethod, Method::from_compiled_offset())); - __ jr(t0); + __ ld(t1, Address(xmethod, Method::from_compiled_offset())); + __ jr(t1); masm->flush(); bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, 0); @@ -160,6 +160,13 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { MacroAssembler* masm = new MacroAssembler(&cb); assert_cond(masm != nullptr); + // Real entry arguments: + // t0: CompiledICData + // j_rarg0: Receiver + // Make sure the move of CompiledICData from t0 to t1 is the frist thing that happens. + // Otherwise we risk clobber t0 as it is used as scratch. + __ mv(t1, t0); + #if (!defined(PRODUCT) && defined(COMPILER2)) if (CountCompiledCalls) { __ la(x18, ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); @@ -170,8 +177,8 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { // get receiver (need to skip return address on top of stack) assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); - // Entry arguments: - // t1: CompiledICData + // Arguments from this point: + // t1 (moved from t0): CompiledICData // j_rarg0: Receiver // This stub is called from compiled code which has no callee-saved registers, @@ -220,8 +227,8 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { // xmethod: Method* // j_rarg0: receiver address ame_addr = __ pc(); - __ ld(t0, Address(xmethod, Method::from_compiled_offset())); - __ jr(t0); + __ ld(t1, Address(xmethod, Method::from_compiled_offset())); + __ jr(t1); __ bind(L_no_such_interface); // Handle IncompatibleClassChangeError in itable stubs. diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index d288f4a893d0a..d2e860aa32032 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -131,9 +131,19 @@ void LIR_Assembler::osr_entry() { // copied into place by code emitted in the IR. Register OSR_buf = osrBufferPointer()->as_register(); - { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); - int monitor_offset = BytesPerWord * method()->max_locals() + - (2 * BytesPerWord) * (number_of_locks - 1); + { + assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); + + const int locals_space = BytesPerWord * method() -> max_locals(); + int monitor_offset = locals_space + (2 * BytesPerWord) * (number_of_locks - 1); + bool large_offset = !Immediate::is_simm20(monitor_offset + BytesPerWord) && number_of_locks > 0; + + if (large_offset) { + // z_lg can only handle displacement upto 20bit signed binary integer + __ z_algfi(OSR_buf, locals_space); + monitor_offset -= locals_space; + } + // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in // the OSR buffer using 2 word entries: first the lock and then // the oop. @@ -147,6 +157,10 @@ void LIR_Assembler::osr_entry() { __ z_lg(Z_R1_scratch, slot_offset + 1*BytesPerWord, OSR_buf); __ z_stg(Z_R1_scratch, frame_map()->address_for_monitor_object(i)); } + + if (large_offset) { + __ z_slgfi(OSR_buf, locals_space); + } } } @@ -216,7 +230,11 @@ int LIR_Assembler::emit_unwind_handler() { LIR_Opr lock = FrameMap::as_opr(Z_R1_scratch); monitor_address(0, lock); stub = new MonitorExitStub(lock, true, 0); - __ unlock_object(Rtmp1, Rtmp2, lock->as_register(), *stub->entry()); + if (LockingMode == LM_MONITOR) { + __ branch_optimized(Assembler::bcondAlways, *stub->entry()); + } else { + __ unlock_object(Rtmp1, Rtmp2, lock->as_register(), *stub->entry()); + } __ bind(*stub->continuation()); } @@ -2350,6 +2368,7 @@ void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr de void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { if (op->init_check()) { // Make sure klass is initialized & doesn't have finalizer. + // init_state needs acquire, but S390 is TSO, and so we are already good. const int state_offset = in_bytes(InstanceKlass::init_state_offset()); Register iklass = op->klass()->as_register(); add_debug_info_for_null_check_here(op->stub()->info()); diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index f6dd20db3d67f..41c2ae260a693 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -120,6 +120,8 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox branch_optimized(Assembler::bcondNotZero, slow_case); // done bind(done); + } else { + assert(false, "Unhandled LockingMode:%d", LockingMode); } } @@ -151,6 +153,8 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb // If the object header was not pointing to the displaced header, // we do unlocking via runtime call. branch_optimized(Assembler::bcondNotEqual, slow_case); + } else { + assert(false, "Unhandled LockingMode:%d", LockingMode); } // done bind(done); diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp index 37631298920ca..544c82d34a769 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018, 2023 SAP SE. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -42,11 +42,47 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> -#define BLOCK_COMMENT(str) if (PrintAssembly) __ block_comment(str) +#define BLOCK_COMMENT(str) __ block_comment(str) + +static void generate_pre_barrier_fast_path(MacroAssembler* masm, + const Register thread, + const Register tmp1) { + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ load_and_test_int(tmp1, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ load_and_test_byte(tmp1, in_progress); + } +} + +static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register Z_thread, const Register value, const Register temp) { + BLOCK_COMMENT("generate_queue_test_and_insertion {"); + + assert_different_registers(temp, value); + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + + __ load_and_test_long(temp, Address(Z_thread, in_bytes(index_offset))); // temp := *(index address) + __ branch_optimized(Assembler::bcondEqual, runtime); // jump to runtime if index == 0 (full buffer) + + // The buffer is not full, store value into it. + __ add2reg(temp, -wordSize); // temp := next index + __ z_stg(temp, in_bytes(index_offset), Z_thread); // *(index address) := next index + + __ z_ag(temp, Address(Z_thread, in_bytes(buffer_offset))); // temp := buffer address + next index + __ z_stg(value, 0, temp); // *(buffer address + next index) := value + BLOCK_COMMENT("} generate_queue_test_and_insertion"); +} void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count) { @@ -59,13 +95,8 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm assert_different_registers(addr, Z_R0_scratch); // would be destroyed by push_frame() assert_different_registers(count, Z_R0_scratch); // would be destroyed by push_frame() Register Rtmp1 = Z_R0_scratch; - const int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ load_and_test_int(Rtmp1, Address(Z_thread, active_offset)); - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ load_and_test_byte(Rtmp1, Address(Z_thread, active_offset)); - } + + generate_pre_barrier_fast_path(masm, Z_thread, Rtmp1); __ z_bre(filtered); // Activity indicator is zero, so there is no marking going on currently. RegisterSaver::save_live_registers(masm, RegisterSaver::arg_registers); // Creates frame. @@ -100,6 +131,181 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas } } +#if defined(COMPILER2) + +#undef __ +#define __ masm-> + +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register pre_val, const address runtime_path) { + BLOCK_COMMENT("generate_c2_barrier_runtime_call {"); + SaveLiveRegisters save_registers(masm, stub); + __ call_VM_leaf(runtime_path, pre_val, Z_thread); + BLOCK_COMMENT("} generate_c2_barrier_runtime_call"); +} + +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + G1PreBarrierStubC2* stub) { + + BLOCK_COMMENT("g1_write_barrier_pre_c2 {"); + + assert(thread == Z_thread, "must be"); + assert_different_registers(obj, pre_val, tmp1); + assert(pre_val != noreg && tmp1 != noreg, "expecting a register"); + + stub->initialize_registers(obj, pre_val, thread, tmp1, noreg); + + generate_pre_barrier_fast_path(masm, thread, tmp1); + __ branch_optimized(Assembler::bcondNotEqual, *stub->entry()); // Activity indicator is zero, so there is no marking going on currently. + + __ bind(*stub->continuation()); + + BLOCK_COMMENT("} g1_write_barrier_pre_c2"); +} + +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + + BLOCK_COMMENT("generate_c2_pre_barrier_stub {"); + + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); + + __ bind(*stub->entry()); + + BLOCK_COMMENT("generate_pre_val_not_null_test {"); + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj), noreg, noreg, AS_RAW); + } + __ z_ltgr(pre_val, pre_val); + __ branch_optimized(Assembler::bcondEqual, *stub->continuation()); + BLOCK_COMMENT("} generate_pre_val_not_null_test"); + + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, + Z_thread, pre_val, tmp1); + + __ branch_optimized(Assembler::bcondAlways, *stub->continuation()); + + __ bind(runtime); + + generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); + + __ branch_optimized(Assembler::bcondAlways, *stub->continuation()); + + BLOCK_COMMENT("} generate_c2_pre_barrier_stub"); +} + +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* stub) { + BLOCK_COMMENT("g1_write_barrier_post_c2 {"); + + assert(thread == Z_thread, "must be"); + assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, Z_R1_scratch); + + assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); + + stub->initialize_registers(thread, tmp1, tmp2); + + BLOCK_COMMENT("generate_region_crossing_test {"); + if (VM_Version::has_DistinctOpnds()) { + __ z_xgrk(tmp1, store_addr, new_val); + } else { + __ z_lgr(tmp1, store_addr); + __ z_xgr(tmp1, new_val); + } + __ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); + __ branch_optimized(Assembler::bcondEqual, *stub->continuation()); + BLOCK_COMMENT("} generate_region_crossing_test"); + + // crosses regions, storing null? + if ((stub->barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ z_ltgr(new_val, new_val); + __ branch_optimized(Assembler::bcondEqual, *stub->continuation()); + } + + BLOCK_COMMENT("generate_card_young_test {"); + CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); + // calculate address of card + __ load_const_optimized(tmp2, (address)ct->card_table()->byte_map_base()); // Card table base. + __ z_srlg(tmp1, store_addr, CardTable::card_shift()); // Index into card table. + __ z_algr(tmp1, tmp2); // Explicit calculation needed for cli. + + // Filter young. + __ z_cli(0, tmp1, G1CardTable::g1_young_card_val()); + + BLOCK_COMMENT("} generate_card_young_test"); + + // From here on, tmp1 holds the card address. + __ branch_optimized(Assembler::bcondNotEqual, *stub->entry()); + + __ bind(*stub->continuation()); + + BLOCK_COMMENT("} g1_write_barrier_post_c2"); +} + +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + + BLOCK_COMMENT("generate_c2_post_barrier_stub {"); + + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); // tmp1 holds the card address. + Register tmp2 = stub->tmp2(); + Register Rcard_addr = tmp1; + + __ bind(*stub->entry()); + + BLOCK_COMMENT("generate_card_clean_test {"); + __ z_sync(); // Required to support concurrent cleaning. + __ z_cli(0, Rcard_addr, 0); // Reload after membar. + __ branch_optimized(Assembler::bcondEqual, *stub->continuation()); + BLOCK_COMMENT("} generate_card_clean_test"); + + BLOCK_COMMENT("generate_dirty_card {"); + // Storing a region crossing, non-null oop, card is clean. + // Dirty card and log. + STATIC_ASSERT(CardTable::dirty_card_val() == 0); + __ z_mvi(0, Rcard_addr, CardTable::dirty_card_val()); + BLOCK_COMMENT("} generate_dirty_card"); + + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, + Z_thread, tmp1, tmp2); + + __ branch_optimized(Assembler::bcondAlways, *stub->continuation()); + + __ bind(runtime); + + generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); + + __ branch_optimized(Assembler::bcondAlways, *stub->continuation()); + + BLOCK_COMMENT("} generate_c2_post_barrier_stub"); +} + +#endif //COMPILER2 + void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, const Address& src, Register dst, Register tmp1, Register tmp2, Label *L_handle_null) { bool on_oop = is_reference_type(type); @@ -136,9 +342,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator const Register Robj = obj ? obj->base() : noreg, Roff = obj ? obj->index() : noreg; - const int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - const int buffer_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - const int index_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); assert_different_registers(Rtmp1, Rtmp2, Z_R0_scratch); // None of the Rtmp must be Z_R0!! assert_different_registers(Robj, Z_R0_scratch); // Used for addressing. Furthermore, push_frame destroys Z_R0!! assert_different_registers(Rval, Z_R0_scratch); // push_frame destroys Z_R0!! @@ -147,14 +350,7 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator BLOCK_COMMENT("g1_write_barrier_pre {"); - // Is marking active? - // Note: value is loaded for test purposes only. No further use here. - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ load_and_test_int(Rtmp1, Address(Z_thread, active_offset)); - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ load_and_test_byte(Rtmp1, Address(Z_thread, active_offset)); - } + generate_pre_barrier_fast_path(masm, Z_thread, Rtmp1); __ z_bre(filtered); // Activity indicator is zero, so there is no marking going on currently. assert(Rpre_val != noreg, "must have a real register"); @@ -194,24 +390,14 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator // We can store the original value in the thread's buffer // only if index > 0. Otherwise, we need runtime to handle. // (The index field is typed as size_t.) - Register Rbuffer = Rtmp1, Rindex = Rtmp2; - assert_different_registers(Rbuffer, Rindex, Rpre_val); - - __ z_lg(Rbuffer, buffer_offset, Z_thread); - __ load_and_test_long(Rindex, Address(Z_thread, index_offset)); - __ z_bre(callRuntime); // If index == 0, goto runtime. - - __ add2reg(Rindex, -wordSize); // Decrement index. - __ z_stg(Rindex, index_offset, Z_thread); - - // Record the previous value. - __ z_stg(Rpre_val, 0, Rbuffer, Rindex); + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + callRuntime, + Z_thread, Rpre_val, Rtmp2); __ z_bru(filtered); // We are done. - Rbuffer = noreg; // end of life - Rindex = noreg; // end of life - __ bind(callRuntime); // Save some registers (inputs and result) over runtime call @@ -326,23 +512,16 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato Register Rcard_addr_x = Rcard_addr; Register Rqueue_index = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp1; - Register Rqueue_buf = (Rtmp3 != Z_R0_scratch) ? Rtmp3 : Rtmp1; - const int qidx_off = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()); - const int qbuf_off = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()); - if ((Rcard_addr == Rqueue_buf) || (Rcard_addr == Rqueue_index)) { + if (Rcard_addr == Rqueue_index) { Rcard_addr_x = Z_R0_scratch; // Register shortage. We have to use Z_R0. } __ lgr_if_needed(Rcard_addr_x, Rcard_addr); - __ load_and_test_long(Rqueue_index, Address(Z_thread, qidx_off)); - __ z_bre(callRuntime); // Index == 0 then jump to runtime. - - __ z_lg(Rqueue_buf, qbuf_off, Z_thread); - - __ add2reg(Rqueue_index, -wordSize); // Decrement index. - __ z_stg(Rqueue_index, qidx_off, Z_thread); - - __ z_stg(Rcard_addr_x, 0, Rqueue_index, Rqueue_buf); // Store card. + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + callRuntime, + Z_thread, Rcard_addr_x, Rqueue_index); __ z_bru(filtered); __ bind(callRuntime); diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp index cc1d51d2fa13e..0f0bdd8b83cfd 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018 SAP SE. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -34,6 +34,8 @@ class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -62,7 +64,27 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); -#endif +#endif // COMPILER1 + +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* c2_stub); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif // COMPILER2 virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, const Address& src, Register dst, Register tmp1, Register tmp2, Label *L_handle_null = nullptr); diff --git a/src/hotspot/cpu/s390/gc/g1/g1_s390.ad b/src/hotspot/cpu/s390/gc/g1/g1_s390.ad new file mode 100644 index 0000000000000..31f60c4aeff0b --- /dev/null +++ b/src/hotspot/cpu/s390/gc/g1/g1_s390.ad @@ -0,0 +1,457 @@ +// +// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright 2024 IBM Corporation. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_s390.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void write_barrier_pre(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp1, + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, Z_thread, tmp1, stub); +} + +static void write_barrier_post(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Z_thread, tmp1, tmp2, stub); +} + +%} // source + +// store pointer +instruct g1StoreP(indirect dst, memoryRegP src, iRegL tmp1, iRegL tmp2, flagsReg cr) %{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set dst (StoreP dst src)); + effect(TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(MEMORY_REF_COST); + format %{ "STG $src,$dst\t # ptr" %} + ins_encode %{ + __ block_comment("g1StoreP {"); + write_barrier_pre(masm, this, + $dst$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($dst$$Register, $src$$Register) /* preserve */); + + __ z_stg($src$$Register, Address($dst$$Register)); + + write_barrier_post(masm, this, + $dst$$Register, /* store_addr */ + $src$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + __ block_comment("} g1StoreP"); + %} + ins_pipe(pipe_class_dummy); +%} + +// Store Compressed Pointer +instruct g1StoreN(indirect mem, iRegN_P2N src, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(MEMORY_REF_COST); + format %{ "STY $src,$mem\t # (cOop)" %} + ins_encode %{ + __ block_comment("g1StoreN {"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + + __ z_sty($src$$Register, Address($mem$$Register)); + + if ((barrier_data() & G1C2BarrierPost) != 0) { + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ oop_decoder($tmp1$$Register, $src$$Register, true /* maybe_null */); + } else { + __ oop_decoder($tmp1$$Register, $src$$Register, false /* maybe_null */); + } + } + + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + __ block_comment("} g1StoreN"); + %} + + ins_pipe(pipe_class_dummy); +%} + +instruct g1CompareAndSwapN(indirect mem_ptr, rarg5RegN oldval, iRegN_P2N newval, iRegI res, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); + effect(USE mem_ptr, TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, USE_KILL oldval, KILL cr); + format %{ "$res = CompareAndSwapN $oldval,$newval,$mem_ptr" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem_ptr$$Register); + assert_different_registers($newval$$Register, $mem_ptr$$Register); + __ block_comment("g1compareAndSwapN {"); + + Register Rcomp = reg_to_register_object($oldval$$reg); + Register Rnew = reg_to_register_object($newval$$reg); + Register Raddr = reg_to_register_object($mem_ptr$$reg); + Register Rres = reg_to_register_object($res$$reg); + + write_barrier_pre(masm, this, + Raddr /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of(Raddr, Rcomp, Rnew) /* preserve */, + RegSet::of(Rres) /* no_preserve */); + + __ z_cs(Rcomp, Rnew, 0, Raddr); + + assert_different_registers(Rres, Raddr); + if (VM_Version::has_LoadStoreConditional()) { + __ load_const_optimized(Z_R0_scratch, 0L); // false (failed) + __ load_const_optimized(Rres, 1L); // true (succeed) + __ z_locgr(Rres, Z_R0_scratch, Assembler::bcondNotEqual); + } else { + Label done; + __ load_const_optimized(Rres, 0L); // false (failed) + __ z_brne(done); // Assume true to be the common case. + __ load_const_optimized(Rres, 1L); // true (succeed) + __ bind(done); + } + + __ oop_decoder($tmp3$$Register, Rnew, true /* maybe_null */); + + write_barrier_post(masm, this, + Raddr /* store_addr */, + $tmp3$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + __ block_comment("} g1compareAndSwapN"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1CompareAndExchangeN(iRegP mem_ptr, rarg5RegN oldval, iRegN_P2N newval, iRegN res, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem_ptr (Binary oldval newval))); + effect(USE mem_ptr, TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, USE_KILL oldval, KILL cr); + format %{ "$res = CompareAndExchangeN $oldval,$newval,$mem_ptr" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem_ptr$$Register); + assert_different_registers($newval$$Register, $mem_ptr$$Register); + __ block_comment("g1CompareAndExchangeN {"); + write_barrier_pre(masm, this, + $mem_ptr$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($mem_ptr$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + + Register Rcomp = reg_to_register_object($oldval$$reg); + Register Rnew = reg_to_register_object($newval$$reg); + Register Raddr = reg_to_register_object($mem_ptr$$reg); + + Register Rres = reg_to_register_object($res$$reg); + assert_different_registers(Rres, Raddr); + + __ z_lgr(Rres, Rcomp); // previous contents + __ z_csy(Rres, Rnew, 0, Raddr); // Try to store new value. + + __ oop_decoder($tmp1$$Register, Rnew, true /* maybe_null */); + + write_barrier_post(masm, this, + Raddr /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + __ block_comment("} g1CompareAndExchangeN"); + %} + ins_pipe(pipe_class_dummy); +%} + +// Load narrow oop +instruct g1LoadN(iRegN dst, indirect mem, iRegP tmp1, iRegP tmp2, flagsReg cr) %{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadN mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(MEMORY_REF_COST); + format %{ "LoadN $dst,$mem\t # (cOop)" %} + ins_encode %{ + __ block_comment("g1LoadN {"); + __ z_llgf($dst$$Register, Address($mem$$Register)); + if ((barrier_data() & G1C2BarrierPre) != 0) { + __ oop_decoder($tmp1$$Register, $dst$$Register, true); + write_barrier_pre(masm, this, + noreg /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register ); + } + __ block_comment("} g1LoadN"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1GetAndSetN(indirect mem, iRegN dst, iRegI tmp, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set dst (GetAndSetN mem dst)); + effect(KILL cr, TEMP tmp, TEMP tmp1, TEMP tmp2, TEMP tmp3); // USE_DEF dst by match rule. + format %{ "XCHGN $dst,[$mem]\t # EXCHANGE (coop, atomic), temp $tmp" %} + ins_encode %{ + __ block_comment("g1GetAndSetN {"); + assert_different_registers($mem$$Register, $dst$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($mem$$Register, $dst$$Register) /* preserve */); + + Register Rdst = reg_to_register_object($dst$$reg); + Register Rtmp = reg_to_register_object($tmp$$reg); + guarantee(Rdst != Rtmp, "Fix match rule to use TEMP_DEF"); + Label retry; + + // Iterate until swap succeeds. + __ z_llgf(Rtmp, Address($mem$$Register)); // current contents + __ bind(retry); + // Calculate incremented value. + __ z_csy(Rtmp, Rdst, Address($mem$$Register)); // Try to store new value. + __ z_brne(retry); // Yikes, concurrent update, need to retry. + + __ oop_decoder($tmp1$$Register, $dst$$Register, true /* maybe_null */); + + __ z_lgr(Rdst, Rtmp); // Exchanged value from memory is return value. + + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + + __ block_comment("} g1GetAndSetN"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1CompareAndSwapP(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, iRegI res, iRegL tmp1, iRegL tmp2, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, USE mem_ptr, USE_KILL oldval, KILL cr); + format %{ "$res = CompareAndSwapP $oldval,$newval,$mem_ptr" %} + ins_encode %{ + __ block_comment("g1CompareAndSwapP {"); + assert_different_registers($oldval$$Register, $mem_ptr$$Register); + assert_different_registers($newval$$Register, $mem_ptr$$Register); + + Register Rcomp = reg_to_register_object($oldval$$reg); + Register Rnew = reg_to_register_object($newval$$reg); + Register Raddr = reg_to_register_object($mem_ptr$$reg); + Register Rres = reg_to_register_object($res$$reg); + + write_barrier_pre(masm, this, + noreg /* obj */, + Rcomp /* pre_val */, + $tmp1$$Register /* tmp1 */, + RegSet::of(Raddr, Rcomp, Rnew) /* preserve */, + RegSet::of(Rres) /* no_preserve */); + + __ z_csg(Rcomp, Rnew, 0, Raddr); + + if (VM_Version::has_LoadStoreConditional()) { + __ load_const_optimized(Z_R0_scratch, 0L); // false (failed) + __ load_const_optimized(Rres, 1L); // true (succeed) + __ z_locgr(Rres, Z_R0_scratch, Assembler::bcondNotEqual); + } else { + Label done; + __ load_const_optimized(Rres, 0L); // false (failed) + __ z_brne(done); // Assume true to be the common case. + __ load_const_optimized(Rres, 1L); // true (succeed) + __ bind(done); + } + + write_barrier_post(masm, this, + Raddr /* store_addr */, + Rnew /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + __ block_comment("} g1CompareAndSwapP"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1CompareAndExchangeP(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, iRegP res, iRegL tmp1, iRegL tmp2, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem_ptr (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, USE mem_ptr, USE_KILL oldval, KILL cr); + format %{ "$res = CompareAndExchangeP $oldval,$newval,$mem_ptr" %} + ins_encode %{ + __ block_comment("g1CompareAndExchangeP {"); + assert_different_registers($oldval$$Register, $mem_ptr$$Register); + assert_different_registers($newval$$Register, $mem_ptr$$Register); + + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($mem_ptr$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + + __ z_lgr($res$$Register, $oldval$$Register); // previous content + + __ z_csg($oldval$$Register, $newval$$Register, 0, $mem_ptr$$reg); + + write_barrier_post(masm, this, + $mem_ptr$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + __ block_comment("} g1CompareAndExchangeP"); + %} + ins_pipe(pipe_class_dummy); +%} + +// Load Pointer +instruct g1LoadP(iRegP dst, memory mem, iRegL tmp1, flagsReg cr) %{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp1, KILL cr); + ins_cost(MEMORY_REF_COST); + format %{ "LG $dst,$mem\t # ptr" %} + ins_encode %{ + __ block_comment("g1LoadP {"); + __ z_lg($dst$$Register, $mem$$Address); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp1$$Register ); + __ block_comment("} g1LoadP"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1GetAndSetP(indirect mem, iRegP dst, iRegL tmp, iRegL tmp1, iRegL tmp2, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set dst (GetAndSetP mem dst)); + effect(KILL cr, TEMP tmp, TEMP tmp1, TEMP tmp2); // USE_DEF dst by match rule. + format %{ "XCHGP $dst,[$mem]\t # EXCHANGE (oop, atomic), temp $tmp" %} + ins_encode %{ + __ block_comment("g1GetAndSetP {"); + + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + RegSet::of($mem$$Register, $dst$$Register) /* preserve */); + + __ z_lgr($tmp1$$Register, $dst$$Register); + Register Rdst = reg_to_register_object($dst$$reg); + Register Rtmp = reg_to_register_object($tmp$$reg); + guarantee(Rdst != Rtmp, "Fix match rule to use TEMP_DEF"); + Label retry; + + // Iterate until swap succeeds. + __ z_lg(Rtmp, Address($mem$$Register)); // current contents + __ bind(retry); + // Calculate incremented value. + __ z_csg(Rtmp, Rdst, Address($mem$$Register)); // Try to store new value. + __ z_brne(retry); // Yikes, concurrent update, need to retry. + __ z_lgr(Rdst, Rtmp); // Exchanged value from memory is return value. + + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp$$Register /* tmp2 */); + __ block_comment("} g1GetAndSetP"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegL tmp1, iRegL tmp2, flagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, KILL cr); + // ins_cost(INSN_COST); + format %{ "encode_heap_oop $tmp1, $src\n\t" + "st $tmp1, $mem\t# compressed ptr" %} + ins_encode %{ + __ block_comment("g1EncodePAndStoreN {"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ oop_encoder($tmp1$$Register, $src$$Register, true /* maybe_null */); + } else { + __ oop_encoder($tmp1$$Register, $src$$Register, false /* maybe_null */); + } + __ z_st($tmp1$$Register, Address($mem$$Register)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + __ block_comment("} g1EncodePAndStoreN"); + %} + ins_pipe(pipe_class_dummy); +%} diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp index 28892da6ca4c1..d826b4a06f336 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp @@ -33,6 +33,9 @@ #include "runtime/jniHandles.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/macros.hpp" +#ifdef COMPILER2 +#include "gc/shared/c2/barrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> @@ -194,8 +197,93 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { #ifdef COMPILER2 -OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) { - Unimplemented(); // This must be implemented to support late barrier expansion. +OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) const { + if (!OptoReg::is_reg(opto_reg)) { + return OptoReg::Bad; + } + + VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if ((vm_reg->is_Register() || vm_reg ->is_FloatRegister()) && (opto_reg & 1) != 0) { + return OptoReg::Bad; + } + + return opto_reg; +} + +#undef __ +#define __ _masm-> + +SaveLiveRegisters::SaveLiveRegisters(MacroAssembler *masm, BarrierStubC2 *stub) + : _masm(masm), _reg_mask(stub->preserve_set()) { + + const int register_save_size = iterate_over_register_mask(ACTION_COUNT_ONLY) * BytesPerWord; + + _frame_size = align_up(register_save_size, frame::alignment_in_bytes) + frame::z_abi_160_size; // FIXME: this could be restricted to argument only + + __ save_return_pc(); + __ push_frame(_frame_size, Z_R14); // FIXME: check if Z_R1_scaratch can do a job here; + + __ z_lg(Z_R14, _z_common_abi(return_pc) + _frame_size, Z_SP); + + iterate_over_register_mask(ACTION_SAVE, _frame_size); +} + +SaveLiveRegisters::~SaveLiveRegisters() { + iterate_over_register_mask(ACTION_RESTORE, _frame_size); + + __ pop_frame(); + + __ restore_return_pc(); +} + +int SaveLiveRegisters::iterate_over_register_mask(IterationAction action, int offset) { + int reg_save_index = 0; + RegMaskIterator live_regs_iterator(_reg_mask); + + while(live_regs_iterator.has_next()) { + const OptoReg::Name opto_reg = live_regs_iterator.next(); + + // Filter out stack slots (spilled registers, i.e., stack-allocated registers). + if (!OptoReg::is_reg(opto_reg)) { + continue; + } + + const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if (vm_reg->is_Register()) { + Register std_reg = vm_reg->as_Register(); + + if (std_reg->encoding() >= Z_R2->encoding() && std_reg->encoding() <= Z_R15->encoding()) { + reg_save_index++; + + if (action == ACTION_SAVE) { + __ z_stg(std_reg, offset - reg_save_index * BytesPerWord, Z_SP); + } else if (action == ACTION_RESTORE) { + __ z_lg(std_reg, offset - reg_save_index * BytesPerWord, Z_SP); + } else { + assert(action == ACTION_COUNT_ONLY, "Sanity"); + } + } + } else if (vm_reg->is_FloatRegister()) { + FloatRegister fp_reg = vm_reg->as_FloatRegister(); + if (fp_reg->encoding() >= Z_F0->encoding() && fp_reg->encoding() <= Z_F15->encoding() + && fp_reg->encoding() != Z_F1->encoding()) { + reg_save_index++; + + if (action == ACTION_SAVE) { + __ z_std(fp_reg, offset - reg_save_index * BytesPerWord, Z_SP); + } else if (action == ACTION_RESTORE) { + __ z_ld(fp_reg, offset - reg_save_index * BytesPerWord, Z_SP); + } else { + assert(action == ACTION_COUNT_ONLY, "Sanity"); + } + } + } else if (false /* vm_reg->is_VectorRegister() */){ + fatal("Vector register support is not there yet!"); + } else { + fatal("Register type is not known"); + } + } + return reg_save_index; } #endif // COMPILER2 diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp index de1de8a51a7f1..fb61adc55b500 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp @@ -32,7 +32,9 @@ #ifdef COMPILER2 #include "code/vmreg.hpp" #include "opto/optoreg.hpp" +#include "opto/regmask.hpp" +class BarrierStubC2; class Node; #endif // COMPILER2 @@ -62,8 +64,42 @@ class BarrierSetAssembler: public CHeapObj { #ifdef COMPILER2 OptoReg::Name refine_register(const Node* node, - OptoReg::Name opto_reg); + OptoReg::Name opto_reg) const; #endif // COMPILER2 }; +#ifdef COMPILER2 + +// This class saves and restores the registers that need to be preserved across +// the runtime call represented by a given C2 barrier stub. Use as follows: +// { +// SaveLiveRegisters save(masm, stub); +// .. +// __ call_VM_leaf(...); +// .. +// } + +class SaveLiveRegisters { + MacroAssembler* _masm; + RegMask _reg_mask; + Register _result_reg; + int _frame_size; + + public: + SaveLiveRegisters(MacroAssembler *masm, BarrierStubC2 *stub); + + ~SaveLiveRegisters(); + + private: + enum IterationAction : int { + ACTION_SAVE, + ACTION_RESTORE, + ACTION_COUNT_ONLY + }; + + int iterate_over_register_mask(IterationAction action, int offset = 0); +}; + +#endif // COMPILER2 + #endif // CPU_S390_GC_SHARED_BARRIERSETASSEMBLER_S390_HPP diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index d00b6c3e2cc2e..5e80817aaba7b 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -2131,18 +2131,6 @@ void InterpreterMacroAssembler::notify_method_exit(bool native_method, if (!native_method) pop(state); bind(jvmti_post_done); } - -#if 0 - // Dtrace currently not supported on z/Architecture. - { - SkipIfEqual skip(this, &DTraceMethodProbes, false); - push(state); - get_method(c_rarg1); - call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), - r15_thread, c_rarg1); - pop(state); - } -#endif } void InterpreterMacroAssembler::skip_if_jvmti_mode(Label &Lskip, Register Rscratch) { diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index af281345b1477..6b739553b1580 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -2127,8 +2127,9 @@ unsigned int MacroAssembler::push_frame_abi160(unsigned int bytes) { // Pop current C frame. void MacroAssembler::pop_frame() { - BLOCK_COMMENT("pop_frame:"); + BLOCK_COMMENT("pop_frame {"); Assembler::z_lg(Z_SP, _z_abi(callers_sp), Z_SP); + BLOCK_COMMENT("} pop_frame"); } // Pop current C frame and restore return PC register (Z_R14). @@ -3458,7 +3459,8 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa L_slow_path = &L_fallthrough; } - // Fast path check: class is fully initialized + // Fast path check: class is fully initialized. + // init_state needs acquire, but S390 is TSO, and so we are already good. z_cli(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); z_bre(*L_fast_path); @@ -3665,7 +3667,7 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg // We need a full fence after clearing owner to avoid stranding. z_fence(); - // Check if the entry lists are empty. + // Check if the entry lists are empty (EntryList first - by convention). load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); z_brne(check_succ); load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); @@ -6014,21 +6016,6 @@ void MacroAssembler::zap_from_to(Register low, Register high, Register val, Regi } #endif // !PRODUCT -SkipIfEqual::SkipIfEqual(MacroAssembler* masm, const bool* flag_addr, bool value, Register _rscratch) { - _masm = masm; - _masm->load_absolute_address(_rscratch, (address)flag_addr); - _masm->load_and_test_int(_rscratch, Address(_rscratch)); - if (value) { - _masm->z_brne(_label); // Skip if true, i.e. != 0. - } else { - _masm->z_bre(_label); // Skip if false, i.e. == 0. - } -} - -SkipIfEqual::~SkipIfEqual() { - _masm->bind(_label); -} - // Implements lightweight-locking. // - obj: the object to be locked, contents preserved. // - temp1, temp2: temporary registers, contents destroyed. @@ -6508,7 +6495,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis // We need a full fence after clearing owner to avoid stranding. z_fence(); - // Check if the entry lists are empty. + // Check if the entry lists are empty (EntryList first - by convention). load_and_test_long(tmp2, EntryList_address); z_brne(check_succ); load_and_test_long(tmp2, cxq_address); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index 5d3a4c2994091..061817a128913 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -1064,24 +1064,6 @@ class MacroAssembler: public Assembler { }; -/** - * class SkipIfEqual: - * - * Instantiating this class will result in assembly code being output that will - * jump around any code emitted between the creation of the instance and it's - * automatic destruction at the end of a scope block, depending on the value of - * the flag passed to the constructor, which will be checked at run-time. - */ -class SkipIfEqual { - private: - MacroAssembler* _masm; - Label _label; - - public: - SkipIfEqual(MacroAssembler*, const bool* flag_addr, bool value, Register _rscratch); - ~SkipIfEqual(); -}; - #ifdef ASSERT // Return false (e.g. important for our impl. of virtual calls). inline bool AbstractAssembler::pd_check_instruction_mark() { return false; } diff --git a/src/hotspot/cpu/s390/matcher_s390.hpp b/src/hotspot/cpu/s390/matcher_s390.hpp index 6c6cae3c58fc3..d8b1ae68f6f50 100644 --- a/src/hotspot/cpu/s390/matcher_s390.hpp +++ b/src/hotspot/cpu/s390/matcher_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2017, 2022 SAP SE. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -63,11 +63,16 @@ return true; } - // Suppress CMOVL. Conditional move available on z/Architecture only from z196 onwards. Not exploited yet. - static int long_cmove_cost() { return ConditionalMoveLimit; } + // Use conditional move (CMOVL) + static int long_cmove_cost() { + // z196/z11 or later hardware support conditional moves + return VM_Version::has_LoadStoreConditional() ? 0 : ConditionalMoveLimit; + } - // Suppress CMOVF. Conditional move available on z/Architecture only from z196 onwards. Not exploited yet. - static int float_cmove_cost() { return ConditionalMoveLimit; } + static int float_cmove_cost() { + // z196/z11 or later hardware support conditional moves + return VM_Version::has_LoadStoreConditional() ? 0 : ConditionalMoveLimit; + } // Set this as clone_shift_expressions. static bool narrow_oop_use_complex_address() { diff --git a/src/hotspot/cpu/s390/nativeInst_s390.cpp b/src/hotspot/cpu/s390/nativeInst_s390.cpp index 9f083fa890454..4db73395d3a70 100644 --- a/src/hotspot/cpu/s390/nativeInst_s390.cpp +++ b/src/hotspot/cpu/s390/nativeInst_s390.cpp @@ -658,8 +658,8 @@ void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { assert(((intptr_t)instr_addr & (BytesPerWord-1)) == 0, "requirement for mt safe patching"); - // Bytes_after_jump cannot change, because we own the Patching_lock. - assert(Patching_lock->owned_by_self(), "must hold lock to patch instruction"); + // Bytes_after_jump cannot change, because we own the CodeCache_lock. + assert(CodeCache_lock->owned_by_self(), "must hold lock to patch instruction"); intptr_t bytes_after_jump = (*(intptr_t*)instr_addr) & 0x000000000000ffffL; // 2 bytes after jump. intptr_t load_const_bytes = (*(intptr_t*)code_buffer) & 0xffffffffffff0000L; *(intptr_t*)instr_addr = load_const_bytes | bytes_after_jump; diff --git a/src/hotspot/cpu/s390/register_s390.hpp b/src/hotspot/cpu/s390/register_s390.hpp index 931e899257e92..18af232e56970 100644 --- a/src/hotspot/cpu/s390/register_s390.hpp +++ b/src/hotspot/cpu/s390/register_s390.hpp @@ -448,4 +448,12 @@ constexpr Register Z_R0_scratch = Z_R0; constexpr Register Z_R1_scratch = Z_R1; constexpr FloatRegister Z_fscratch_1 = Z_F1; +typedef AbstractRegSet RegSet; + +template <> +inline Register AbstractRegSet::first() { + if (_bitset == 0) { return noreg; } + return as_Register(count_trailing_zeros(_bitset)); +} + #endif // CPU_S390_REGISTER_S390_HPP diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 1bc9484215005..8b897033aa55d 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1477,10 +1477,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return nullptr; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return nullptr; -} - // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { return false; @@ -1644,6 +1640,10 @@ const RegMask Matcher::method_handle_invoke_SP_save_mask() { // Should the matcher clone input 'm' of node 'n'? bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { + if (is_encode_and_store_pattern(n, m)) { + mstack.push(m, Visit); + return true; + } return false; } @@ -3913,6 +3913,7 @@ instruct loadL_unaligned(iRegL dst, memory mem) %{ // Load Pointer instruct loadP(iRegP dst, memory mem) %{ match(Set dst (LoadP mem)); + predicate(n->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "LG $dst,$mem\t # ptr" %} @@ -3924,6 +3925,7 @@ instruct loadP(iRegP dst, memory mem) %{ // LoadP + CastP2L instruct castP2X_loadP(iRegL dst, memory mem) %{ match(Set dst (CastP2X (LoadP mem))); + predicate(n->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "LG $dst,$mem\t # ptr + p2x" %} @@ -4220,28 +4222,6 @@ instruct storeB(memory mem, iRegI src) %{ ins_pipe(pipe_class_dummy); %} -instruct storeCM(memory mem, immI_0 src) %{ - match(Set mem (StoreCM mem src)); - ins_cost(MEMORY_REF_COST); - // TODO: s390 port size(VARIABLE_SIZE); - format %{ "STC(Y) $src,$mem\t # CMS card-mark byte (must be 0!)" %} - ins_encode %{ - guarantee($mem$$index$$Register != Z_R0, "content will not be used."); - if ($mem$$index$$Register != noreg) { - // Can't use clear_mem --> load const zero and store character. - __ load_const_optimized(Z_R0_scratch, (long)0); - if (Immediate::is_uimm12($mem$$disp)) { - __ z_stc(Z_R0_scratch, $mem$$Address); - } else { - __ z_stcy(Z_R0_scratch, $mem$$Address); - } - } else { - __ clear_mem(Address($mem$$Address), 1); - } - %} - ins_pipe(pipe_class_dummy); -%} - // CHAR/SHORT // Store Char/Short @@ -4286,6 +4266,7 @@ instruct storeL(memory mem, iRegL src) %{ // Store Pointer instruct storeP(memory dst, memoryRegP src) %{ match(Set dst (StoreP dst src)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "STG $src,$dst\t # ptr" %} @@ -4388,6 +4369,7 @@ instruct memInitL(memoryRS mem, immL16 src) %{ // Move Immediate to 8-byte memory. instruct memInitP(memoryRS mem, immP16 src) %{ match(Set mem (StoreP mem src)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(6); format %{ "MVGHI $mem,$src\t # direct mem init 8" %} @@ -4417,6 +4399,7 @@ instruct negL_reg_reg(iRegL dst, immL_0 zero, iRegL src, flagsReg cr) %{ // Load narrow oop instruct loadN(iRegN dst, memory mem) %{ match(Set dst (LoadN mem)); + predicate(n->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "LoadN $dst,$mem\t # (cOop)" %} @@ -4480,7 +4463,7 @@ instruct loadConNKlass(iRegN dst, immNKlass src) %{ instruct decodeLoadN(iRegP dst, memory mem) %{ match(Set dst (DecodeN (LoadN mem))); - predicate(false && (CompressedOops::base()==nullptr)&&(CompressedOops::shift()==0)); + predicate(false && (CompressedOops::base()==nullptr) && (CompressedOops::shift()==0)); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "DecodeLoadN $dst,$mem\t # (cOop Load+Decode)" %} @@ -4735,6 +4718,7 @@ instruct encodeP_NN_Ex(iRegN dst, iRegP src, flagsReg cr) %{ // Store Compressed Pointer instruct storeN(memory mem, iRegN_P2N src) %{ match(Set mem (StoreN mem src)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(Z_DISP_SIZE); format %{ "ST $src,$mem\t # (cOop)" %} @@ -5146,6 +5130,7 @@ instruct compareAndSwapL_bool(iRegP mem_ptr, rarg5RegL oldval, iRegL newval, iRe instruct compareAndSwapP_bool(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, iRegI res, flagsReg cr) %{ match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(USE mem_ptr, USE_KILL oldval, KILL cr); size(18); format %{ "$res = CompareAndSwapP $oldval,$newval,$mem_ptr" %} @@ -5156,6 +5141,7 @@ instruct compareAndSwapP_bool(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, instruct compareAndSwapN_bool(iRegP mem_ptr, rarg5RegN oldval, iRegN_P2N newval, iRegI res, flagsReg cr) %{ match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(USE mem_ptr, USE_KILL oldval, KILL cr); size(16); format %{ "$res = CompareAndSwapN $oldval,$newval,$mem_ptr" %} @@ -5443,6 +5429,7 @@ instruct xchgL_reg_mem(memoryRSY mem, iRegL dst, iRegL tmp, flagsReg cr) %{ %} instruct xchgN_reg_mem(memoryRSY mem, iRegN dst, iRegI tmp, flagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set dst (GetAndSetN mem dst)); effect(KILL cr, TEMP tmp); // USE_DEF dst by match rule. format %{ "XCHGN $dst,[$mem]\t # EXCHANGE (coop, atomic), temp $tmp" %} @@ -5452,6 +5439,7 @@ instruct xchgN_reg_mem(memoryRSY mem, iRegN dst, iRegI tmp, flagsReg cr) %{ instruct xchgP_reg_mem(memoryRSY mem, iRegP dst, iRegL tmp, flagsReg cr) %{ match(Set dst (GetAndSetP mem dst)); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(KILL cr, TEMP tmp); // USE_DEF dst by match rule. format %{ "XCHGP $dst,[$mem]\t # EXCHANGE (oop, atomic), temp $tmp" %} ins_encode(z_enc_SwapL(mem, dst, tmp)); @@ -5926,7 +5914,7 @@ instruct addP_regN_reg_imm20(iRegP dst, iRegP_N2P src1, iRegL src2, immL20 con) instruct addP_mem_imm(memoryRSY mem, immL8 src, flagsReg cr) %{ match(Set mem (StoreP mem (AddP (LoadP mem) src))); effect(KILL cr); - predicate(VM_Version::has_MemWithImmALUOps()); + predicate(VM_Version::has_MemWithImmALUOps() && n->as_LoadStore()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(6); format %{ "AGSI $mem,$src\t # direct mem add 8 (ptr)" %} diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index d878731cca51f..dd9ed4c95462b 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -3053,6 +3053,29 @@ class StubGenerator: public StubCodeGenerator { return start; } + // load Method* target of MethodHandle + // Z_ARG1 = jobject receiver + // Z_method = Method* result + address generate_upcall_stub_load_target() { + StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target"); + address start = __ pc(); + + __ resolve_global_jobject(Z_ARG1, Z_tmp_1, Z_tmp_2); + // Load target method from receiver + __ load_heap_oop(Z_method, Address(Z_ARG1, java_lang_invoke_MethodHandle::form_offset()), + noreg, noreg, IS_NOT_NULL); + __ load_heap_oop(Z_method, Address(Z_method, java_lang_invoke_LambdaForm::vmentry_offset()), + noreg, noreg, IS_NOT_NULL); + __ load_heap_oop(Z_method, Address(Z_method, java_lang_invoke_MemberName::method_offset()), + noreg, noreg, IS_NOT_NULL); + __ z_lg(Z_method, Address(Z_method, java_lang_invoke_ResolvedMethodName::vmtarget_offset())); + __ z_stg(Z_method, Address(Z_thread, JavaThread::callee_target_offset())); // just in case callee is deoptimized + + __ z_br(Z_R14); + + return start; + } + void generate_initial_stubs() { // Generates all stubs and initializes the entry points. @@ -3110,6 +3133,7 @@ class StubGenerator: public StubCodeGenerator { } StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); } void generate_compiler_stubs() { diff --git a/src/hotspot/cpu/s390/upcallLinker_s390.cpp b/src/hotspot/cpu/s390/upcallLinker_s390.cpp index 734b4e89c7cb2..8baad40a519a4 100644 --- a/src/hotspot/cpu/s390/upcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/upcallLinker_s390.cpp @@ -23,6 +23,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "classfile/javaClasses.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "prims/upcallLinker.hpp" @@ -116,7 +117,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; // arg save & restore + move -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, @@ -206,7 +207,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("on_entry {"); __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry)); __ z_aghik(Z_ARG1, Z_SP, frame_data_offset); - __ load_const_optimized(Z_ARG2, (intptr_t)receiver); __ call(call_target_address); __ z_lgr(Z_thread, Z_RET); __ block_comment("} on_entry"); @@ -216,12 +216,11 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, arg_shuffle.generate(_masm, shuffle_reg, abi._shadow_space_bytes, frame::z_jit_out_preserve_size); __ block_comment("} argument_shuffle"); - __ block_comment("receiver {"); - __ get_vm_result(Z_ARG1); - __ block_comment("} receiver"); - - __ load_const_optimized(Z_method, (intptr_t)entry); - __ z_stg(Z_method, Address(Z_thread, in_bytes(JavaThread::callee_target_offset()))); + __ block_comment("load_target {"); + __ load_const_optimized(Z_ARG1, (intptr_t)receiver); + __ load_const_optimized(call_target_address, StubRoutines::upcall_stub_load_target()); + __ call(call_target_address); // load taget Method* into Z_method + __ block_comment("} load_target"); __ z_lg(call_target_address, Address(Z_method, in_bytes(Method::from_compiled_offset()))); __ call(call_target_address); @@ -274,7 +273,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, #ifndef PRODUCT stringStream ss; - ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + ss.print("upcall_stub_%s", signature->as_C_string()); const char* name = _masm->code_string(ss.as_string()); #else // PRODUCT const char* name = "upcall_stub"; diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index c1679cd111f5a..e4ab99bf1c36f 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -557,6 +557,14 @@ bool Assembler::needs_rex2(Register reg1, Register reg2, Register reg3) { return rex2; } +#ifndef PRODUCT +bool Assembler::needs_evex(XMMRegister reg1, XMMRegister reg2, XMMRegister reg3) { + return (reg1->is_valid() && reg1->encoding() >= 16) || + (reg2->is_valid() && reg2->encoding() >= 16) || + (reg3->is_valid() && reg3->encoding() >= 16); +} +#endif + bool Assembler::needs_eevex(Register reg1, Register reg2, Register reg3) { return needs_rex2(reg1, reg2, reg3); } @@ -3525,7 +3533,7 @@ void Assembler::vmaskmovpd(Address dst, XMMRegister src, XMMRegister mask, int v // Move Unaligned EVEX enabled Vector (programmable : 8,16,32,64) void Assembler::evmovdqub(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_embedded_opmask_register_specifier(mask); attributes.set_is_evex_instruction(); @@ -3542,7 +3550,7 @@ void Assembler::evmovdqub(XMMRegister dst, XMMRegister src, int vector_len) { } void Assembler::evmovdqub(XMMRegister dst, KRegister mask, Address src, bool merge, int vector_len) { - assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); @@ -3562,7 +3570,7 @@ void Assembler::evmovdqub(XMMRegister dst, Address src, int vector_len) { } void Assembler::evmovdqub(Address dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); assert(src != xnoreg, "sanity"); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); @@ -3577,13 +3585,18 @@ void Assembler::evmovdqub(Address dst, KRegister mask, XMMRegister src, bool mer emit_operand(src, dst, 0); } +void Assembler::evmovdquw(XMMRegister dst, XMMRegister src, int vector_len) { + // Unmasked instruction + evmovdquw(dst, k0, src, /*merge*/ false, vector_len); +} + void Assembler::evmovdquw(XMMRegister dst, Address src, int vector_len) { // Unmasked instruction evmovdquw(dst, k0, src, /*merge*/ false, vector_len); } void Assembler::evmovdquw(XMMRegister dst, KRegister mask, Address src, bool merge, int vector_len) { - assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); @@ -3603,7 +3616,7 @@ void Assembler::evmovdquw(Address dst, XMMRegister src, int vector_len) { } void Assembler::evmovdquw(Address dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); assert(src != xnoreg, "sanity"); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); @@ -3618,6 +3631,19 @@ void Assembler::evmovdquw(Address dst, KRegister mask, XMMRegister src, bool mer emit_operand(src, dst, 0); } +void Assembler::evmovdquw(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_embedded_opmask_register_specifier(mask); + attributes.set_is_evex_instruction(); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int16(0x6F, (0xC0 | encode)); +} + + void Assembler::evmovdqul(XMMRegister dst, XMMRegister src, int vector_len) { // Unmasked instruction evmovdqul(dst, k0, src, /*merge*/ false, vector_len); @@ -4439,11 +4465,6 @@ void Assembler::enotl(Register dst, Register src) { emit_int16((unsigned char)0xF7, (0xD0 | encode)); } -void Assembler::orw(Register dst, Register src) { - (void)prefix_and_encode(dst->encoding(), src->encoding()); - emit_arith(0x0B, 0xC0, dst, src); -} - void Assembler::eorw(Register dst, Register src1, Register src2, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); @@ -4738,22 +4759,6 @@ void Assembler::vpermpd(XMMRegister dst, XMMRegister src, int imm8, int vector_l emit_int24(0x01, (0xC0 | encode), imm8); } -void Assembler::evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); - emit_int16(0x76, (0xC0 | encode)); -} - -void Assembler::evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - assert(VM_Version::supports_avx512_vbmi(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); - emit_int16(0x7D, (0xC0 | encode)); -} - void Assembler::evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512_vbmi(), ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -4826,6 +4831,7 @@ void Assembler::vpcmpeqb(XMMRegister dst, XMMRegister src1, Address src2, int ve // In this context, kdst is written the mask used to process the equal components void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(kdst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -4833,7 +4839,8 @@ void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, XMMRegister src, int } void Assembler::evpcmpgtb(KRegister kdst, XMMRegister nds, Address src, int vector_len) { - assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512bw(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); @@ -4845,7 +4852,8 @@ void Assembler::evpcmpgtb(KRegister kdst, XMMRegister nds, Address src, int vect } void Assembler::evpcmpgtb(KRegister kdst, KRegister mask, XMMRegister nds, Address src, int vector_len) { - assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512bw(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); @@ -4858,16 +4866,34 @@ void Assembler::evpcmpgtb(KRegister kdst, KRegister mask, XMMRegister nds, Addre emit_operand(as_Register(dst_enc), src, 0); } +void Assembler::evpcmpub(KRegister kdst, XMMRegister nds, XMMRegister src, ComparisonPredicate vcc, int vector_len) { + assert(VM_Version::supports_avx512bw(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(kdst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x3E, (0xC0 | encode), vcc); +} + void Assembler::evpcmpuw(KRegister kdst, XMMRegister nds, XMMRegister src, ComparisonPredicate vcc, int vector_len) { - assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512bw(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(kdst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int24(0x3E, (0xC0 | encode), vcc); } +void Assembler::evpcmpud(KRegister kdst, XMMRegister nds, XMMRegister src, ComparisonPredicate vcc, int vector_len) { + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(kdst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x1E, (0xC0 | encode), vcc); +} + void Assembler::evpcmpuq(KRegister kdst, XMMRegister nds, XMMRegister src, ComparisonPredicate vcc, int vector_len) { - assert(VM_Version::supports_avx512vl(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(kdst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); @@ -4875,7 +4901,8 @@ void Assembler::evpcmpuq(KRegister kdst, XMMRegister nds, XMMRegister src, Compa } void Assembler::evpcmpuw(KRegister kdst, XMMRegister nds, Address src, ComparisonPredicate vcc, int vector_len) { - assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512bw(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); @@ -4889,6 +4916,7 @@ void Assembler::evpcmpuw(KRegister kdst, XMMRegister nds, Address src, Compariso void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, Address src, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -4900,7 +4928,8 @@ void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, Address src, int vect } void Assembler::evpcmpeqb(KRegister kdst, KRegister mask, XMMRegister nds, Address src, int vector_len) { - assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512bw(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); @@ -6767,6 +6796,27 @@ void Assembler::sha256msg2(XMMRegister dst, XMMRegister src) { emit_int16((unsigned char)0xCD, (0xC0 | encode)); } +void Assembler::sha512msg1(XMMRegister dst, XMMRegister src) { + assert(VM_Version::supports_sha512() && VM_Version::supports_avx(), ""); + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + emit_int16((unsigned char)0xCC, (0xC0 | encode)); +} + +void Assembler::sha512msg2(XMMRegister dst, XMMRegister src) { + assert(VM_Version::supports_sha512() && VM_Version::supports_avx(), ""); + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + emit_int16((unsigned char)0xCD, (0xC0 | encode)); +} + +void Assembler::sha512rnds2(XMMRegister dst, XMMRegister nds, XMMRegister src) { + assert(VM_Version::supports_sha512() && VM_Version::supports_avx(), ""); + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + emit_int16((unsigned char)0xCB, (0xC0 | encode)); +} + void Assembler::shll(Register dst, int imm8) { assert(isShiftCount(imm8), "illegal shift count"); int encode = prefix_and_encode(dst->encoding()); @@ -8353,6 +8403,161 @@ void Assembler::vpaddq(XMMRegister dst, XMMRegister nds, Address src, int vector emit_operand(dst, src, 0); } +void Assembler::vpaddsb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds, src) || VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xEC, (0xC0 | encode)); +} + +void Assembler::vpaddsb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xEC); + emit_operand(dst, src, 0); +} + +void Assembler::vpaddsw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds, src) || VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xED, (0xC0 | encode)); +} + +void Assembler::vpaddsw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xED); + emit_operand(dst, src, 0); +} + +void Assembler::vpaddusb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds, src) || VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xDC, (0xC0 | encode)); +} + +void Assembler::vpaddusb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xDC); + emit_operand(dst, src, 0); +} + + +void Assembler::vpaddusw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds, src) || VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xDD, (0xC0 | encode)); +} + +void Assembler::vpaddusw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xDD); + emit_operand(dst, src, 0); +} + + +void Assembler::vpsubsb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds, src) || VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xE8, (0xC0 | encode)); +} + +void Assembler::vpsubsb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xE8); + emit_operand(dst, src, 0); +} + +void Assembler::vpsubsw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds, src) || VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xE9, (0xC0 | encode)); +} + +void Assembler::vpsubsw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xE9); + emit_operand(dst, src, 0); +} + +void Assembler::vpsubusb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds, src) || VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xD8, (0xC0 | encode)); +} + +void Assembler::vpsubusb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD8); + emit_operand(dst, src, 0); +} + +void Assembler::vpsubusw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds, src) || VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xD9, (0xC0 | encode)); +} + +void Assembler::vpsubusw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD9); + emit_operand(dst, src, 0); +} + + void Assembler::psubb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); @@ -8382,13 +8587,6 @@ void Assembler::psubq(XMMRegister dst, XMMRegister src) { emit_int8((0xC0 | encode)); } -void Assembler::vpsubusb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xD8, (0xC0 | encode)); -} - void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); @@ -8518,6 +8716,15 @@ void Assembler::vpmuludq(XMMRegister dst, XMMRegister nds, XMMRegister src, int emit_int16((unsigned char)0xF4, (0xC0 | encode)); } +void Assembler::vpmuldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + (vector_len == AVX_256bit ? VM_Version::supports_avx2() : VM_Version::supports_evex()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_rex_vex_w_reverted(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x28, (0xC0 | encode)); +} + void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); @@ -8565,14 +8772,6 @@ void Assembler::vpminsb(XMMRegister dst, XMMRegister nds, XMMRegister src, int v emit_int16(0x38, (0xC0 | encode)); } -void Assembler::vpminub(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : - (vector_len == AVX_256bit ? VM_Version::supports_avx2() : VM_Version::supports_avx512bw()), ""); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16(0xDA, (0xC0 | encode)); -} - void Assembler::pminsw(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); @@ -8718,43 +8917,383 @@ void Assembler::vmaxpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve emit_int16(0x5F, (0xC0 | encode)); } -// Shift packed integers left by specified number of bits. -void Assembler::psllw(XMMRegister dst, int shift) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - // XMM6 is for /6 encoding: 66 0F 71 /6 ib - int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int24(0x71, (0xC0 | encode), shift & 0xFF); -} - -void Assembler::pslld(XMMRegister dst, int shift) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); - // XMM6 is for /6 encoding: 66 0F 72 /6 ib - int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int24(0x72, (0xC0 | encode), shift & 0xFF); -} - -void Assembler::psllq(XMMRegister dst, int shift) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); - // XMM6 is for /6 encoding: 66 0F 73 /6 ib - int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int24(0x73, (0xC0 | encode), shift & 0xFF); +void Assembler::vpminub(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds, src) || VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xDA, (0xC0 | encode)); } -void Assembler::psllw(XMMRegister dst, XMMRegister shift) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xF1, (0xC0 | encode)); +void Assembler::vpminub(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xDA); + emit_operand(dst, src, 0); } -void Assembler::pslld(XMMRegister dst, XMMRegister shift) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xF2, (0xC0 | encode)); +void Assembler::evpminub(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xDA, (0xC0 | encode)); +} + +void Assembler::evpminub(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xDA); + emit_operand(dst, src, 0); +} + +void Assembler::vpminuw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x3A, (0xC0 | encode)); +} + +void Assembler::vpminuw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8((unsigned char)0x3A); + emit_operand(dst, src, 0); +} + +void Assembler::evpminuw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x3A, (0xC0 | encode)); +} + +void Assembler::evpminuw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x3A); + emit_operand(dst, src, 0); +} + +void Assembler::vpminud(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x3B, (0xC0 | encode)); +} + +void Assembler::vpminud(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8((unsigned char)0x3B); + emit_operand(dst, src, 0); +} + +void Assembler::evpminud(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x3B, (0xC0 | encode)); +} + +void Assembler::evpminud(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x3B); + emit_operand(dst, src, 0); +} + +void Assembler::evpminuq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x3B, (0xC0 | encode)); +} + +void Assembler::evpminuq(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x3B); + emit_operand(dst, src, 0); +} + +void Assembler::vpmaxub(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + (vector_len == AVX_256bit ? VM_Version::supports_avx2() : VM_Version::supports_avx512bw()), ""); + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xDE, (0xC0 | encode)); +} + +void Assembler::vpmaxub(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + (vector_len == AVX_256bit ? VM_Version::supports_avx2() : VM_Version::supports_avx512bw()), ""); + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xDE); + emit_operand(dst, src, 0); +} + +void Assembler::evpmaxub(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xDE, (0xC0 | encode)); +} + +void Assembler::evpmaxub(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xDE); + emit_operand(dst, src, 0); +} + +void Assembler::vpmaxuw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + (vector_len == AVX_256bit ? VM_Version::supports_avx2() : VM_Version::supports_avx512bw()), ""); + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x3E, (0xC0 | encode)); +} + +void Assembler::vpmaxuw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + (vector_len == AVX_256bit ? VM_Version::supports_avx2() : VM_Version::supports_avx512bw()), ""); + assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8((unsigned char)0x3E); + emit_operand(dst, src, 0); +} + +void Assembler::evpmaxuw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x3E, (0xC0 | encode)); +} + +void Assembler::evpmaxuw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x3E); + emit_operand(dst, src, 0); +} + +void Assembler::vpmaxud(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0, ""); + assert((vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds, src) || VM_Version::supports_avx512vl())), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x3F, (0xC0 | encode)); +} + +void Assembler::vpmaxud(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(UseAVX > 0, ""); + assert((vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8((unsigned char)0x3F); + emit_operand(dst, src, 0); +} + +void Assembler::evpmaxud(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x3F, (0xC0 | encode)); +} + +void Assembler::evpmaxud(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x3F); + emit_operand(dst, src, 0); +} + +void Assembler::evpmaxuq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x3F, (0xC0 | encode)); +} + +void Assembler::evpmaxuq(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x3F); + emit_operand(dst, src, 0); +} + +// Shift packed integers left by specified number of bits. +void Assembler::psllw(XMMRegister dst, int shift) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + // XMM6 is for /6 encoding: 66 0F 71 /6 ib + int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int24(0x71, (0xC0 | encode), shift & 0xFF); +} + +void Assembler::pslld(XMMRegister dst, int shift) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + // XMM6 is for /6 encoding: 66 0F 72 /6 ib + int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int24(0x72, (0xC0 | encode), shift & 0xFF); +} + +void Assembler::psllq(XMMRegister dst, int shift) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + // XMM6 is for /6 encoding: 66 0F 73 /6 ib + int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int24(0x73, (0xC0 | encode), shift & 0xFF); +} + +void Assembler::psllw(XMMRegister dst, XMMRegister shift) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xF1, (0xC0 | encode)); +} + +void Assembler::pslld(XMMRegister dst, XMMRegister shift) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xF2, (0xC0 | encode)); } void Assembler::psllq(XMMRegister dst, XMMRegister shift) { @@ -10080,8 +10619,178 @@ void Assembler::vpunpcklqdq(XMMRegister dst, XMMRegister nds, XMMRegister src, i emit_int16(0x6C, (0xC0 | encode)); } -// xmm/mem sourced byte/word/dword/qword replicate -void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { +// xmm/mem sourced byte/word/dword/qword replicate +void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xFC, (0xC0 | encode)); +} + +void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + InstructionMark im(this); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFC); + emit_operand(dst, src, 0); +} + +void Assembler::evpaddw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xFD, (0xC0 | encode)); +} + +void Assembler::evpaddw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + InstructionMark im(this); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFD); + emit_operand(dst, src, 0); +} + +void Assembler::evpaddd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xFE, (0xC0 | encode)); +} + +void Assembler::evpaddd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFE); + emit_operand(dst, src, 0); +} + +void Assembler::evpaddq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xD4, (0xC0 | encode)); +} + +void Assembler::evpaddq(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD4); + emit_operand(dst, src, 0); +} + +void Assembler::evaddps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int16(0x58, (0xC0 | encode)); +} + +void Assembler::evaddps(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_operand(dst, src, 0); +} + +void Assembler::evaddpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16(0x58, (0xC0 | encode)); +} + +void Assembler::evaddpd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_operand(dst, src, 0); +} + +void Assembler::evpsubb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -10090,10 +10799,10 @@ void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMReg attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xFC, (0xC0 | encode)); + emit_int16((unsigned char)0xF8, (0xC0 | encode)); } -void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evpsubb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); @@ -10104,11 +10813,11 @@ void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int8((unsigned char)0xFC); + emit_int8((unsigned char)0xF8); emit_operand(dst, src, 0); } -void Assembler::evpaddw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { +void Assembler::evpsubw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -10117,10 +10826,10 @@ void Assembler::evpaddw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMReg attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xFD, (0xC0 | encode)); + emit_int16((unsigned char)0xF9, (0xC0 | encode)); } -void Assembler::evpaddw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evpsubw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); @@ -10131,11 +10840,11 @@ void Assembler::evpaddw(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int8((unsigned char)0xFD); + emit_int8((unsigned char)0xF9); emit_operand(dst, src, 0); } -void Assembler::evpaddd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { +void Assembler::evpsubd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); @@ -10145,10 +10854,10 @@ void Assembler::evpaddd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMReg attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xFE, (0xC0 | encode)); + emit_int16((unsigned char)0xFA, (0xC0 | encode)); } -void Assembler::evpaddd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evpsubd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); @@ -10160,11 +10869,11 @@ void Assembler::evpaddd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int8((unsigned char)0xFE); + emit_int8((unsigned char)0xFA); emit_operand(dst, src, 0); } -void Assembler::evpaddq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { +void Assembler::evpsubq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); @@ -10174,10 +10883,10 @@ void Assembler::evpaddq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMReg attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xD4, (0xC0 | encode)); + emit_int16((unsigned char)0xFB, (0xC0 | encode)); } -void Assembler::evpaddq(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evpsubq(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); @@ -10189,11 +10898,11 @@ void Assembler::evpaddq(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int8((unsigned char)0xD4); + emit_int8((unsigned char)0xFB); emit_operand(dst, src, 0); } -void Assembler::evaddps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { +void Assembler::evsubps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); @@ -10203,10 +10912,10 @@ void Assembler::evaddps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMReg attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); - emit_int16(0x58, (0xC0 | encode)); + emit_int16(0x5C, (0xC0 | encode)); } -void Assembler::evaddps(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evsubps(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); @@ -10218,11 +10927,11 @@ void Assembler::evaddps(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); - emit_int8(0x58); + emit_int8(0x5C); emit_operand(dst, src, 0); } -void Assembler::evaddpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { +void Assembler::evsubpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); @@ -10232,10 +10941,10 @@ void Assembler::evaddpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMReg attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16(0x58, (0xC0 | encode)); + emit_int16(0x5C, (0xC0 | encode)); } -void Assembler::evaddpd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evsubpd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); @@ -10247,11 +10956,11 @@ void Assembler::evaddpd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int8(0x58); + emit_int8(0x5C); emit_operand(dst, src, 0); } -void Assembler::evpsubb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { +void Assembler::evpaddsb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -10260,10 +10969,10 @@ void Assembler::evpsubb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMReg attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xF8, (0xC0 | encode)); + emit_int16((unsigned char)0xEC, (0xC0 | encode)); } -void Assembler::evpsubb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evpaddsb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); @@ -10274,11 +10983,11 @@ void Assembler::evpsubb(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int8((unsigned char)0xF8); + emit_int8((unsigned char)0xEC); emit_operand(dst, src, 0); } -void Assembler::evpsubw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { +void Assembler::evpaddsw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -10287,10 +10996,10 @@ void Assembler::evpsubw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMReg attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xF9, (0xC0 | encode)); + emit_int16((unsigned char)0xED, (0xC0 | encode)); } -void Assembler::evpsubw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evpaddsw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); @@ -10301,13 +11010,12 @@ void Assembler::evpsubw(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int8((unsigned char)0xF9); + emit_int8((unsigned char)0xED); emit_operand(dst, src, 0); } -void Assembler::evpsubd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_evex(), ""); - assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); +void Assembler::evpaddusb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); @@ -10315,13 +11023,12 @@ void Assembler::evpsubd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMReg attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xFA, (0xC0 | encode)); + emit_int16((unsigned char)0xDC, (0xC0 | encode)); } -void Assembler::evpsubd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evpaddusb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); - assert(VM_Version::supports_evex(), ""); - assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); @@ -10330,28 +11037,26 @@ void Assembler::evpsubd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int8((unsigned char)0xFA); + emit_int8((unsigned char)0xDC); emit_operand(dst, src, 0); } -void Assembler::evpsubq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_evex(), ""); - assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); +void Assembler::evpaddusw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16((unsigned char)0xFB, (0xC0 | encode)); + emit_int16((unsigned char)0xDD, (0xC0 | encode)); } -void Assembler::evpsubq(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evpaddusw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); - assert(VM_Version::supports_evex(), ""); - assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); @@ -10359,27 +11064,25 @@ void Assembler::evpsubq(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int8((unsigned char)0xFB); + emit_int8((unsigned char)0xDD); emit_operand(dst, src, 0); } -void Assembler::evsubps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_evex(), ""); - assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); +void Assembler::evpsubsb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { attributes.reset_is_clear_context(); } - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); - emit_int16(0x5C, (0xC0 | encode)); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xE8, (0xC0 | encode)); } -void Assembler::evsubps(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evpsubsb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); - assert(VM_Version::supports_evex(), ""); - assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); @@ -10387,29 +11090,27 @@ void Assembler::evsubps(XMMRegister dst, KRegister mask, XMMRegister nds, Addres if (merge) { attributes.reset_is_clear_context(); } - vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); - emit_int8(0x5C); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xE8); emit_operand(dst, src, 0); } -void Assembler::evsubpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_evex(), ""); - assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); +void Assembler::evpsubsw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int16(0x5C, (0xC0 | encode)); + emit_int16((unsigned char)0xE9, (0xC0 | encode)); } -void Assembler::evsubpd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { +void Assembler::evpsubsw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { InstructionMark im(this); - assert(VM_Version::supports_evex(), ""); - assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); @@ -10417,7 +11118,62 @@ void Assembler::evsubpd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres attributes.reset_is_clear_context(); } vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int8(0x5C); + emit_int8((unsigned char)0xE9); + emit_operand(dst, src, 0); +} + +void Assembler::evpsubusb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xD8, (0xC0 | encode)); +} + +void Assembler::evpsubusb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + InstructionMark im(this); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD8); + emit_operand(dst, src, 0); +} + +void Assembler::evpsubusw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xD9, (0xC0 | encode)); +} + + +void Assembler::evpsubusw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + InstructionMark im(this); + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD9); emit_operand(dst, src, 0); } @@ -10504,6 +11260,18 @@ void Assembler::evpmullq(XMMRegister dst, KRegister mask, XMMRegister nds, Addre emit_operand(dst, src, 0); } +void Assembler::evpmulhw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xE5, (0xC0 | encode)); +} + void Assembler::evmulps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); @@ -11686,6 +12454,19 @@ void Assembler::evbroadcasti64x2(XMMRegister dst, Address src, int vector_len) { emit_operand(dst, src, 0); } +void Assembler::vbroadcasti128(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx2(), ""); + assert(vector_len == AVX_256bit, ""); + assert(dst != xnoreg, "sanity"); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); + // swap src<->dst for encoding + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x5A); + emit_operand(dst, src, 0); +} + // scalar single/double precision replicate // duplicate single precision data from src into programmed locations in dest : requires AVX512VL @@ -16103,3 +16884,84 @@ void InstructionAttr::set_address_attributes(int tuple_type, int input_size_in_b _input_size_in_bits = input_size_in_bits; } } + +void Assembler::evpermi2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_vbmi() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x75, (0xC0 | encode)); +} + +void Assembler::evpermi2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x75, (0xC0 | encode)); +} + +void Assembler::evpermi2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x76, (0xC0 | encode)); +} + +void Assembler::evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x76, (0xC0 | encode)); +} + +void Assembler::evpermi2ps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x77, (0xC0 | encode)); +} + +void Assembler::evpermi2pd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x77, (0xC0 | encode)); +} + +void Assembler::evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_vbmi(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x7D, (0xC0 | encode)); +} + +void Assembler::evpermt2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(vector_len <= AVX_256bit ? VM_Version::supports_avx512vlbw() : VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x7D, (0xC0 | encode)); +} + +void Assembler::evpermt2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x7E, (0xC0 | encode)); +} + +void Assembler::evpermt2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x7E, (0xC0 | encode)); +} + diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index eace7bb9cc169..420c28254d53f 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -780,6 +780,7 @@ class Assembler : public AbstractAssembler { bool needs_eevex(Register reg1, Register reg2 = noreg, Register reg3 = noreg); bool needs_eevex(int enc1, int enc2 = -1, int enc3 = -1); + NOT_PRODUCT(bool needs_evex(XMMRegister reg1, XMMRegister reg2 = xnoreg, XMMRegister reg3 = xnoreg);) void rex_prefix(Address adr, XMMRegister xreg, VexSimdPrefix pre, VexOpcode opc, bool rex_w); @@ -1756,6 +1757,7 @@ class Assembler : public AbstractAssembler { void evmovdqub(XMMRegister dst, KRegister mask, Address src, bool merge, int vector_len); void evmovdqub(Address dst, KRegister mask, XMMRegister src, bool merge, int vector_len); + void evmovdquw(XMMRegister dst, XMMRegister src, int vector_len); void evmovdquw(XMMRegister dst, Address src, int vector_len); void evmovdquw(Address dst, XMMRegister src, int vector_len); void evmovdquw(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len); @@ -1901,7 +1903,6 @@ class Assembler : public AbstractAssembler { #endif void btq(Register dst, Register src); - void orw(Register dst, Register src); void eorw(Register dst, Register src1, Register src2, bool no_flags); void orl(Address dst, int32_t imm32); @@ -1962,9 +1963,17 @@ class Assembler : public AbstractAssembler { void vpermilps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpermilpd(XMMRegister dst, XMMRegister src, int imm8, int vector_len); void vpermpd(XMMRegister dst, XMMRegister src, int imm8, int vector_len); + void evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len); + void evpermi2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2ps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2pd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); - void evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len); + void evpermt2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermt2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermt2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void pause(); @@ -1988,9 +1997,12 @@ class Assembler : public AbstractAssembler { void evpcmpgtb(KRegister kdst, XMMRegister nds, Address src, int vector_len); void evpcmpgtb(KRegister kdst, KRegister mask, XMMRegister nds, Address src, int vector_len); + void evpcmpub(KRegister kdst, XMMRegister nds, XMMRegister src, ComparisonPredicate vcc, int vector_len); + void evpcmpuw(KRegister kdst, XMMRegister nds, XMMRegister src, ComparisonPredicate vcc, int vector_len); void evpcmpuw(KRegister kdst, XMMRegister nds, Address src, ComparisonPredicate vcc, int vector_len); + void evpcmpud(KRegister kdst, XMMRegister nds, XMMRegister src, ComparisonPredicate vcc, int vector_len); void evpcmpuq(KRegister kdst, XMMRegister nds, XMMRegister src, ComparisonPredicate vcc, int vector_len); void pcmpeqw(XMMRegister dst, XMMRegister src); @@ -2340,6 +2352,9 @@ class Assembler : public AbstractAssembler { void sha256rnds2(XMMRegister dst, XMMRegister src); void sha256msg1(XMMRegister dst, XMMRegister src); void sha256msg2(XMMRegister dst, XMMRegister src); + void sha512rnds2(XMMRegister dst, XMMRegister nds, XMMRegister src); + void sha512msg1(XMMRegister dst, XMMRegister src); + void sha512msg2(XMMRegister dst, XMMRegister src); void shldl(Register dst, Register src); void eshldl(Register dst, Register src1, Register src2, bool no_flags); @@ -2671,6 +2686,40 @@ class Assembler : public AbstractAssembler { void vpaddd(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void vpaddq(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + // Saturating packed insturctions. + void vpaddsb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpaddsw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpaddusb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpaddusw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpaddsb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpaddsw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpaddusb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpaddusw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void vpsubsb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpsubsw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpsubusb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpsubusw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpsubsb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpsubsw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpsubusb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpsubusw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void vpaddsb(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void vpaddsw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void vpaddusb(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void vpaddusw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void evpaddsb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpaddsw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpaddusb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpaddusw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void vpsubsb(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void vpsubsw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void vpsubusb(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void vpsubusw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void evpsubsb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpsubsw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpsubusb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpsubusw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + // Leaf level assembler routines for masked operations. void evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); void evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); @@ -2696,6 +2745,7 @@ class Assembler : public AbstractAssembler { void evsubps(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); void evsubpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); void evsubpd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpmulhw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); void evpmullw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); void evpmullw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); void evpmulld(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); @@ -2814,7 +2864,6 @@ class Assembler : public AbstractAssembler { void psubw(XMMRegister dst, XMMRegister src); void psubd(XMMRegister dst, XMMRegister src); void psubq(XMMRegister dst, XMMRegister src); - void vpsubusb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpsubw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpsubd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); @@ -2832,6 +2881,7 @@ class Assembler : public AbstractAssembler { void vpmulld(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpmullq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpmuludq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpmuldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void vpmulld(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void evpmullq(XMMRegister dst, XMMRegister nds, Address src, int vector_len); @@ -2840,7 +2890,6 @@ class Assembler : public AbstractAssembler { // Minimum of packed integers void pminsb(XMMRegister dst, XMMRegister src); void vpminsb(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); - void vpminub(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); void pminsw(XMMRegister dst, XMMRegister src); void vpminsw(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); void pminsd(XMMRegister dst, XMMRegister src); @@ -2864,6 +2913,38 @@ class Assembler : public AbstractAssembler { void maxpd(XMMRegister dst, XMMRegister src); void vmaxpd(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); + // Unsigned maximum packed integers. + void vpmaxub(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); + void vpmaxuw(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); + void vpmaxud(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); + void vpmaxub(XMMRegister dst, XMMRegister src1, Address src2, int vector_len); + void vpmaxuw(XMMRegister dst, XMMRegister src1, Address src2, int vector_len); + void vpmaxud(XMMRegister dst, XMMRegister src1, Address src2, int vector_len); + void evpmaxub(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpmaxuw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpmaxud(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpmaxuq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpmaxub(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpmaxuw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpmaxud(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpmaxuq(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + + // Unsigned minimum packed integers. + void vpminub(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); + void vpminuw(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); + void vpminud(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); + void vpminub(XMMRegister dst, XMMRegister src1, Address src2, int vector_len); + void vpminuw(XMMRegister dst, XMMRegister src1, Address src2, int vector_len); + void vpminud(XMMRegister dst, XMMRegister src1, Address src2, int vector_len); + void evpminub(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpminuw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpminud(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpminuq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpminub(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpminuw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpminud(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpminuq(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + // Shift left packed integers void psllw(XMMRegister dst, int shift); void pslld(XMMRegister dst, int shift); @@ -3030,6 +3111,7 @@ class Assembler : public AbstractAssembler { void evbroadcasti32x4(XMMRegister dst, Address src, int vector_len); void evbroadcasti64x2(XMMRegister dst, XMMRegister src, int vector_len); void evbroadcasti64x2(XMMRegister dst, Address src, int vector_len); + void vbroadcasti128(XMMRegister dst, Address src, int vector_len); // scalar single/double/128bit precision replicate void vbroadcastss(XMMRegister dst, XMMRegister src, int vector_len); diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index c3444d5a5abce..64265a9690940 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -1333,10 +1333,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch } #endif - if (!(UseZGC && !ZGenerational)) { - // Load barrier has not yet been applied, so ZGC can't verify the oop here - __ verify_oop(dest->as_register()); - } + __ verify_oop(dest->as_register()); } } @@ -1578,6 +1575,7 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { if (op->init_check()) { add_debug_info_for_null_check_here(op->stub()->info()); + // init_state needs acquire, but x86 is TSO, and so we are already good. __ cmpb(Address(op->klass()->as_register(), InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 839745f76ec6a..61c8036b1cec9 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -477,9 +477,9 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t // StoreLoad achieves this. membar(StoreLoad); - // Check if the entry lists are empty. - movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + // Check if the entry lists are empty (EntryList first - by convention). + movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); jccb(Assembler::zero, LSuccess); // If so we are done. // Check if there is a successor. @@ -806,9 +806,9 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, // StoreLoad achieves this. membar(StoreLoad); - // Check if the entry lists are empty. - movptr(reg_rax, cxq_address); - orptr(reg_rax, EntryList_address); + // Check if the entry lists are empty (EntryList first - by convention). + movptr(reg_rax, EntryList_address); + orptr(reg_rax, cxq_address); jccb(Assembler::zero, unlocked); // If so we are done. // Check if there is a successor. @@ -822,7 +822,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, } movptr(Address(thread, JavaThread::unlocked_inflated_monitor_offset()), monitor); - testl(monitor, monitor); // Fast Unlock ZF = 0 + orl(t, 1); // Fast Unlock ZF = 0 jmpb(slow_path); // Recursive unlock. @@ -837,8 +837,9 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, #ifdef ASSERT // Check that unlocked label is reached with ZF set. Label zf_correct; + Label zf_bad_zero; jcc(Assembler::zero, zf_correct); - stop("Fast Unlock ZF != 1"); + jmp(zf_bad_zero); #endif bind(slow_path); @@ -847,8 +848,10 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, } #ifdef ASSERT // Check that stub->continuation() label is reached with ZF not set. - jccb(Assembler::notZero, zf_correct); + jcc(Assembler::notZero, zf_correct); stop("Fast Unlock ZF != 0"); + bind(zf_bad_zero); + stop("Fast Unlock ZF != 1"); bind(zf_correct); #endif // C2 uses the value of ZF to determine the continuation. @@ -936,6 +939,72 @@ void C2_MacroAssembler::pminmax(int opcode, BasicType elem_bt, XMMRegister dst, } } +void C2_MacroAssembler::vpuminmax(int opcode, BasicType elem_bt, XMMRegister dst, + XMMRegister src1, Address src2, int vlen_enc) { + assert(opcode == Op_UMinV || opcode == Op_UMaxV, "sanity"); + if (opcode == Op_UMinV) { + switch(elem_bt) { + case T_BYTE: vpminub(dst, src1, src2, vlen_enc); break; + case T_SHORT: vpminuw(dst, src1, src2, vlen_enc); break; + case T_INT: vpminud(dst, src1, src2, vlen_enc); break; + case T_LONG: evpminuq(dst, k0, src1, src2, false, vlen_enc); break; + default: fatal("Unsupported type %s", type2name(elem_bt)); break; + } + } else { + assert(opcode == Op_UMaxV, "required"); + switch(elem_bt) { + case T_BYTE: vpmaxub(dst, src1, src2, vlen_enc); break; + case T_SHORT: vpmaxuw(dst, src1, src2, vlen_enc); break; + case T_INT: vpmaxud(dst, src1, src2, vlen_enc); break; + case T_LONG: evpmaxuq(dst, k0, src1, src2, false, vlen_enc); break; + default: fatal("Unsupported type %s", type2name(elem_bt)); break; + } + } +} + +void C2_MacroAssembler::vpuminmaxq(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc) { + // T1 = -1 + vpcmpeqq(xtmp1, xtmp1, xtmp1, vlen_enc); + // T1 = -1 << 63 + vpsllq(xtmp1, xtmp1, 63, vlen_enc); + // Convert SRC2 to signed value i.e. T2 = T1 + SRC2 + vpaddq(xtmp2, xtmp1, src2, vlen_enc); + // Convert SRC1 to signed value i.e. T1 = T1 + SRC1 + vpaddq(xtmp1, xtmp1, src1, vlen_enc); + // Mask = T2 > T1 + vpcmpgtq(xtmp1, xtmp2, xtmp1, vlen_enc); + if (opcode == Op_UMaxV) { + // Res = Mask ? Src2 : Src1 + vpblendvb(dst, src1, src2, xtmp1, vlen_enc); + } else { + // Res = Mask ? Src1 : Src2 + vpblendvb(dst, src2, src1, xtmp1, vlen_enc); + } +} + +void C2_MacroAssembler::vpuminmax(int opcode, BasicType elem_bt, XMMRegister dst, + XMMRegister src1, XMMRegister src2, int vlen_enc) { + assert(opcode == Op_UMinV || opcode == Op_UMaxV, "sanity"); + if (opcode == Op_UMinV) { + switch(elem_bt) { + case T_BYTE: vpminub(dst, src1, src2, vlen_enc); break; + case T_SHORT: vpminuw(dst, src1, src2, vlen_enc); break; + case T_INT: vpminud(dst, src1, src2, vlen_enc); break; + case T_LONG: evpminuq(dst, k0, src1, src2, false, vlen_enc); break; + default: fatal("Unsupported type %s", type2name(elem_bt)); break; + } + } else { + assert(opcode == Op_UMaxV, "required"); + switch(elem_bt) { + case T_BYTE: vpmaxub(dst, src1, src2, vlen_enc); break; + case T_SHORT: vpmaxuw(dst, src1, src2, vlen_enc); break; + case T_INT: vpmaxud(dst, src1, src2, vlen_enc); break; + case T_LONG: evpmaxuq(dst, k0, src1, src2, false, vlen_enc); break; + default: fatal("Unsupported type %s", type2name(elem_bt)); break; + } + } +} + void C2_MacroAssembler::vpminmax(int opcode, BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc) { @@ -2359,6 +2428,10 @@ void C2_MacroAssembler::evmovdqu(BasicType type, KRegister kmask, Address dst, X MacroAssembler::evmovdqu(type, kmask, dst, src, merge, vector_len); } +void C2_MacroAssembler::evmovdqu(BasicType type, KRegister kmask, XMMRegister dst, XMMRegister src, bool merge, int vector_len) { + MacroAssembler::evmovdqu(type, kmask, dst, src, merge, vector_len); +} + void C2_MacroAssembler::vmovmask(BasicType elem_bt, XMMRegister dst, Address src, XMMRegister mask, int vec_enc) { switch(elem_bt) { @@ -2657,7 +2730,6 @@ void C2_MacroAssembler::vectortest(BasicType bt, XMMRegister src1, XMMRegister s } void C2_MacroAssembler::vpadd(BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc) { - assert(UseAVX >= 2, "required"); #ifdef ASSERT bool is_bw = ((elem_bt == T_BYTE) || (elem_bt == T_SHORT)); bool is_bw_supported = VM_Version::supports_avx512bw(); @@ -4631,7 +4703,126 @@ void C2_MacroAssembler::evmasked_op(int ideal_opc, BasicType eType, KRegister ma case Op_RotateLeftV: evrold(eType, dst, mask, src1, imm8, merge, vlen_enc); break; default: - fatal("Unsupported masked operation"); break; + fatal("Unsupported operation %s", NodeClassNames[ideal_opc]); + break; + } +} + +void C2_MacroAssembler::evmasked_saturating_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, XMMRegister src1, + XMMRegister src2, bool is_unsigned, bool merge, int vlen_enc) { + if (is_unsigned) { + evmasked_saturating_unsigned_op(ideal_opc, elem_bt, mask, dst, src1, src2, merge, vlen_enc); + } else { + evmasked_saturating_signed_op(ideal_opc, elem_bt, mask, dst, src1, src2, merge, vlen_enc); + } +} + +void C2_MacroAssembler::evmasked_saturating_signed_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, + XMMRegister src1, XMMRegister src2, bool merge, int vlen_enc) { + switch (elem_bt) { + case T_BYTE: + if (ideal_opc == Op_SaturatingAddV) { + evpaddsb(dst, mask, src1, src2, merge, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + evpsubsb(dst, mask, src1, src2, merge, vlen_enc); + } + break; + case T_SHORT: + if (ideal_opc == Op_SaturatingAddV) { + evpaddsw(dst, mask, src1, src2, merge, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + evpsubsw(dst, mask, src1, src2, merge, vlen_enc); + } + break; + default: + fatal("Unsupported type %s", type2name(elem_bt)); + break; + } +} + +void C2_MacroAssembler::evmasked_saturating_unsigned_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, + XMMRegister src1, XMMRegister src2, bool merge, int vlen_enc) { + switch (elem_bt) { + case T_BYTE: + if (ideal_opc == Op_SaturatingAddV) { + evpaddusb(dst, mask, src1, src2, merge, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + evpsubusb(dst, mask, src1, src2, merge, vlen_enc); + } + break; + case T_SHORT: + if (ideal_opc == Op_SaturatingAddV) { + evpaddusw(dst, mask, src1, src2, merge, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + evpsubusw(dst, mask, src1, src2, merge, vlen_enc); + } + break; + default: + fatal("Unsupported type %s", type2name(elem_bt)); + break; + } +} + +void C2_MacroAssembler::evmasked_saturating_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, XMMRegister src1, + Address src2, bool is_unsigned, bool merge, int vlen_enc) { + if (is_unsigned) { + evmasked_saturating_unsigned_op(ideal_opc, elem_bt, mask, dst, src1, src2, merge, vlen_enc); + } else { + evmasked_saturating_signed_op(ideal_opc, elem_bt, mask, dst, src1, src2, merge, vlen_enc); + } +} + +void C2_MacroAssembler::evmasked_saturating_signed_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, + XMMRegister src1, Address src2, bool merge, int vlen_enc) { + switch (elem_bt) { + case T_BYTE: + if (ideal_opc == Op_SaturatingAddV) { + evpaddsb(dst, mask, src1, src2, merge, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + evpsubsb(dst, mask, src1, src2, merge, vlen_enc); + } + break; + case T_SHORT: + if (ideal_opc == Op_SaturatingAddV) { + evpaddsw(dst, mask, src1, src2, merge, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + evpsubsw(dst, mask, src1, src2, merge, vlen_enc); + } + break; + default: + fatal("Unsupported type %s", type2name(elem_bt)); + break; + } +} + +void C2_MacroAssembler::evmasked_saturating_unsigned_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, + XMMRegister src1, Address src2, bool merge, int vlen_enc) { + switch (elem_bt) { + case T_BYTE: + if (ideal_opc == Op_SaturatingAddV) { + evpaddusb(dst, mask, src1, src2, merge, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + evpsubusb(dst, mask, src1, src2, merge, vlen_enc); + } + break; + case T_SHORT: + if (ideal_opc == Op_SaturatingAddV) { + evpaddusw(dst, mask, src1, src2, merge, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + evpsubusw(dst, mask, src1, src2, merge, vlen_enc); + } + break; + default: + fatal("Unsupported type %s", type2name(elem_bt)); + break; } } @@ -4721,6 +4912,10 @@ void C2_MacroAssembler::evmasked_op(int ideal_opc, BasicType eType, KRegister ma evpmaxs(eType, dst, mask, src1, src2, merge, vlen_enc); break; case Op_MinV: evpmins(eType, dst, mask, src1, src2, merge, vlen_enc); break; + case Op_UMinV: + evpminu(eType, dst, mask, src1, src2, merge, vlen_enc); break; + case Op_UMaxV: + evpmaxu(eType, dst, mask, src1, src2, merge, vlen_enc); break; case Op_XorV: evxor(eType, dst, mask, src1, src2, merge, vlen_enc); break; case Op_OrV: @@ -4728,7 +4923,8 @@ void C2_MacroAssembler::evmasked_op(int ideal_opc, BasicType eType, KRegister ma case Op_AndV: evand(eType, dst, mask, src1, src2, merge, vlen_enc); break; default: - fatal("Unsupported masked operation"); break; + fatal("Unsupported operation %s", NodeClassNames[ideal_opc]); + break; } } @@ -4781,6 +4977,10 @@ void C2_MacroAssembler::evmasked_op(int ideal_opc, BasicType eType, KRegister ma evpmaxs(eType, dst, mask, src1, src2, merge, vlen_enc); break; case Op_MinV: evpmins(eType, dst, mask, src1, src2, merge, vlen_enc); break; + case Op_UMaxV: + evpmaxu(eType, dst, mask, src1, src2, merge, vlen_enc); break; + case Op_UMinV: + evpminu(eType, dst, mask, src1, src2, merge, vlen_enc); break; case Op_XorV: evxor(eType, dst, mask, src1, src2, merge, vlen_enc); break; case Op_OrV: @@ -4788,7 +4988,8 @@ void C2_MacroAssembler::evmasked_op(int ideal_opc, BasicType eType, KRegister ma case Op_AndV: evand(eType, dst, mask, src1, src2, merge, vlen_enc); break; default: - fatal("Unsupported masked operation"); break; + fatal("Unsupported operation %s", NodeClassNames[ideal_opc]); + break; } } @@ -6475,3 +6676,409 @@ void C2_MacroAssembler::vector_rearrange_int_float(BasicType bt, XMMRegister dst vpermps(dst, shuffle, src, vlen_enc); } } + +void C2_MacroAssembler::vector_saturating_op(int ideal_opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc) { + switch(elem_bt) { + case T_BYTE: + if (ideal_opc == Op_SaturatingAddV) { + vpaddsb(dst, src1, src2, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + vpsubsb(dst, src1, src2, vlen_enc); + } + break; + case T_SHORT: + if (ideal_opc == Op_SaturatingAddV) { + vpaddsw(dst, src1, src2, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + vpsubsw(dst, src1, src2, vlen_enc); + } + break; + default: + fatal("Unsupported type %s", type2name(elem_bt)); + break; + } +} + +void C2_MacroAssembler::vector_saturating_unsigned_op(int ideal_opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc) { + switch(elem_bt) { + case T_BYTE: + if (ideal_opc == Op_SaturatingAddV) { + vpaddusb(dst, src1, src2, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + vpsubusb(dst, src1, src2, vlen_enc); + } + break; + case T_SHORT: + if (ideal_opc == Op_SaturatingAddV) { + vpaddusw(dst, src1, src2, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + vpsubusw(dst, src1, src2, vlen_enc); + } + break; + default: + fatal("Unsupported type %s", type2name(elem_bt)); + break; + } +} + +void C2_MacroAssembler::vector_sub_dq_saturating_unsigned_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1, + XMMRegister src2, KRegister ktmp, int vlen_enc) { + // For unsigned subtraction, overflow happens when magnitude of second input is greater than first input. + // overflow_mask = Inp1 Inp1 + MIN_VALUE < Inp2 + MIN_VALUE + vpgenmin_value(elem_bt, xtmp1, xtmp1, vlen_enc, true); + vpadd(elem_bt, xtmp2, src1, xtmp1, vlen_enc); + vpadd(elem_bt, xtmp1, src2, xtmp1, vlen_enc); + + vpcmpgt(elem_bt, xtmp2, xtmp1, xtmp2, vlen_enc); + + // Res = INP1 - INP2 (non-commutative and non-associative) + vpsub(elem_bt, dst, src1, src2, vlen_enc); + // Res = Mask ? Zero : Res + vpxor(xtmp1, xtmp1, xtmp1, vlen_enc); + vpblendvb(dst, dst, xtmp1, xtmp2, vlen_enc); +} + +void C2_MacroAssembler::vector_add_dq_saturating_unsigned_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, + XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp, int vlen_enc) { + // Unsigned values ranges comprise of only +ve numbers, thus there exist only an upper bound saturation. + // overflow_mask = (SRC1 + SRC2) >> 31 == 1 +// +// We empirically determined its semantic equivalence to following reduced expression +// overflow_mask = (a + b) = Res + MIN_VALUE + vpadd(elem_bt, xtmp2, xtmp2, dst, vlen_enc); + // Compute overflow detection mask = Res<1> >> 31(I)/63(L)) == 1 + vpxor(xtmp1, dst, src1, vlen_enc); + vpxor(xtmp2, dst, src2, vlen_enc); + vpand(xtmp2, xtmp1, xtmp2, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + // res = src1 - src2 + vpsub(elem_bt, dst, src1, src2, vlen_enc); + // Overflow occurs when both inputs have opposite polarity and + // result polarity does not comply with first input polarity. + // overflow = ((src1 ^ src2) & (res ^ src1) >>> 31(I)/63(L)) == 1; + vpxor(xtmp1, src1, src2, vlen_enc); + vpxor(xtmp2, dst, src1, vlen_enc); + vpand(xtmp2, xtmp1, xtmp2, vlen_enc); + } + + // Compute overflow detection mask. + evpmov_vec_to_mask(elem_bt, ktmp1, xtmp2, xtmp2, xtmp1, vlen_enc); + // Note: xtmp1 hold -1 in all its lanes after above call. + + // Compute mask based on first input polarity. + evpmov_vec_to_mask(elem_bt, ktmp2, src1, xtmp2, xtmp1, vlen_enc, true); + + vpgenmax_value(elem_bt, xtmp2, xtmp1, vlen_enc, true); + vpgenmin_value(elem_bt, xtmp1, xtmp1, vlen_enc); + + // Compose a vector of saturating (MAX/MIN) values, where lanes corresponding to + // set bits in first input polarity mask holds a min value. + evpblend(elem_bt, xtmp2, ktmp2, xtmp2, xtmp1, true, vlen_enc); + // Blend destination lanes with saturated values using overflow detection mask. + evpblend(elem_bt, dst, ktmp1, dst, xtmp2, true, vlen_enc); +} + + +void C2_MacroAssembler::vector_addsub_dq_saturating_avx(int ideal_opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, + XMMRegister src2, XMMRegister xtmp1, XMMRegister xtmp2, + XMMRegister xtmp3, XMMRegister xtmp4, int vlen_enc) { + assert(elem_bt == T_INT || elem_bt == T_LONG, ""); + // Addition/Subtraction happens over two's compliment representation of numbers and is agnostic to signed'ness. + // Overflow detection based on Hacker's delight section 2-13. + if (ideal_opc == Op_SaturatingAddV) { + // res = src1 + src2 + vpadd(elem_bt, dst, src1, src2, vlen_enc); + // Overflow occurs if result polarity does not comply with equivalent polarity inputs. + // overflow = (((res ^ src1) & (res ^ src2)) >>> 31(I)/63(L)) == 1 + vpxor(xtmp1, dst, src1, vlen_enc); + vpxor(xtmp2, dst, src2, vlen_enc); + vpand(xtmp2, xtmp1, xtmp2, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + // res = src1 - src2 + vpsub(elem_bt, dst, src1, src2, vlen_enc); + // Overflow occurs when both inputs have opposite polarity and + // result polarity does not comply with first input polarity. + // overflow = ((src1 ^ src2) & (res ^ src1) >>> 31(I)/63(L)) == 1; + vpxor(xtmp1, src1, src2, vlen_enc); + vpxor(xtmp2, dst, src1, vlen_enc); + vpand(xtmp2, xtmp1, xtmp2, vlen_enc); + } + + // Sign-extend to compute overflow detection mask. + vpsign_extend_dq(elem_bt, xtmp3, xtmp2, vlen_enc); + + vpcmpeqd(xtmp1, xtmp1, xtmp1, vlen_enc); + vpgenmax_value(elem_bt, xtmp2, xtmp1, vlen_enc); + vpgenmin_value(elem_bt, xtmp1, xtmp1, vlen_enc); + + // Compose saturating min/max vector using first input polarity mask. + vpsign_extend_dq(elem_bt, xtmp4, src1, vlen_enc); + vpblendvb(xtmp1, xtmp2, xtmp1, xtmp4, vlen_enc); + + // Blend result with saturating vector using overflow detection mask. + vpblendvb(dst, dst, xtmp1, xtmp3, vlen_enc); +} + +void C2_MacroAssembler::vector_saturating_op(int ideal_opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, Address src2, int vlen_enc) { + switch(elem_bt) { + case T_BYTE: + if (ideal_opc == Op_SaturatingAddV) { + vpaddsb(dst, src1, src2, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + vpsubsb(dst, src1, src2, vlen_enc); + } + break; + case T_SHORT: + if (ideal_opc == Op_SaturatingAddV) { + vpaddsw(dst, src1, src2, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + vpsubsw(dst, src1, src2, vlen_enc); + } + break; + default: + fatal("Unsupported type %s", type2name(elem_bt)); + break; + } +} + +void C2_MacroAssembler::vector_saturating_unsigned_op(int ideal_opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, Address src2, int vlen_enc) { + switch(elem_bt) { + case T_BYTE: + if (ideal_opc == Op_SaturatingAddV) { + vpaddusb(dst, src1, src2, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + vpsubusb(dst, src1, src2, vlen_enc); + } + break; + case T_SHORT: + if (ideal_opc == Op_SaturatingAddV) { + vpaddusw(dst, src1, src2, vlen_enc); + } else { + assert(ideal_opc == Op_SaturatingSubV, ""); + vpsubusw(dst, src1, src2, vlen_enc); + } + break; + default: + fatal("Unsupported type %s", type2name(elem_bt)); + break; + } +} + +void C2_MacroAssembler::select_from_two_vectors_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1, + XMMRegister src2, int vlen_enc) { + switch(elem_bt) { + case T_BYTE: + evpermi2b(dst, src1, src2, vlen_enc); + break; + case T_SHORT: + evpermi2w(dst, src1, src2, vlen_enc); + break; + case T_INT: + evpermi2d(dst, src1, src2, vlen_enc); + break; + case T_LONG: + evpermi2q(dst, src1, src2, vlen_enc); + break; + case T_FLOAT: + evpermi2ps(dst, src1, src2, vlen_enc); + break; + case T_DOUBLE: + evpermi2pd(dst, src1, src2, vlen_enc); + break; + default: + fatal("Unsupported type %s", type2name(elem_bt)); + break; + } +} + +void C2_MacroAssembler::vector_saturating_op(int ideal_opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, bool is_unsigned, int vlen_enc) { + if (is_unsigned) { + vector_saturating_unsigned_op(ideal_opc, elem_bt, dst, src1, src2, vlen_enc); + } else { + vector_saturating_op(ideal_opc, elem_bt, dst, src1, src2, vlen_enc); + } +} + +void C2_MacroAssembler::vector_saturating_op(int ideal_opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, Address src2, bool is_unsigned, int vlen_enc) { + if (is_unsigned) { + vector_saturating_unsigned_op(ideal_opc, elem_bt, dst, src1, src2, vlen_enc); + } else { + vector_saturating_op(ideal_opc, elem_bt, dst, src1, src2, vlen_enc); + } +} diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index af57546b3d143..3a36fd75e3f86 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -56,10 +56,21 @@ XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc); + void vpuminmax(int opcode, BasicType elem_bt, + XMMRegister dst, XMMRegister src1, XMMRegister src2, + int vlen_enc); + + void vpuminmax(int opcode, BasicType elem_bt, + XMMRegister dst, XMMRegister src1, Address src2, + int vlen_enc); + void vminmax_fp(int opcode, BasicType elem_bt, XMMRegister dst, XMMRegister a, XMMRegister b, XMMRegister tmp, XMMRegister atmp, XMMRegister btmp, int vlen_enc); + + void vpuminmaxq(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc); + void evminmax_fp(int opcode, BasicType elem_bt, XMMRegister dst, XMMRegister a, XMMRegister b, KRegister ktmp, XMMRegister atmp, XMMRegister btmp, @@ -105,6 +116,7 @@ void evmovdqu(BasicType type, KRegister kmask, XMMRegister dst, Address src, bool merge, int vector_len); void evmovdqu(BasicType type, KRegister kmask, Address dst, XMMRegister src, bool merge, int vector_len); + void evmovdqu(BasicType type, KRegister kmask, XMMRegister dst, XMMRegister src, bool merge, int vector_len); // extract void extract(BasicType typ, Register dst, XMMRegister src, int idx); @@ -505,4 +517,70 @@ void vgather8b_offset(BasicType elem_bt, XMMRegister dst, Register base, Register idx_base, Register offset, Register rtmp, int vlen_enc); + void vector_saturating_op(int opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, bool is_unsigned, int vlen_enc); + + void vector_saturating_op(int opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, Address src2, bool is_unsigned, int vlen_enc); + + void vector_saturating_op(int opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc); + + void vector_saturating_op(int opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, Address src2, int vlen_enc); + + void vector_saturating_unsigned_op(int opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc); + + void vector_saturating_unsigned_op(int opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, Address src2, int vlen_enc); + + void vector_sub_dq_saturating_unsigned_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, KRegister ktmp, int vlen_enc); + + void vector_sub_dq_saturating_unsigned_avx(BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, + XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc); + + void vector_add_dq_saturating_unsigned_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, + XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp, int vlen_enc); + + void vector_add_dq_saturating_unsigned_avx(BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, + XMMRegister xtmp1, XMMRegister xtmp2, XMMRegister xtmp3, int vlen_enc); + + void vector_addsub_dq_saturating_avx(int opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, + XMMRegister xtmp1, XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, int vlen_enc); + + void vector_addsub_dq_saturating_evex(int opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, + XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp1, KRegister ktmp2, int vlen_enc); + + void evpmovd2m_emu(KRegister ktmp, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc, bool xtmp2_hold_M1 = false); + + void evpmovq2m_emu(KRegister ktmp, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc, bool xtmp2_hold_M1 = false); + + void vpsign_extend_dq(BasicType etype, XMMRegister dst, XMMRegister src, int vlen_enc); + + void vpgenmin_value(BasicType etype, XMMRegister dst, XMMRegister allones, int vlen_enc, bool compute_allones = false); + + void vpgenmax_value(BasicType etype, XMMRegister dst, XMMRegister allones, int vlen_enc, bool compute_allones = false); + + void evpcmpu(BasicType etype, KRegister kmask, XMMRegister src1, XMMRegister src2, Assembler::ComparisonPredicate cond, int vlen_enc); + + void vpcmpgt(BasicType etype, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc); + + void evpmov_vec_to_mask(BasicType etype, KRegister ktmp, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, + int vlen_enc, bool xtmp2_hold_M1 = false); + + void evmasked_saturating_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, XMMRegister src1, XMMRegister src2, + bool is_unsigned, bool merge, int vlen_enc); + + void evmasked_saturating_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, XMMRegister src1, Address src2, + bool is_unsigned, bool merge, int vlen_enc); + + void evmasked_saturating_signed_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, XMMRegister src1, XMMRegister src2, + bool merge, int vlen_enc); + + void evmasked_saturating_signed_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, XMMRegister src1, Address src2, + bool merge, int vlen_enc); + + void evmasked_saturating_unsigned_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, XMMRegister src1, + XMMRegister src2, bool merge, int vlen_enc); + + void evmasked_saturating_unsigned_op(int ideal_opc, BasicType elem_bt, KRegister mask, XMMRegister dst, XMMRegister src1, + Address src2, bool merge, int vlen_enc); + + void select_from_two_vectors_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc); + #endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index b52be627776b8..b6be4012519a0 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -38,7 +38,10 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> @@ -160,6 +163,56 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator } } +static void generate_queue_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register thread, const Register value, const Register temp) { + // This code assumes that buffer index is pointer sized. + STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t)); + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + __ movptr(temp, Address(thread, in_bytes(index_offset))); // temp := *(index address) + __ testptr(temp, temp); // index == 0? + __ jcc(Assembler::zero, runtime); // jump to runtime if index == 0 (full buffer) + // The buffer is not full, store value into it. + __ subptr(temp, wordSize); // temp := next index + __ movptr(Address(thread, in_bytes(index_offset)), temp); // *(index address) := next index + __ addptr(temp, Address(thread, in_bytes(buffer_offset))); // temp := buffer address + next index + __ movptr(Address(temp, 0), value); // *(buffer address + next index) := value +} + +static void generate_pre_barrier_fast_path(MacroAssembler* masm, + const Register thread) { + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ cmpl(in_progress, 0); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ cmpb(in_progress, 0); + } +} + +static void generate_pre_barrier_slow_path(MacroAssembler* masm, + const Register obj, + const Register pre_val, + const Register thread, + const Register tmp, + Label& done, + Label& runtime) { + // Do we need to load the previous value? + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + } + // Is the previous value null? + __ cmpptr(pre_val, NULL_WORD); + __ jcc(Assembler::equal, done); + generate_queue_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, + thread, pre_val, tmp); + __ jmp(done); +} + void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, @@ -185,43 +238,10 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, assert(pre_val != rax, "check this code"); } - Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - - // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ cmpl(in_progress, 0); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ cmpb(in_progress, 0); - } - __ jcc(Assembler::equal, done); - - // Do we need to load the previous value? - if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); - } - - // Is the previous value null? - __ cmpptr(pre_val, NULL_WORD); + generate_pre_barrier_fast_path(masm, thread); + // If marking is not active (*(mark queue active address) == 0), jump to done __ jcc(Assembler::equal, done); - - // Can we store original value in the thread's buffer? - // Is index == 0? - // (The index field is typed as size_t.) - - __ movptr(tmp, index); // tmp := *index_adr - __ cmpptr(tmp, 0); // tmp == 0? - __ jcc(Assembler::equal, runtime); // If yes, goto runtime - - __ subptr(tmp, wordSize); // tmp := tmp - wordSize - __ movptr(index, tmp); // *index_adr := tmp - __ addptr(tmp, buffer); // tmp := tmp + *buffer_adr - - // Record the previous value - __ movptr(Address(tmp, 0), pre_val); - __ jmp(done); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, done, runtime); __ bind(runtime); @@ -263,6 +283,54 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, __ bind(done); } +static void generate_post_barrier_fast_path(MacroAssembler* masm, + const Register store_addr, + const Register new_val, + const Register tmp, + const Register tmp2, + Label& done, + bool new_val_may_be_null) { + CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); + // Does store cross heap regions? + __ movptr(tmp, store_addr); // tmp := store address + __ xorptr(tmp, new_val); // tmp := store address ^ new value + __ shrptr(tmp, G1HeapRegion::LogOfHRGrainBytes); // ((store address ^ new value) >> LogOfHRGrainBytes) == 0? + __ jcc(Assembler::equal, done); + // Crosses regions, storing null? + if (new_val_may_be_null) { + __ cmpptr(new_val, NULL_WORD); // new value == null? + __ jcc(Assembler::equal, done); + } + // Storing region crossing non-null, is card young? + __ movptr(tmp, store_addr); // tmp := store address + __ shrptr(tmp, CardTable::card_shift()); // tmp := card address relative to card table base + // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT + // a valid address and therefore is not properly handled by the relocation code. + __ movptr(tmp2, (intptr_t)ct->card_table()->byte_map_base()); // tmp2 := card table base address + __ addptr(tmp, tmp2); // tmp := card address + __ cmpb(Address(tmp, 0), G1CardTable::g1_young_card_val()); // *(card address) == young_card_val? +} + +static void generate_post_barrier_slow_path(MacroAssembler* masm, + const Register thread, + const Register tmp, + const Register tmp2, + Label& done, + Label& runtime) { + __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); // StoreLoad membar + __ cmpb(Address(tmp, 0), G1CardTable::dirty_card_val()); // *(card address) == dirty_card_val? + __ jcc(Assembler::equal, done); + // Storing a region crossing, non-null oop, card is clean. + // Dirty card and log. + __ movb(Address(tmp, 0), G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val + generate_queue_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, + thread, tmp, tmp2); + __ jmp(done); +} + void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, @@ -273,74 +341,125 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, assert(thread == r15_thread, "must be"); #endif // _LP64 - Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - CardTableBarrierSet* ct = - barrier_set_cast(BarrierSet::barrier_set()); - Label done; Label runtime; - // Does store cross heap regions? - - __ movptr(tmp, store_addr); - __ xorptr(tmp, new_val); - __ shrptr(tmp, G1HeapRegion::LogOfHRGrainBytes); + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp, tmp2, done, true /* new_val_may_be_null */); + // If card is young, jump to done __ jcc(Assembler::equal, done); + generate_post_barrier_slow_path(masm, thread, tmp, tmp2, done, runtime); - // crosses regions, storing null? + __ bind(runtime); + // save the live input values + RegSet saved = RegSet::of(store_addr NOT_LP64(COMMA thread)); + __ push_set(saved); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp, thread); + __ pop_set(saved); - __ cmpptr(new_val, NULL_WORD); - __ jcc(Assembler::equal, done); + __ bind(done); +} - // storing region crossing non-null, is card already dirty? +#if defined(COMPILER2) - const Register card_addr = tmp; - const Register cardtable = tmp2; +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { +#ifdef _LP64 + SaveLiveRegisters save_registers(masm, stub); + if (c_rarg0 != arg) { + __ mov(c_rarg0, arg); + } + __ mov(c_rarg1, r15_thread); + // rax is a caller-saved, non-argument-passing register, so it does not + // interfere with c_rarg0 or c_rarg1. If it contained any live value before + // entering this stub, it is saved at this point, and restored after the + // call. If it did not contain any live value, it is free to be used. In + // either case, it is safe to use it here as a call scratch register. + __ call(RuntimeAddress(runtime_path), rax); +#else + Unimplemented(); +#endif // _LP64 +} - __ movptr(card_addr, store_addr); - __ shrptr(card_addr, CardTable::card_shift()); - // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT - // a valid address and therefore is not properly handled by the relocation code. - __ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base()); - __ addptr(card_addr, cardtable); +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp, + G1PreBarrierStubC2* stub) { +#ifdef _LP64 + assert(thread == r15_thread, "must be"); +#endif // _LP64 + assert(pre_val != noreg, "check this code"); + if (obj != noreg) { + assert_different_registers(obj, pre_val, tmp); + } - __ cmpb(Address(card_addr, 0), G1CardTable::g1_young_card_val()); - __ jcc(Assembler::equal, done); + stub->initialize_registers(obj, pre_val, thread, tmp); - __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); - __ cmpb(Address(card_addr, 0), G1CardTable::dirty_card_val()); - __ jcc(Assembler::equal, done); + generate_pre_barrier_fast_path(masm, thread); + // If marking is active (*(mark queue active address) != 0), jump to stub (slow path) + __ jcc(Assembler::notEqual, *stub->entry()); + __ bind(*stub->continuation()); +} - // storing a region crossing, non-null oop, card is clean. - // dirty card and log. +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register thread = stub->thread(); + Register tmp = stub->tmp1(); + assert(stub->tmp2() == noreg, "not needed in this platform"); - __ movb(Address(card_addr, 0), G1CardTable::dirty_card_val()); + __ bind(*stub->entry()); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, *stub->continuation(), runtime); - // The code below assumes that buffer index is pointer sized. - STATIC_ASSERT(in_bytes(G1DirtyCardQueue::byte_width_of_index()) == sizeof(intptr_t)); + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); + __ jmp(*stub->continuation()); +} - __ movptr(tmp2, queue_index); - __ testptr(tmp2, tmp2); - __ jcc(Assembler::zero, runtime); - __ subptr(tmp2, wordSize); - __ movptr(queue_index, tmp2); - __ addptr(tmp2, buffer); - __ movptr(Address(tmp2, 0), card_addr); - __ jmp(done); +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp, + Register tmp2, + G1PostBarrierStubC2* stub) { +#ifdef _LP64 + assert(thread == r15_thread, "must be"); +#endif // _LP64 - __ bind(runtime); - // save the live input values - RegSet saved = RegSet::of(store_addr NOT_LP64(COMMA thread)); - __ push_set(saved); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); - __ pop_set(saved); + stub->initialize_registers(thread, tmp, tmp2); - __ bind(done); + bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp, tmp2, *stub->continuation(), new_val_may_be_null); + // If card is not young, jump to stub (slow path) + __ jcc(Assembler::notEqual, *stub->entry()); + + __ bind(*stub->continuation()); +} + +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register thread = stub->thread(); + Register tmp = stub->tmp1(); // tmp holds the card address. + Register tmp2 = stub->tmp2(); + assert(stub->tmp3() == noreg, "not needed in this platform"); + + __ bind(*stub->entry()); + generate_post_barrier_slow_path(masm, thread, tmp, tmp2, *stub->continuation(), runtime); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, tmp, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); + __ jmp(*stub->continuation()); } +#endif // COMPILER2 + void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { bool in_heap = (decorators & IN_HEAP) != 0; diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp index a5695f5657a4a..4dbb1efd885ea 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp @@ -32,6 +32,9 @@ class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1BarrierStubC2; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -65,6 +68,26 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp_thread); + +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp, + Register tmp2, + G1PostBarrierStubC2* c2_stub); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif // COMPILER2 }; #endif // CPU_X86_GC_G1_G1BARRIERSETASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad new file mode 100644 index 0000000000000..8c1559f90f46d --- /dev/null +++ b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad @@ -0,0 +1,371 @@ +// +// 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. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_x86.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void write_barrier_pre(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp, + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, r15_thread, tmp, stub); +} + +static void write_barrier_post(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, r15_thread, tmp1, tmp2, stub); +} + +%} + +instruct g1StoreP(memory mem, any_RegP src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(125); // XXX + format %{ "movq $mem, $src\t# ptr" %} + ins_encode %{ + // Materialize the store address internally (as opposed to defining 'mem' as + // an indirect memory operand) to reduce the overhead of LCM when processing + // large basic blocks with many stores. Such basic blocks arise, for + // instance, from static initializations of large String arrays. + // The same holds for g1StoreN and g1EncodePAndStoreN. + __ lea($tmp1$$Register, $mem$$Address); + write_barrier_pre(masm, this, + $tmp1$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); + __ movq(Address($tmp1$$Register, 0), $src$$Register); + write_barrier_post(masm, this, + $tmp1$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp3$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct g1StoreN(memory mem, rRegN src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(125); // XXX + format %{ "movl $mem, $src\t# ptr" %} + ins_encode %{ + __ lea($tmp1$$Register, $mem$$Address); + write_barrier_pre(masm, this, + $tmp1$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); + __ movl(Address($tmp1$$Register, 0), $src$$Register); + if ((barrier_data() & G1C2BarrierPost) != 0) { + __ movl($tmp2$$Register, $src$$Register); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ decode_heap_oop($tmp2$$Register); + } else { + __ decode_heap_oop_not_null($tmp2$$Register); + } + } + write_barrier_post(masm, this, + $tmp1$$Register /* store_addr */, + $tmp2$$Register /* new_val */, + $tmp3$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct g1EncodePAndStoreN(memory mem, any_RegP src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(125); // XXX + format %{ "encode_heap_oop $src\n\t" + "movl $mem, $src\t# ptr" %} + ins_encode %{ + __ lea($tmp1$$Register, $mem$$Address); + write_barrier_pre(masm, this, + $tmp1$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); + __ movq($tmp2$$Register, $src$$Register); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ encode_heap_oop($tmp2$$Register); + } else { + __ encode_heap_oop_not_null($tmp2$$Register); + } + __ movl(Address($tmp1$$Register, 0), $tmp2$$Register); + write_barrier_post(masm, this, + $tmp1$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp3$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct g1CompareAndExchangeP(indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set oldval (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + format %{ "lock\n\t" + "cmpxchgq $newval, $mem" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */); + __ movq($tmp1$$Register, $newval$$Register); + __ lock(); + __ cmpxchgq($tmp1$$Register, Address($mem$$Register, 0)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1CompareAndExchangeN(indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set oldval (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + format %{ "lock\n\t" + "cmpxchgq $newval, $mem" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */); + __ movl($tmp1$$Register, $newval$$Register); + __ lock(); + __ cmpxchgl($tmp1$$Register, Address($mem$$Register, 0)); + __ decode_heap_oop($tmp1$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1CompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL oldval, KILL cr); + format %{ "lock\n\t" + "cmpxchgq $newval, $mem\n\t" + "sete $res\n\t" + "movzbl $res, $res" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ movq($tmp1$$Register, $newval$$Register); + __ lock(); + __ cmpxchgq($tmp1$$Register, Address($mem$$Register, 0)); + __ setb(Assembler::equal, $res$$Register); + __ movzbl($res$$Register, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1CompareAndSwapN(rRegI res, indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL oldval, KILL cr); + format %{ "lock\n\t" + "cmpxchgq $newval, $mem\n\t" + "sete $res\n\t" + "movzbl $res, $res" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ movl($tmp1$$Register, $newval$$Register); + __ lock(); + __ cmpxchgl($tmp1$$Register, Address($mem$$Register, 0)); + __ setb(Assembler::equal, $res$$Register); + __ movzbl($res$$Register, $res$$Register); + __ decode_heap_oop($tmp1$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1GetAndSetP(indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set newval (GetAndSetP mem newval)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + format %{ "xchgq $newval, $mem" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + __ movq($tmp1$$Register, $newval$$Register); + __ xchgq($newval$$Register, Address($mem$$Register, 0)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1GetAndSetN(indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set newval (GetAndSetN mem newval)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + format %{ "xchgq $newval, $mem" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + __ movl($tmp1$$Register, $newval$$Register); + __ decode_heap_oop($tmp1$$Register); + __ xchgl($newval$$Register, Address($mem$$Register, 0)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1LoadP(rRegP dst, memory mem, rRegP tmp, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp, KILL cr); + ins_cost(125); // XXX + format %{ "movq $dst, $mem\t# ptr" %} + ins_encode %{ + __ movq($dst$$Register, $mem$$Address); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp$$Register /* tmp */); + %} + ins_pipe(ialu_reg_mem); // XXX +%} + +instruct g1LoadN(rRegN dst, memory mem, rRegP tmp1, rRegP tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadN mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(125); // XXX + format %{ "movl $dst, $mem\t# compressed ptr" %} + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + __ movl($tmp1$$Register, $dst$$Register); + __ decode_heap_oop($tmp1$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp */); + %} + ins_pipe(ialu_reg_mem); // XXX +%} diff --git a/src/hotspot/cpu/x86/gc/x/xBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/x/xBarrierSetAssembler_x86.cpp deleted file mode 100644 index a7dc34b17b1f6..0000000000000 --- a/src/hotspot/cpu/x86/gc/x/xBarrierSetAssembler_x86.cpp +++ /dev/null @@ -1,734 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/codeBlob.hpp" -#include "code/vmreg.inline.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xBarrierSet.hpp" -#include "gc/x/xBarrierSetAssembler.hpp" -#include "gc/x/xBarrierSetRuntime.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/sharedRuntime.hpp" -#include "utilities/macros.hpp" -#ifdef COMPILER1 -#include "c1/c1_LIRAssembler.hpp" -#include "c1/c1_MacroAssembler.hpp" -#include "gc/x/c1/xBarrierSetC1.hpp" -#endif // COMPILER1 -#ifdef COMPILER2 -#include "gc/x/c2/xBarrierSetC2.hpp" -#endif // COMPILER2 - -#ifdef PRODUCT -#define BLOCK_COMMENT(str) /* nothing */ -#else -#define BLOCK_COMMENT(str) __ block_comment(str) -#endif - -#undef __ -#define __ masm-> - -static void call_vm(MacroAssembler* masm, - address entry_point, - Register arg0, - Register arg1) { - // Setup arguments - if (arg1 == c_rarg0) { - if (arg0 == c_rarg1) { - __ xchgptr(c_rarg1, c_rarg0); - } else { - __ movptr(c_rarg1, arg1); - __ movptr(c_rarg0, arg0); - } - } else { - if (arg0 != c_rarg0) { - __ movptr(c_rarg0, arg0); - } - if (arg1 != c_rarg1) { - __ movptr(c_rarg1, arg1); - } - } - - // Call VM - __ MacroAssembler::call_VM_leaf_base(entry_point, 2); -} - -void XBarrierSetAssembler::load_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Register dst, - Address src, - Register tmp1, - Register tmp_thread) { - if (!XBarrierSet::barrier_needed(decorators, type)) { - // Barrier not needed - BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); - return; - } - - BLOCK_COMMENT("XBarrierSetAssembler::load_at {"); - - // Allocate scratch register - Register scratch = tmp1; - if (tmp1 == noreg) { - scratch = r12; - __ push(scratch); - } - - assert_different_registers(dst, scratch); - - Label done; - - // - // Fast Path - // - - // Load address - __ lea(scratch, src); - - // Load oop at address - __ movptr(dst, Address(scratch, 0)); - - // Test address bad mask - __ testptr(dst, address_bad_mask_from_thread(r15_thread)); - __ jcc(Assembler::zero, done); - - // - // Slow path - // - - // Save registers - __ push(rax); - __ push(rcx); - __ push(rdx); - __ push(rdi); - __ push(rsi); - __ push(r8); - __ push(r9); - __ push(r10); - __ push(r11); - - // We may end up here from generate_native_wrapper, then the method may have - // floats as arguments, and we must spill them before calling the VM runtime - // leaf. From the interpreter all floats are passed on the stack. - assert(Argument::n_float_register_parameters_j == 8, "Assumption"); - const int xmm_size = wordSize * 2; - const int xmm_spill_size = xmm_size * Argument::n_float_register_parameters_j; - __ subptr(rsp, xmm_spill_size); - __ movdqu(Address(rsp, xmm_size * 7), xmm7); - __ movdqu(Address(rsp, xmm_size * 6), xmm6); - __ movdqu(Address(rsp, xmm_size * 5), xmm5); - __ movdqu(Address(rsp, xmm_size * 4), xmm4); - __ movdqu(Address(rsp, xmm_size * 3), xmm3); - __ movdqu(Address(rsp, xmm_size * 2), xmm2); - __ movdqu(Address(rsp, xmm_size * 1), xmm1); - __ movdqu(Address(rsp, xmm_size * 0), xmm0); - - // Call VM - call_vm(masm, XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), dst, scratch); - - __ movdqu(xmm0, Address(rsp, xmm_size * 0)); - __ movdqu(xmm1, Address(rsp, xmm_size * 1)); - __ movdqu(xmm2, Address(rsp, xmm_size * 2)); - __ movdqu(xmm3, Address(rsp, xmm_size * 3)); - __ movdqu(xmm4, Address(rsp, xmm_size * 4)); - __ movdqu(xmm5, Address(rsp, xmm_size * 5)); - __ movdqu(xmm6, Address(rsp, xmm_size * 6)); - __ movdqu(xmm7, Address(rsp, xmm_size * 7)); - __ addptr(rsp, xmm_spill_size); - - __ pop(r11); - __ pop(r10); - __ pop(r9); - __ pop(r8); - __ pop(rsi); - __ pop(rdi); - __ pop(rdx); - __ pop(rcx); - - if (dst == rax) { - __ addptr(rsp, wordSize); - } else { - __ movptr(dst, rax); - __ pop(rax); - } - - __ bind(done); - - // Restore scratch register - if (tmp1 == noreg) { - __ pop(scratch); - } - - BLOCK_COMMENT("} XBarrierSetAssembler::load_at"); -} - -#ifdef ASSERT - -void XBarrierSetAssembler::store_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Address dst, - Register src, - Register tmp1, - Register tmp2, - Register tmp3) { - BLOCK_COMMENT("XBarrierSetAssembler::store_at {"); - - // Verify oop store - if (is_reference_type(type)) { - // Note that src could be noreg, which means we - // are storing null and can skip verification. - if (src != noreg) { - Label done; - __ testptr(src, address_bad_mask_from_thread(r15_thread)); - __ jcc(Assembler::zero, done); - __ stop("Verify oop store failed"); - __ should_not_reach_here(); - __ bind(done); - } - } - - // Store value - BarrierSetAssembler::store_at(masm, decorators, type, dst, src, tmp1, tmp2, tmp3); - - BLOCK_COMMENT("} XBarrierSetAssembler::store_at"); -} - -#endif // ASSERT - -void XBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Register src, - Register dst, - Register count) { - if (!XBarrierSet::barrier_needed(decorators, type)) { - // Barrier not needed - return; - } - - BLOCK_COMMENT("XBarrierSetAssembler::arraycopy_prologue {"); - - // Save registers - __ pusha(); - - // Call VM - call_vm(masm, XBarrierSetRuntime::load_barrier_on_oop_array_addr(), src, count); - - // Restore registers - __ popa(); - - BLOCK_COMMENT("} XBarrierSetAssembler::arraycopy_prologue"); -} - -void XBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, - Register jni_env, - Register obj, - Register tmp, - Label& slowpath) { - BLOCK_COMMENT("XBarrierSetAssembler::try_resolve_jobject_in_native {"); - - // Resolve jobject - BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath); - - // Test address bad mask - __ testptr(obj, address_bad_mask_from_jni_env(jni_env)); - __ jcc(Assembler::notZero, slowpath); - - BLOCK_COMMENT("} XBarrierSetAssembler::try_resolve_jobject_in_native"); -} - -#ifdef COMPILER1 - -#undef __ -#define __ ce->masm()-> - -void XBarrierSetAssembler::generate_c1_load_barrier_test(LIR_Assembler* ce, - LIR_Opr ref) const { - __ testptr(ref->as_register(), address_bad_mask_from_thread(r15_thread)); -} - -void XBarrierSetAssembler::generate_c1_load_barrier_stub(LIR_Assembler* ce, - XLoadBarrierStubC1* stub) const { - // Stub entry - __ bind(*stub->entry()); - - Register ref = stub->ref()->as_register(); - Register ref_addr = noreg; - Register tmp = noreg; - - if (stub->tmp()->is_valid()) { - // Load address into tmp register - ce->leal(stub->ref_addr(), stub->tmp()); - ref_addr = tmp = stub->tmp()->as_pointer_register(); - } else { - // Address already in register - ref_addr = stub->ref_addr()->as_address_ptr()->base()->as_pointer_register(); - } - - assert_different_registers(ref, ref_addr, noreg); - - // Save rax unless it is the result or tmp register - if (ref != rax && tmp != rax) { - __ push(rax); - } - - // Setup arguments and call runtime stub - __ subptr(rsp, 2 * BytesPerWord); - ce->store_parameter(ref_addr, 1); - ce->store_parameter(ref, 0); - __ call(RuntimeAddress(stub->runtime_stub())); - __ addptr(rsp, 2 * BytesPerWord); - - // Verify result - __ verify_oop(rax); - - // Move result into place - if (ref != rax) { - __ movptr(ref, rax); - } - - // Restore rax unless it is the result or tmp register - if (ref != rax && tmp != rax) { - __ pop(rax); - } - - // Stub exit - __ jmp(*stub->continuation()); -} - -#undef __ -#define __ sasm-> - -void XBarrierSetAssembler::generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, - DecoratorSet decorators) const { - // Enter and save registers - __ enter(); - __ save_live_registers_no_oop_map(true /* save_fpu_registers */); - - // Setup arguments - __ load_parameter(1, c_rarg1); - __ load_parameter(0, c_rarg0); - - // Call VM - __ call_VM_leaf(XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), c_rarg0, c_rarg1); - - // Restore registers and return - __ restore_live_registers_except_rax(true /* restore_fpu_registers */); - __ leave(); - __ ret(0); -} - -#endif // COMPILER1 - -#ifdef COMPILER2 - -OptoReg::Name XBarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) { - if (!OptoReg::is_reg(opto_reg)) { - return OptoReg::Bad; - } - - const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); - if (vm_reg->is_XMMRegister()) { - opto_reg &= ~15; - switch (node->ideal_reg()) { - case Op_VecX: - opto_reg |= 2; - break; - case Op_VecY: - opto_reg |= 4; - break; - case Op_VecZ: - opto_reg |= 8; - break; - default: - opto_reg |= 1; - break; - } - } - - return opto_reg; -} - -// We use the vec_spill_helper from the x86.ad file to avoid reinventing this wheel -extern void vec_spill_helper(C2_MacroAssembler *masm, bool is_load, - int stack_offset, int reg, uint ireg, outputStream* st); - -#undef __ -#define __ _masm-> - -class XSaveLiveRegisters { -private: - struct XMMRegisterData { - XMMRegister _reg; - int _size; - - // Used by GrowableArray::find() - bool operator == (const XMMRegisterData& other) { - return _reg == other._reg; - } - }; - - MacroAssembler* const _masm; - GrowableArray _gp_registers; - GrowableArray _opmask_registers; - GrowableArray _xmm_registers; - int _spill_size; - int _spill_offset; - - static int xmm_compare_register_size(XMMRegisterData* left, XMMRegisterData* right) { - if (left->_size == right->_size) { - return 0; - } - - return (left->_size < right->_size) ? -1 : 1; - } - - static int xmm_slot_size(OptoReg::Name opto_reg) { - // The low order 4 bytes denote what size of the XMM register is live - return (opto_reg & 15) << 3; - } - - static uint xmm_ideal_reg_for_size(int reg_size) { - switch (reg_size) { - case 8: - return Op_VecD; - case 16: - return Op_VecX; - case 32: - return Op_VecY; - case 64: - return Op_VecZ; - default: - fatal("Invalid register size %d", reg_size); - return 0; - } - } - - bool xmm_needs_vzeroupper() const { - return _xmm_registers.is_nonempty() && _xmm_registers.at(0)._size > 16; - } - - void xmm_register_save(const XMMRegisterData& reg_data) { - const OptoReg::Name opto_reg = OptoReg::as_OptoReg(reg_data._reg->as_VMReg()); - const uint ideal_reg = xmm_ideal_reg_for_size(reg_data._size); - _spill_offset -= reg_data._size; - C2_MacroAssembler c2_masm(__ code()); - vec_spill_helper(&c2_masm, false /* is_load */, _spill_offset, opto_reg, ideal_reg, tty); - } - - void xmm_register_restore(const XMMRegisterData& reg_data) { - const OptoReg::Name opto_reg = OptoReg::as_OptoReg(reg_data._reg->as_VMReg()); - const uint ideal_reg = xmm_ideal_reg_for_size(reg_data._size); - C2_MacroAssembler c2_masm(__ code()); - vec_spill_helper(&c2_masm, true /* is_load */, _spill_offset, opto_reg, ideal_reg, tty); - _spill_offset += reg_data._size; - } - - void gp_register_save(Register reg) { - _spill_offset -= 8; - __ movq(Address(rsp, _spill_offset), reg); - } - - void opmask_register_save(KRegister reg) { - _spill_offset -= 8; - __ kmov(Address(rsp, _spill_offset), reg); - } - - void gp_register_restore(Register reg) { - __ movq(reg, Address(rsp, _spill_offset)); - _spill_offset += 8; - } - - void opmask_register_restore(KRegister reg) { - __ kmov(reg, Address(rsp, _spill_offset)); - _spill_offset += 8; - } - - void initialize(XLoadBarrierStubC2* stub) { - // Create mask of caller saved registers that need to - // be saved/restored if live - RegMask caller_saved; - caller_saved.Insert(OptoReg::as_OptoReg(rax->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(rcx->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(rdx->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(rsi->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(rdi->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r8->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r9->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r10->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r11->as_VMReg())); - caller_saved.Remove(OptoReg::as_OptoReg(stub->ref()->as_VMReg())); - - if (UseAPX) { - caller_saved.Insert(OptoReg::as_OptoReg(r16->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r17->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r18->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r19->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r20->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r21->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r22->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r23->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r24->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r25->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r26->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r27->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r28->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r29->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r30->as_VMReg())); - caller_saved.Insert(OptoReg::as_OptoReg(r31->as_VMReg())); - } - - // Create mask of live registers - RegMask live = stub->live(); - if (stub->tmp() != noreg) { - live.Insert(OptoReg::as_OptoReg(stub->tmp()->as_VMReg())); - } - - int gp_spill_size = 0; - int opmask_spill_size = 0; - int xmm_spill_size = 0; - - // Record registers that needs to be saved/restored - RegMaskIterator rmi(live); - while (rmi.has_next()) { - const OptoReg::Name opto_reg = rmi.next(); - const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); - - if (vm_reg->is_Register()) { - if (caller_saved.Member(opto_reg)) { - _gp_registers.append(vm_reg->as_Register()); - gp_spill_size += 8; - } - } else if (vm_reg->is_KRegister()) { - // All opmask registers are caller saved, thus spill the ones - // which are live. - if (_opmask_registers.find(vm_reg->as_KRegister()) == -1) { - _opmask_registers.append(vm_reg->as_KRegister()); - opmask_spill_size += 8; - } - } else if (vm_reg->is_XMMRegister()) { - // We encode in the low order 4 bits of the opto_reg, how large part of the register is live - const VMReg vm_reg_base = OptoReg::as_VMReg(opto_reg & ~15); - const int reg_size = xmm_slot_size(opto_reg); - const XMMRegisterData reg_data = { vm_reg_base->as_XMMRegister(), reg_size }; - const int reg_index = _xmm_registers.find(reg_data); - if (reg_index == -1) { - // Not previously appended - _xmm_registers.append(reg_data); - xmm_spill_size += reg_size; - } else { - // Previously appended, update size - const int reg_size_prev = _xmm_registers.at(reg_index)._size; - if (reg_size > reg_size_prev) { - _xmm_registers.at_put(reg_index, reg_data); - xmm_spill_size += reg_size - reg_size_prev; - } - } - } else { - fatal("Unexpected register type"); - } - } - - // Sort by size, largest first - _xmm_registers.sort(xmm_compare_register_size); - - // On Windows, the caller reserves stack space for spilling register arguments - const int arg_spill_size = frame::arg_reg_save_area_bytes; - - // Stack pointer must be 16 bytes aligned for the call - _spill_offset = _spill_size = align_up(xmm_spill_size + gp_spill_size + opmask_spill_size + arg_spill_size, 16); - } - -public: - XSaveLiveRegisters(MacroAssembler* masm, XLoadBarrierStubC2* stub) : - _masm(masm), - _gp_registers(), - _opmask_registers(), - _xmm_registers(), - _spill_size(0), - _spill_offset(0) { - - // - // Stack layout after registers have been spilled: - // - // | ... | original rsp, 16 bytes aligned - // ------------------ - // | zmm0 high | - // | ... | - // | zmm0 low | 16 bytes aligned - // | ... | - // | ymm1 high | - // | ... | - // | ymm1 low | 16 bytes aligned - // | ... | - // | xmmN high | - // | ... | - // | xmmN low | 8 bytes aligned - // | reg0 | 8 bytes aligned - // | reg1 | - // | ... | - // | regN | new rsp, if 16 bytes aligned - // | | else new rsp, 16 bytes aligned - // ------------------ - // - - // Figure out what registers to save/restore - initialize(stub); - - // Allocate stack space - if (_spill_size > 0) { - __ subptr(rsp, _spill_size); - } - - // Save XMM/YMM/ZMM registers - for (int i = 0; i < _xmm_registers.length(); i++) { - xmm_register_save(_xmm_registers.at(i)); - } - - if (xmm_needs_vzeroupper()) { - __ vzeroupper(); - } - - // Save general purpose registers - for (int i = 0; i < _gp_registers.length(); i++) { - gp_register_save(_gp_registers.at(i)); - } - - // Save opmask registers - for (int i = 0; i < _opmask_registers.length(); i++) { - opmask_register_save(_opmask_registers.at(i)); - } - } - - ~XSaveLiveRegisters() { - // Restore opmask registers - for (int i = _opmask_registers.length() - 1; i >= 0; i--) { - opmask_register_restore(_opmask_registers.at(i)); - } - - // Restore general purpose registers - for (int i = _gp_registers.length() - 1; i >= 0; i--) { - gp_register_restore(_gp_registers.at(i)); - } - - __ vzeroupper(); - - // Restore XMM/YMM/ZMM registers - for (int i = _xmm_registers.length() - 1; i >= 0; i--) { - xmm_register_restore(_xmm_registers.at(i)); - } - - // Free stack space - if (_spill_size > 0) { - __ addptr(rsp, _spill_size); - } - } -}; - -class XSetupArguments { -private: - MacroAssembler* const _masm; - const Register _ref; - const Address _ref_addr; - -public: - XSetupArguments(MacroAssembler* masm, XLoadBarrierStubC2* stub) : - _masm(masm), - _ref(stub->ref()), - _ref_addr(stub->ref_addr()) { - - // Setup arguments - if (_ref_addr.base() == noreg) { - // No self healing - if (_ref != c_rarg0) { - __ movq(c_rarg0, _ref); - } - __ xorq(c_rarg1, c_rarg1); - } else { - // Self healing - if (_ref == c_rarg0) { - __ lea(c_rarg1, _ref_addr); - } else if (_ref != c_rarg1) { - __ lea(c_rarg1, _ref_addr); - __ movq(c_rarg0, _ref); - } else if (_ref_addr.base() != c_rarg0 && _ref_addr.index() != c_rarg0) { - __ movq(c_rarg0, _ref); - __ lea(c_rarg1, _ref_addr); - } else { - __ xchgq(c_rarg0, c_rarg1); - if (_ref_addr.base() == c_rarg0) { - __ lea(c_rarg1, Address(c_rarg1, _ref_addr.index(), _ref_addr.scale(), _ref_addr.disp())); - } else if (_ref_addr.index() == c_rarg0) { - __ lea(c_rarg1, Address(_ref_addr.base(), c_rarg1, _ref_addr.scale(), _ref_addr.disp())); - } else { - ShouldNotReachHere(); - } - } - } - } - - ~XSetupArguments() { - // Transfer result - if (_ref != rax) { - __ movq(_ref, rax); - } - } -}; - -#undef __ -#define __ masm-> - -void XBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, XLoadBarrierStubC2* stub) const { - BLOCK_COMMENT("XLoadBarrierStubC2"); - - // Stub entry - __ bind(*stub->entry()); - - { - XSaveLiveRegisters save_live_registers(masm, stub); - XSetupArguments setup_arguments(masm, stub); - __ call(RuntimeAddress(stub->slow_path())); - } - - // Stub exit - __ jmp(*stub->continuation()); -} - -#endif // COMPILER2 - -#undef __ -#define __ masm-> - -void XBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) { - // Check if metadata bits indicate a bad oop - __ testptr(obj, Address(r15_thread, XThreadLocalData::address_bad_mask_offset())); - __ jcc(Assembler::notZero, error); - BarrierSetAssembler::check_oop(masm, obj, tmp1, tmp2, error); -} - -#undef __ diff --git a/src/hotspot/cpu/x86/gc/x/xBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/x/xBarrierSetAssembler_x86.hpp deleted file mode 100644 index 52034ab786ec2..0000000000000 --- a/src/hotspot/cpu/x86/gc/x/xBarrierSetAssembler_x86.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2018, 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 - * 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 CPU_X86_GC_X_XBARRIERSETASSEMBLER_X86_HPP -#define CPU_X86_GC_X_XBARRIERSETASSEMBLER_X86_HPP - -#include "code/vmreg.hpp" -#include "oops/accessDecorators.hpp" -#ifdef COMPILER2 -#include "opto/optoreg.hpp" -#endif // COMPILER2 - -class MacroAssembler; - -#ifdef COMPILER1 -class LIR_Assembler; -class LIR_Opr; -class StubAssembler; -#endif // COMPILER1 - -#ifdef COMPILER2 -class Node; -#endif // COMPILER2 - -#ifdef COMPILER1 -class XLoadBarrierStubC1; -#endif // COMPILER1 - -#ifdef COMPILER2 -class XLoadBarrierStubC2; -#endif // COMPILER2 - -class XBarrierSetAssembler : public XBarrierSetAssemblerBase { -public: - virtual void load_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Register dst, - Address src, - Register tmp1, - Register tmp_thread); - -#ifdef ASSERT - virtual void store_at(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Address dst, - Register src, - Register tmp1, - Register tmp2, - Register tmp3); -#endif // ASSERT - - virtual void arraycopy_prologue(MacroAssembler* masm, - DecoratorSet decorators, - BasicType type, - Register src, - Register dst, - Register count); - - virtual void try_resolve_jobject_in_native(MacroAssembler* masm, - Register jni_env, - Register obj, - Register tmp, - Label& slowpath); - -#ifdef COMPILER1 - void generate_c1_load_barrier_test(LIR_Assembler* ce, - LIR_Opr ref) const; - - void generate_c1_load_barrier_stub(LIR_Assembler* ce, - XLoadBarrierStubC1* stub) const; - - void generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, - DecoratorSet decorators) const; -#endif // COMPILER1 - -#ifdef COMPILER2 - OptoReg::Name refine_register(const Node* node, - OptoReg::Name opto_reg); - - void generate_c2_load_barrier_stub(MacroAssembler* masm, - XLoadBarrierStubC2* stub) const; -#endif // COMPILER2 - - void check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error); -}; - -#endif // CPU_X86_GC_X_XBARRIERSETASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/x/xGlobals_x86.cpp b/src/hotspot/cpu/x86/gc/x/xGlobals_x86.cpp deleted file mode 100644 index baa99ddd60db7..0000000000000 --- a/src/hotspot/cpu/x86/gc/x/xGlobals_x86.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xGlobals.hpp" -#include "runtime/globals.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/powerOfTwo.hpp" - -// -// The heap can have three different layouts, depending on the max heap size. -// -// Address Space & Pointer Layout 1 -// -------------------------------- -// -// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) -// . . -// . . -// . . -// +--------------------------------+ 0x0000014000000000 (20TB) -// | Remapped View | -// +--------------------------------+ 0x0000010000000000 (16TB) -// . . -// +--------------------------------+ 0x00000c0000000000 (12TB) -// | Marked1 View | -// +--------------------------------+ 0x0000080000000000 (8TB) -// | Marked0 View | -// +--------------------------------+ 0x0000040000000000 (4TB) -// . . -// +--------------------------------+ 0x0000000000000000 -// -// 6 4 4 4 4 -// 3 6 5 2 1 0 -// +--------------------+----+-----------------------------------------------+ -// |00000000 00000000 00|1111|11 11111111 11111111 11111111 11111111 11111111| -// +--------------------+----+-----------------------------------------------+ -// | | | -// | | * 41-0 Object Offset (42-bits, 4TB address space) -// | | -// | * 45-42 Metadata Bits (4-bits) 0001 = Marked0 (Address view 4-8TB) -// | 0010 = Marked1 (Address view 8-12TB) -// | 0100 = Remapped (Address view 16-20TB) -// | 1000 = Finalizable (Address view N/A) -// | -// * 63-46 Fixed (18-bits, always zero) -// -// -// Address Space & Pointer Layout 2 -// -------------------------------- -// -// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) -// . . -// . . -// . . -// +--------------------------------+ 0x0000280000000000 (40TB) -// | Remapped View | -// +--------------------------------+ 0x0000200000000000 (32TB) -// . . -// +--------------------------------+ 0x0000180000000000 (24TB) -// | Marked1 View | -// +--------------------------------+ 0x0000100000000000 (16TB) -// | Marked0 View | -// +--------------------------------+ 0x0000080000000000 (8TB) -// . . -// +--------------------------------+ 0x0000000000000000 -// -// 6 4 4 4 4 -// 3 7 6 3 2 0 -// +------------------+-----+------------------------------------------------+ -// |00000000 00000000 0|1111|111 11111111 11111111 11111111 11111111 11111111| -// +-------------------+----+------------------------------------------------+ -// | | | -// | | * 42-0 Object Offset (43-bits, 8TB address space) -// | | -// | * 46-43 Metadata Bits (4-bits) 0001 = Marked0 (Address view 8-16TB) -// | 0010 = Marked1 (Address view 16-24TB) -// | 0100 = Remapped (Address view 32-40TB) -// | 1000 = Finalizable (Address view N/A) -// | -// * 63-47 Fixed (17-bits, always zero) -// -// -// Address Space & Pointer Layout 3 -// -------------------------------- -// -// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) -// . . -// . . -// . . -// +--------------------------------+ 0x0000500000000000 (80TB) -// | Remapped View | -// +--------------------------------+ 0x0000400000000000 (64TB) -// . . -// +--------------------------------+ 0x0000300000000000 (48TB) -// | Marked1 View | -// +--------------------------------+ 0x0000200000000000 (32TB) -// | Marked0 View | -// +--------------------------------+ 0x0000100000000000 (16TB) -// . . -// +--------------------------------+ 0x0000000000000000 -// -// 6 4 4 4 4 -// 3 8 7 4 3 0 -// +------------------+----+-------------------------------------------------+ -// |00000000 00000000 |1111|1111 11111111 11111111 11111111 11111111 11111111| -// +------------------+----+-------------------------------------------------+ -// | | | -// | | * 43-0 Object Offset (44-bits, 16TB address space) -// | | -// | * 47-44 Metadata Bits (4-bits) 0001 = Marked0 (Address view 16-32TB) -// | 0010 = Marked1 (Address view 32-48TB) -// | 0100 = Remapped (Address view 64-80TB) -// | 1000 = Finalizable (Address view N/A) -// | -// * 63-48 Fixed (16-bits, always zero) -// - -size_t XPlatformAddressOffsetBits() { - const size_t min_address_offset_bits = 42; // 4TB - const size_t max_address_offset_bits = 44; // 16TB - const size_t address_offset = round_up_power_of_2(MaxHeapSize * XVirtualToPhysicalRatio); - const size_t address_offset_bits = log2i_exact(address_offset); - return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); -} - -size_t XPlatformAddressMetadataShift() { - return XPlatformAddressOffsetBits(); -} diff --git a/src/hotspot/cpu/x86/gc/x/xGlobals_x86.hpp b/src/hotspot/cpu/x86/gc/x/xGlobals_x86.hpp deleted file mode 100644 index dd00d4ddadcf1..0000000000000 --- a/src/hotspot/cpu/x86/gc/x/xGlobals_x86.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 CPU_X86_GC_X_XGLOBALS_X86_HPP -#define CPU_X86_GC_X_XGLOBALS_X86_HPP - -const size_t XPlatformHeapViews = 3; -const size_t XPlatformCacheLineSize = 64; - -size_t XPlatformAddressOffsetBits(); -size_t XPlatformAddressMetadataShift(); - -#endif // CPU_X86_GC_X_XGLOBALS_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/x/x_x86_64.ad b/src/hotspot/cpu/x86/gc/x/x_x86_64.ad deleted file mode 100644 index ba4b3cb6df05f..0000000000000 --- a/src/hotspot/cpu/x86/gc/x/x_x86_64.ad +++ /dev/null @@ -1,156 +0,0 @@ -// -// 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 -// 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. -// - -source_hpp %{ - -#include "gc/shared/gc_globals.hpp" -#include "gc/x/c2/xBarrierSetC2.hpp" -#include "gc/x/xThreadLocalData.hpp" - -%} - -source %{ - -#include "c2_intelJccErratum_x86.hpp" - -static void x_load_barrier(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref, Register tmp, uint8_t barrier_data) { - if (barrier_data == XLoadBarrierElided) { - return; - } - XLoadBarrierStubC2* const stub = XLoadBarrierStubC2::create(node, ref_addr, ref, tmp, barrier_data); - { - IntelJccErratumAlignment intel_alignment(masm, 10 /* jcc_size */); - __ testptr(ref, Address(r15_thread, XThreadLocalData::address_bad_mask_offset())); - __ jcc(Assembler::notZero, *stub->entry()); - } - __ bind(*stub->continuation()); -} - -static void x_load_barrier_cmpxchg(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref, Register tmp, Label& good) { - XLoadBarrierStubC2* const stub = XLoadBarrierStubC2::create(node, ref_addr, ref, tmp, XLoadBarrierStrong); - { - IntelJccErratumAlignment intel_alignment(masm, 10 /* jcc_size */); - __ testptr(ref, Address(r15_thread, XThreadLocalData::address_bad_mask_offset())); - __ jcc(Assembler::zero, good); - } - { - IntelJccErratumAlignment intel_alignment(masm, 5 /* jcc_size */); - __ jmp(*stub->entry()); - } - __ bind(*stub->continuation()); -} - -static void x_cmpxchg_common(MacroAssembler* masm, const MachNode* node, Register mem_reg, Register newval, Register tmp) { - // Compare value (oldval) is in rax - const Address mem = Address(mem_reg, 0); - - if (node->barrier_data() != XLoadBarrierElided) { - __ movptr(tmp, rax); - } - - __ lock(); - __ cmpxchgptr(newval, mem); - - if (node->barrier_data() != XLoadBarrierElided) { - Label good; - x_load_barrier_cmpxchg(masm, node, mem, rax, tmp, good); - __ movptr(rax, tmp); - __ lock(); - __ cmpxchgptr(newval, mem); - __ bind(good); - } -} - -%} - -// Load Pointer -instruct xLoadP(rRegP dst, memory mem, rFlagsReg cr) -%{ - predicate(UseZGC && !ZGenerational && n->as_Load()->barrier_data() != 0); - match(Set dst (LoadP mem)); - effect(KILL cr, TEMP dst); - - ins_cost(125); - - format %{ "movq $dst, $mem" %} - - ins_encode %{ - __ movptr($dst$$Register, $mem$$Address); - x_load_barrier(masm, this, $mem$$Address, $dst$$Register, noreg /* tmp */, barrier_data()); - %} - - ins_pipe(ialu_reg_mem); -%} - -instruct xCompareAndExchangeP(indirect mem, rax_RegP oldval, rRegP newval, rRegP tmp, rFlagsReg cr) %{ - match(Set oldval (CompareAndExchangeP mem (Binary oldval newval))); - predicate(UseZGC && !ZGenerational && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(KILL cr, TEMP tmp); - - format %{ "lock\n\t" - "cmpxchgq $newval, $mem" %} - - ins_encode %{ - precond($oldval$$Register == rax); - x_cmpxchg_common(masm, this, $mem$$Register, $newval$$Register, $tmp$$Register); - %} - - ins_pipe(pipe_cmpxchg); -%} - -instruct xCompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp, rFlagsReg cr, rax_RegP oldval) %{ - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - predicate(UseZGC && !ZGenerational && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(KILL cr, KILL oldval, TEMP tmp); - - format %{ "lock\n\t" - "cmpxchgq $newval, $mem\n\t" - "setcc $res \t# emits sete + movzbl or setzue for APX" %} - - ins_encode %{ - precond($oldval$$Register == rax); - x_cmpxchg_common(masm, this, $mem$$Register, $newval$$Register, $tmp$$Register); - if (barrier_data() != XLoadBarrierElided) { - __ cmpptr($tmp$$Register, rax); - } - __ setcc(Assembler::equal, $res$$Register); - %} - - ins_pipe(pipe_cmpxchg); -%} - -instruct xXChgP(indirect mem, rRegP newval, rFlagsReg cr) %{ - match(Set newval (GetAndSetP mem newval)); - predicate(UseZGC && !ZGenerational && n->as_LoadStore()->barrier_data() != 0); - effect(KILL cr); - - format %{ "xchgq $newval, $mem" %} - - ins_encode %{ - __ xchgptr($newval$$Register, Address($mem$$Register, 0)); - x_load_barrier(masm, this, Address(noreg, 0), $newval$$Register, noreg /* tmp */, barrier_data()); - %} - - ins_pipe(pipe_cmpxchg); -%} diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index 65d7c1e3303ba..3795b1fc176ac 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -363,8 +363,12 @@ static void emit_store_fast_path_check_c2(MacroAssembler* masm, Address ref_addr } static bool is_c2_compilation() { +#ifdef COMPILER2 CompileTask* task = ciEnv::current()->task(); return task != nullptr && is_c2_compile(task->comp_level()); +#else + return false; +#endif } void ZBarrierSetAssembler::store_barrier_fast(MacroAssembler* masm, @@ -1260,6 +1264,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, __ call(RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr())); } else if (stub->is_atomic()) { __ call(RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr())); + } else if (stub->is_nokeepalive()) { + __ call(RuntimeAddress(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr())); } else { __ call(RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr())); } diff --git a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad index 455d622acdf17..9555cadd0227d 100644 --- a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad +++ b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad @@ -91,7 +91,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address } } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; - ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic); + bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0; + ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive); ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler(); bs_asm->store_barrier_fast(masm, ref_addr, rnew_zaddress, rnew_zpointer, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation()); } @@ -114,7 +115,7 @@ operand no_rax_RegP() // Load Pointer instruct zLoadP(rRegP dst, memory mem, rFlagsReg cr) %{ - predicate(UseZGC && ZGenerational && n->as_Load()->barrier_data() != 0); + predicate(UseZGC && n->as_Load()->barrier_data() != 0); match(Set dst (LoadP mem)); effect(TEMP dst, KILL cr); @@ -133,7 +134,7 @@ instruct zLoadP(rRegP dst, memory mem, rFlagsReg cr) // Load Pointer and Null Check instruct zLoadPNullCheck(rFlagsReg cr, memory op, immP0 zero) %{ - predicate(UseZGC && ZGenerational && n->in(1)->as_Load()->barrier_data() != 0); + predicate(UseZGC && n->in(1)->as_Load()->barrier_data() != 0); match(Set cr (CmpP (LoadP op) zero)); ins_cost(500); // XXX @@ -149,7 +150,7 @@ instruct zLoadPNullCheck(rFlagsReg cr, memory op, immP0 zero) // Store Pointer instruct zStoreP(memory mem, any_RegP src, rRegP tmp, rFlagsReg cr) %{ - predicate(UseZGC && ZGenerational && n->as_Store()->barrier_data() != 0); + predicate(UseZGC && n->as_Store()->barrier_data() != 0); match(Set mem (StoreP mem src)); effect(TEMP tmp, KILL cr); @@ -165,7 +166,7 @@ instruct zStoreP(memory mem, any_RegP src, rRegP tmp, rFlagsReg cr) // Store Null Pointer instruct zStorePNull(memory mem, immP0 zero, rRegP tmp, rFlagsReg cr) %{ - predicate(UseZGC && ZGenerational && n->as_Store()->barrier_data() != 0); + predicate(UseZGC && n->as_Store()->barrier_data() != 0); match(Set mem (StoreP mem zero)); effect(TEMP tmp, KILL cr); @@ -184,7 +185,7 @@ instruct zStorePNull(memory mem, immP0 zero, rRegP tmp, rFlagsReg cr) instruct zCompareAndExchangeP(indirect mem, no_rax_RegP newval, rRegP tmp, rax_RegP oldval, rFlagsReg cr) %{ match(Set oldval (CompareAndExchangeP mem (Binary oldval newval))); - predicate(UseZGC && ZGenerational && n->as_LoadStore()->barrier_data() != 0); + predicate(UseZGC && n->as_LoadStore()->barrier_data() != 0); effect(TEMP tmp, KILL cr); format %{ "lock\n\t" @@ -207,7 +208,7 @@ instruct zCompareAndExchangeP(indirect mem, no_rax_RegP newval, rRegP tmp, rax_R instruct zCompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp, rax_RegP oldval, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - predicate(UseZGC && ZGenerational && n->as_LoadStore()->barrier_data() != 0); + predicate(UseZGC && n->as_LoadStore()->barrier_data() != 0); effect(TEMP tmp, KILL oldval, KILL cr); format %{ "lock\n\t" @@ -229,7 +230,7 @@ instruct zCompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp, rax_ instruct zXChgP(indirect mem, rRegP newval, rRegP tmp, rFlagsReg cr) %{ match(Set newval (GetAndSetP mem newval)); - predicate(UseZGC && ZGenerational && n->as_LoadStore()->barrier_data() != 0); + predicate(UseZGC && n->as_LoadStore()->barrier_data() != 0); effect(TEMP tmp, KILL cr); format %{ "xchgq $newval, $mem" %} diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 893ae4e844ba4..55c4e29b8a33b 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -3482,6 +3482,17 @@ void MacroAssembler::vpbroadcastd(XMMRegister dst, AddressLiteral src, int vecto } } +void MacroAssembler::vbroadcasti128(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch) { + assert(rscratch != noreg || always_reachable(src), "missing"); + + if (reachable(src)) { + Assembler::vbroadcasti128(dst, as_Address(src), vector_len); + } else { + lea(rscratch, src); + Assembler::vbroadcasti128(dst, Address(rscratch, 0), vector_len); + } +} + void MacroAssembler::vpbroadcastq(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch) { assert(rscratch != noreg || always_reachable(src), "missing"); @@ -5084,7 +5095,8 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa L_slow_path = &L_fallthrough; } - // Fast path check: class is fully initialized + // Fast path check: class is fully initialized. + // init_state needs acquire, but x86 is TSO, and so we are already good. cmpb(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); jcc(Assembler::equal, *L_fast_path); @@ -9302,6 +9314,30 @@ void MacroAssembler::byte_array_inflate(Register src, Register dst, Register len bind(done); } +void MacroAssembler::evmovdqu(BasicType type, KRegister kmask, XMMRegister dst, XMMRegister src, bool merge, int vector_len) { + switch(type) { + case T_BYTE: + case T_BOOLEAN: + evmovdqub(dst, kmask, src, merge, vector_len); + break; + case T_CHAR: + case T_SHORT: + evmovdquw(dst, kmask, src, merge, vector_len); + break; + case T_INT: + case T_FLOAT: + evmovdqul(dst, kmask, src, merge, vector_len); + break; + case T_LONG: + case T_DOUBLE: + evmovdquq(dst, kmask, src, merge, vector_len); + break; + default: + fatal("Unexpected type argument %s", type2name(type)); + break; + } +} + void MacroAssembler::evmovdqu(BasicType type, KRegister kmask, XMMRegister dst, Address src, bool merge, int vector_len) { switch(type) { @@ -9493,6 +9529,66 @@ void MacroAssembler::evperm(BasicType type, XMMRegister dst, KRegister mask, XMM } } +void MacroAssembler::evpminu(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + switch(type) { + case T_BYTE: + evpminub(dst, mask, nds, src, merge, vector_len); break; + case T_SHORT: + evpminuw(dst, mask, nds, src, merge, vector_len); break; + case T_INT: + evpminud(dst, mask, nds, src, merge, vector_len); break; + case T_LONG: + evpminuq(dst, mask, nds, src, merge, vector_len); break; + default: + fatal("Unexpected type argument %s", type2name(type)); break; + } +} + +void MacroAssembler::evpmaxu(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { + switch(type) { + case T_BYTE: + evpmaxub(dst, mask, nds, src, merge, vector_len); break; + case T_SHORT: + evpmaxuw(dst, mask, nds, src, merge, vector_len); break; + case T_INT: + evpmaxud(dst, mask, nds, src, merge, vector_len); break; + case T_LONG: + evpmaxuq(dst, mask, nds, src, merge, vector_len); break; + default: + fatal("Unexpected type argument %s", type2name(type)); break; + } +} + +void MacroAssembler::evpminu(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + switch(type) { + case T_BYTE: + evpminub(dst, mask, nds, src, merge, vector_len); break; + case T_SHORT: + evpminuw(dst, mask, nds, src, merge, vector_len); break; + case T_INT: + evpminud(dst, mask, nds, src, merge, vector_len); break; + case T_LONG: + evpminuq(dst, mask, nds, src, merge, vector_len); break; + default: + fatal("Unexpected type argument %s", type2name(type)); break; + } +} + +void MacroAssembler::evpmaxu(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + switch(type) { + case T_BYTE: + evpmaxub(dst, mask, nds, src, merge, vector_len); break; + case T_SHORT: + evpmaxuw(dst, mask, nds, src, merge, vector_len); break; + case T_INT: + evpmaxud(dst, mask, nds, src, merge, vector_len); break; + case T_LONG: + evpmaxuq(dst, mask, nds, src, merge, vector_len); break; + default: + fatal("Unexpected type argument %s", type2name(type)); break; + } +} + void MacroAssembler::evpmins(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len) { switch(type) { case T_BYTE: @@ -10201,17 +10297,6 @@ Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) ShouldNotReachHere(); return Assembler::overflow; } -SkipIfEqual::SkipIfEqual( - MacroAssembler* masm, const bool* flag_addr, bool value, Register rscratch) { - _masm = masm; - _masm->cmp8(ExternalAddress((address)flag_addr), value, rscratch); - _masm->jcc(Assembler::equal, _label); -} - -SkipIfEqual::~SkipIfEqual() { - _masm->bind(_label); -} - // 32-bit Windows has its own fast-path implementation // of get_thread #if !defined(WIN32) || defined(_LP64) diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 2ce4fc40e90e0..d508feed93c28 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -1118,6 +1118,7 @@ class MacroAssembler: public Assembler { XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4, Register buf, Register state, Register ofs, Register limit, Register rsp, bool multi_block, XMMRegister shuf_mask); + void sha512_update_ni_x1(Register arg_hash, Register arg_msg, Register ofs, Register limit, bool multi_block); #endif // _LP64 void fast_md5(Register buf, Address state, Address ofs, Address limit, @@ -1216,6 +1217,9 @@ class MacroAssembler: public Assembler { void addpd(XMMRegister dst, Address src) { Assembler::addpd(dst, src); } void addpd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); + using Assembler::vbroadcasti128; + void vbroadcasti128(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch = noreg); + using Assembler::vbroadcastsd; void vbroadcastsd(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch = noreg); @@ -1278,6 +1282,7 @@ class MacroAssembler: public Assembler { // AVX512 Unaligned void evmovdqu(BasicType type, KRegister kmask, Address dst, XMMRegister src, bool merge, int vector_len); void evmovdqu(BasicType type, KRegister kmask, XMMRegister dst, Address src, bool merge, int vector_len); + void evmovdqu(BasicType type, KRegister kmask, XMMRegister dst, XMMRegister src, bool merge, int vector_len); void evmovdqub(XMMRegister dst, XMMRegister src, int vector_len) { Assembler::evmovdqub(dst, src, vector_len); } void evmovdqub(XMMRegister dst, Address src, int vector_len) { Assembler::evmovdqub(dst, src, vector_len); } @@ -1291,6 +1296,7 @@ class MacroAssembler: public Assembler { void evmovdqub(XMMRegister dst, KRegister mask, Address src, bool merge, int vector_len) { Assembler::evmovdqub(dst, mask, src, merge, vector_len); } void evmovdqub(XMMRegister dst, KRegister mask, AddressLiteral src, bool merge, int vector_len, Register rscratch = noreg); + void evmovdquw(XMMRegister dst, XMMRegister src, int vector_len) { Assembler::evmovdquw(dst, src, vector_len); } void evmovdquw(Address dst, XMMRegister src, int vector_len) { Assembler::evmovdquw(dst, src, vector_len); } void evmovdquw(XMMRegister dst, Address src, int vector_len) { Assembler::evmovdquw(dst, src, vector_len); } @@ -1501,6 +1507,8 @@ class MacroAssembler: public Assembler { void vpmulld(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { Assembler::vpmulld(dst, nds, src, vector_len); } void vpmulld(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register rscratch = noreg); + void vpmuldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { Assembler::vpmuldq(dst, nds, src, vector_len); } + void vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector_len); @@ -1510,9 +1518,13 @@ class MacroAssembler: public Assembler { void vpsraw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); void vpsraw(XMMRegister dst, XMMRegister nds, int shift, int vector_len); + void evpsrad(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); + void evpsrad(XMMRegister dst, XMMRegister nds, int shift, int vector_len); + void evpsraq(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); void evpsraq(XMMRegister dst, XMMRegister nds, int shift, int vector_len); + using Assembler::evpsllw; void evpsllw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len, bool is_varshift) { if (!is_varshift) { Assembler::evpsllw(dst, mask, nds, src, merge, vector_len); @@ -1557,6 +1569,7 @@ class MacroAssembler: public Assembler { Assembler::evpsrlvq(dst, mask, nds, src, merge, vector_len); } } + using Assembler::evpsraw; void evpsraw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len, bool is_varshift) { if (!is_varshift) { Assembler::evpsraw(dst, mask, nds, src, merge, vector_len); @@ -1564,6 +1577,7 @@ class MacroAssembler: public Assembler { Assembler::evpsravw(dst, mask, nds, src, merge, vector_len); } } + using Assembler::evpsrad; void evpsrad(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len, bool is_varshift) { if (!is_varshift) { Assembler::evpsrad(dst, mask, nds, src, merge, vector_len); @@ -1585,6 +1599,11 @@ class MacroAssembler: public Assembler { void evpmins(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); void evpmaxs(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpminu(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpmaxu(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpminu(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpmaxu(BasicType type, XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void vpsrlw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); void vpsrlw(XMMRegister dst, XMMRegister nds, int shift, int vector_len); @@ -2158,22 +2177,4 @@ class MacroAssembler: public Assembler { #endif }; -/** - * class SkipIfEqual: - * - * Instantiating this class will result in assembly code being output that will - * jump around any code emitted between the creation of the instance and it's - * automatic destruction at the end of a scope block, depending on the value of - * the flag passed to the constructor, which will be checked at run-time. - */ -class SkipIfEqual { - private: - MacroAssembler* _masm; - Label _label; - - public: - SkipIfEqual(MacroAssembler*, const bool* flag_addr, bool value, Register rscratch); - ~SkipIfEqual(); -}; - #endif // CPU_X86_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp index 090de71425f17..e7d728c2e9672 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp @@ -1519,5 +1519,184 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste } } +//Implemented using Intel IpSec implementation (intel-ipsec-mb on github) +void MacroAssembler::sha512_update_ni_x1(Register arg_hash, Register arg_msg, Register ofs, Register limit, bool multi_block) { + Label done_hash, block_loop; + address K512_W = StubRoutines::x86::k512_W_addr(); + + vbroadcasti128(xmm15, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512()), Assembler::AVX_256bit, r10); + + //load current hash value and transform + vmovdqu(xmm0, Address(arg_hash)); + vmovdqu(xmm1, Address(arg_hash, 32)); + //ymm0 = D C B A, ymm1 = H G F E + vperm2i128(xmm2, xmm0, xmm1, 0x20); + vperm2i128(xmm3, xmm0, xmm1, 0x31); + //ymm2 = F E B A, ymm3 = H G D C + vpermq(xmm13, xmm2, 0x1b, Assembler::AVX_256bit); + vpermq(xmm14, xmm3, 0x1b, Assembler::AVX_256bit); + //ymm13 = A B E F, ymm14 = C D G H + + lea(rax, ExternalAddress(K512_W)); + align(32); + bind(block_loop); + vmovdqu(xmm11, xmm13);//ABEF + vmovdqu(xmm12, xmm14);//CDGH + + //R0 - R3 + vmovdqu(xmm0, Address(arg_msg, 0 * 32)); + vpshufb(xmm3, xmm0, xmm15, Assembler::AVX_256bit);//ymm0 / ymm3 = W[0..3] + vpaddq(xmm0, xmm3, Address(rax, 0 * 32), Assembler::AVX_256bit); + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + + //R4 - R7 + vmovdqu(xmm0, Address(arg_msg, 1 * 32)); + vpshufb(xmm4, xmm0, xmm15, Assembler::AVX_256bit);//ymm0 / ymm4 = W[4..7] + vpaddq(xmm0, xmm4, Address(rax, 1 * 32), Assembler::AVX_256bit); + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + sha512msg1(xmm3, xmm4); //ymm3 = W[0..3] + S0(W[1..4]) + + //R8 - R11 + vmovdqu(xmm0, Address(arg_msg, 2 * 32)); + vpshufb(xmm5, xmm0, xmm15, Assembler::AVX_256bit);//ymm0 / ymm5 = W[8..11] + vpaddq(xmm0, xmm5, Address(rax, 2 * 32), Assembler::AVX_256bit); + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + sha512msg1(xmm4, xmm5);//ymm4 = W[4..7] + S0(W[5..8]) + + //R12 - R15 + vmovdqu(xmm0, Address(arg_msg, 3 * 32)); + vpshufb(xmm6, xmm0, xmm15, Assembler::AVX_256bit); //ymm0 / ymm6 = W[12..15] + vpaddq(xmm0, xmm6, Address(rax, 3 * 32), Assembler::AVX_256bit); + vpermq(xmm8, xmm6, 0x1b, Assembler::AVX_256bit); //ymm8 = W[12] W[13] W[14] W[15] + vpermq(xmm9, xmm5, 0x39, Assembler::AVX_256bit); //ymm9 = W[8] W[11] W[10] W[9] + vpblendd(xmm8, xmm8, xmm9, 0x3f, Assembler::AVX_256bit); //ymm8 = W[12] W[11] W[10] W[9] + vpaddq(xmm3, xmm3, xmm8, Assembler::AVX_256bit); + sha512msg2(xmm3, xmm6);//W[16..19] = xmm3 + W[9..12] + S1(W[14..17]) + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + sha512msg1(xmm5, xmm6); //ymm5 = W[8..11] + S0(W[9..12]) + + //R16 - R19, R32 - R35, R48 - R51 + for (int i = 4, j = 3; j > 0; j--) { + vpaddq(xmm0, xmm3, Address(rax, i * 32), Assembler::AVX_256bit); + vpermq(xmm8, xmm3, 0x1b, Assembler::AVX_256bit);//ymm8 = W[16] W[17] W[18] W[19] + vpermq(xmm9, xmm6, 0x39, Assembler::AVX_256bit);//ymm9 = W[12] W[15] W[14] W[13] + vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//xmm7 = W[16] W[15] W[14] W[13] + vpaddq(xmm4, xmm4, xmm7, Assembler::AVX_256bit);//ymm4 = W[4..7] + S0(W[5..8]) + W[13..16] + sha512msg2(xmm4, xmm3);//ymm4 += S1(W[14..17]) + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + sha512msg1(xmm6, xmm3); //ymm6 = W[12..15] + S0(W[13..16]) + i += 1; + //R20 - R23, R36 - R39, R52 - R55 + vpaddq(xmm0, xmm4, Address(rax, i * 32), Assembler::AVX_256bit); + vpermq(xmm8, xmm4, 0x1b, Assembler::AVX_256bit);//ymm8 = W[20] W[21] W[22] W[23] + vpermq(xmm9, xmm3, 0x39, Assembler::AVX_256bit);//ymm9 = W[16] W[19] W[18] W[17] + vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[20] W[19] W[18] W[17] + vpaddq(xmm5, xmm5, xmm7, Assembler::AVX_256bit);//ymm5 = W[8..11] + S0(W[9..12]) + W[17..20] + sha512msg2(xmm5, xmm4);//ymm5 += S1(W[18..21]) + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + sha512msg1(xmm3, xmm4); //ymm3 = W[16..19] + S0(W[17..20]) + i += 1; + //R24 - R27, R40 - R43, R56 - R59 + vpaddq(xmm0, xmm5, Address(rax, i * 32), Assembler::AVX_256bit); + vpermq(xmm8, xmm5, 0x1b, Assembler::AVX_256bit);//ymm8 = W[24] W[25] W[26] W[27] + vpermq(xmm9, xmm4, 0x39, Assembler::AVX_256bit);//ymm9 = W[20] W[23] W[22] W[21] + vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[24] W[23] W[22] W[21] + vpaddq(xmm6, xmm6, xmm7, Assembler::AVX_256bit);//ymm6 = W[12..15] + S0(W[13..16]) + W[21..24] + sha512msg2(xmm6, xmm5);//ymm6 += S1(W[22..25]) + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + sha512msg1(xmm4, xmm5);//ymm4 = W[20..23] + S0(W[21..24]) + i += 1; + //R28 - R31, R44 - R47, R60 - R63 + vpaddq(xmm0, xmm6, Address(rax, i * 32), Assembler::AVX_256bit); + vpermq(xmm8, xmm6, 0x1b, Assembler::AVX_256bit);//ymm8 = W[28] W[29] W[30] W[31] + vpermq(xmm9, xmm5, 0x39, Assembler::AVX_256bit);//ymm9 = W[24] W[27] W[26] W[25] + vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[28] W[27] W[26] W[25] + vpaddq(xmm3, xmm3, xmm7, Assembler::AVX_256bit);//ymm3 = W[16..19] + S0(W[17..20]) + W[25..28] + sha512msg2(xmm3, xmm6); //ymm3 += S1(W[26..29]) + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + sha512msg1(xmm5, xmm6);//ymm5 = W[24..27] + S0(W[25..28]) + i += 1; + } + //R64 - R67 + vpaddq(xmm0, xmm3, Address(rax, 16 * 32), Assembler::AVX_256bit); + vpermq(xmm8, xmm3, 0x1b, Assembler::AVX_256bit);//ymm8 = W[64] W[65] W[66] W[67] + vpermq(xmm9, xmm6, 0x39, Assembler::AVX_256bit);//ymm9 = W[60] W[63] W[62] W[61] + vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[64] W[63] W[62] W[61] + vpaddq(xmm4, xmm4, xmm7, Assembler::AVX_256bit);//ymm4 = W[52..55] + S0(W[53..56]) + W[61..64] + sha512msg2(xmm4, xmm3);//ymm4 += S1(W[62..65]) + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + sha512msg1(xmm6, xmm3);//ymm6 = W[60..63] + S0(W[61..64]) + + //R68 - R71 + vpaddq(xmm0, xmm4, Address(rax, 17 * 32), Assembler::AVX_256bit); + vpermq(xmm8, xmm4, 0x1b, Assembler::AVX_256bit);//ymm8 = W[68] W[69] W[70] W[71] + vpermq(xmm9, xmm3, 0x39, Assembler::AVX_256bit);//ymm9 = W[64] W[67] W[66] W[65] + vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[68] W[67] W[66] W[65] + vpaddq(xmm5, xmm5, xmm7, Assembler::AVX_256bit);//ymm5 = W[56..59] + S0(W[57..60]) + W[65..68] + sha512msg2(xmm5, xmm4);//ymm5 += S1(W[66..69]) + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + + //R72 - R75 + vpaddq(xmm0, xmm5, Address(rax, 18 * 32), Assembler::AVX_256bit); + vpermq(xmm8, xmm5, 0x1b, Assembler::AVX_256bit);//ymm8 = W[72] W[73] W[74] W[75] + vpermq(xmm9, xmm4, 0x39, Assembler::AVX_256bit);//ymm9 = W[68] W[71] W[70] W[69] + vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[72] W[71] W[70] W[69] + vpaddq(xmm6, xmm6, xmm7, Assembler::AVX_256bit);//ymm6 = W[60..63] + S0(W[61..64]) + W[69..72] + sha512msg2(xmm6, xmm5);//ymm6 += S1(W[70..73]) + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + + //R76 - R79 + vpaddq(xmm0, xmm6, Address(rax, 19 * 32), Assembler::AVX_256bit); + sha512rnds2(xmm12, xmm11, xmm0); + vperm2i128(xmm0, xmm0, xmm0, 0x01); + sha512rnds2(xmm11, xmm12, xmm0); + + //update hash value + vpaddq(xmm14, xmm14, xmm12, Assembler::AVX_256bit); + vpaddq(xmm13, xmm13, xmm11, Assembler::AVX_256bit); + + if (multi_block) { + addptr(arg_msg, 4 * 32); + addptr(ofs, 128); + cmpptr(ofs, limit); + jcc(Assembler::belowEqual, block_loop); + movptr(rax, ofs); //return ofs + } + + //store the hash value back in memory + //xmm13 = ABEF + //xmm14 = CDGH + vperm2i128(xmm1, xmm13, xmm14, 0x31); + vperm2i128(xmm2, xmm13, xmm14, 0x20); + vpermq(xmm1, xmm1, 0xb1, Assembler::AVX_256bit);//ymm1 = D C B A + vpermq(xmm2, xmm2, 0xb1, Assembler::AVX_256bit);//ymm2 = H G F E + vmovdqu(Address(arg_hash, 0 * 32), xmm1); + vmovdqu(Address(arg_hash, 1 * 32), xmm2); + + bind(done_hash); +} + #endif //#ifdef _LP64 diff --git a/src/hotspot/cpu/x86/nativeInst_x86.cpp b/src/hotspot/cpu/x86/nativeInst_x86.cpp index 395c3219809de..d5021c29ed6b0 100644 --- a/src/hotspot/cpu/x86/nativeInst_x86.cpp +++ b/src/hotspot/cpu/x86/nativeInst_x86.cpp @@ -81,7 +81,7 @@ void NativeCall::insert(address code_pos, address entry) { // (spinlock). Then patches the last byte, and then atomically replaces // the jmp's with the first 4 byte of the new instruction. void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) { - assert(Patching_lock->is_locked() || + assert(CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "concurrent code patching"); assert (instr_addr != nullptr, "illegal address for code patching"); @@ -144,7 +144,7 @@ void NativeCall::set_destination_mt_safe(address dest) { debug_only(verify()); // Make sure patching code is locked. No two threads can patch at the same // time but one may be executing this code. - assert(Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint() || + assert(CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint() || CompiledICLocker::is_safe(instruction_address()), "concurrent code patching"); // Both C1 and C2 should now be generating code which aligns the patched address // to be within a single cache line. diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 4f37dc31d0305..93b1618024e2d 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "classfile/javaClasses.hpp" #include "classfile/vmIntrinsics.hpp" #include "compiler/oopMap.hpp" #include "gc/shared/barrierSet.hpp" @@ -1557,7 +1558,7 @@ address StubGenerator::generate_sha256_implCompress(bool multi_block, const char address StubGenerator::generate_sha512_implCompress(bool multi_block, const char *name) { assert(VM_Version::supports_avx2(), ""); - assert(VM_Version::supports_bmi2(), ""); + assert(VM_Version::supports_bmi2() || VM_Version::supports_sha512(), ""); __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", name); address start = __ pc(); @@ -1567,22 +1568,24 @@ address StubGenerator::generate_sha512_implCompress(bool multi_block, const char Register ofs = c_rarg2; Register limit = c_rarg3; - const XMMRegister msg = xmm0; - const XMMRegister state0 = xmm1; - const XMMRegister state1 = xmm2; - const XMMRegister msgtmp0 = xmm3; - const XMMRegister msgtmp1 = xmm4; - const XMMRegister msgtmp2 = xmm5; - const XMMRegister msgtmp3 = xmm6; - const XMMRegister msgtmp4 = xmm7; - - const XMMRegister shuf_mask = xmm8; - __ enter(); - __ sha512_AVX2(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4, - buf, state, ofs, limit, rsp, multi_block, shuf_mask); - + if (VM_Version::supports_sha512()) { + __ sha512_update_ni_x1(state, buf, ofs, limit, multi_block); + } else { + const XMMRegister msg = xmm0; + const XMMRegister state0 = xmm1; + const XMMRegister state1 = xmm2; + const XMMRegister msgtmp0 = xmm3; + const XMMRegister msgtmp1 = xmm4; + const XMMRegister msgtmp2 = xmm5; + const XMMRegister msgtmp3 = xmm6; + const XMMRegister msgtmp4 = xmm7; + + const XMMRegister shuf_mask = xmm8; + __ sha512_AVX2(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4, + buf, state, ofs, limit, rsp, multi_block, shuf_mask); + } __ vzeroupper(); __ leave(); __ ret(0); @@ -3796,6 +3799,28 @@ address StubGenerator::generate_upcall_stub_exception_handler() { return start; } +// load Method* target of MethodHandle +// j_rarg0 = jobject receiver +// rbx = result +address StubGenerator::generate_upcall_stub_load_target() { + StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target"); + address start = __ pc(); + + __ resolve_global_jobject(j_rarg0, r15_thread, rscratch1); + // Load target method from receiver + __ load_heap_oop(rbx, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), rscratch1); + __ load_heap_oop(rbx, Address(rbx, java_lang_invoke_LambdaForm::vmentry_offset()), rscratch1); + __ load_heap_oop(rbx, Address(rbx, java_lang_invoke_MemberName::method_offset()), rscratch1); + __ access_load_at(T_ADDRESS, IN_HEAP, rbx, + Address(rbx, java_lang_invoke_ResolvedMethodName::vmtarget_offset()), + noreg, noreg); + __ movptr(Address(r15_thread, JavaThread::callee_target_offset()), rbx); // just in case callee is deoptimized + + __ ret(0); + + return start; +} + address StubGenerator::generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { StubCodeMark mark(this, "StubRoutines", "lookup_secondary_supers_table"); @@ -3955,6 +3980,7 @@ void StubGenerator::generate_final_stubs() { } StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); } void StubGenerator::generate_compiler_stubs() { @@ -4006,6 +4032,8 @@ void StubGenerator::generate_compiler_stubs() { generate_chacha_stubs(); + generate_sha3_stubs(); + #ifdef COMPILER2 if ((UseAVX == 2) && EnableX86ECoreOpts) { generate_string_indexof(StubRoutines::_string_indexof_array); @@ -4160,41 +4188,41 @@ void StubGenerator::generate_compiler_stubs() { log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "jsvml" JNI_LIB_SUFFIX, p2i(libjsvml)); if (UseAVX > 2) { - for (int op = 0; op < VectorSupport::NUM_SVML_OP; op++) { - int vop = VectorSupport::VECTOR_OP_SVML_START + op; + for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { + int vop = VectorSupport::VECTOR_OP_MATH_START + op; if ((!VM_Version::supports_avx512dq()) && (vop == VectorSupport::VECTOR_OP_LOG || vop == VectorSupport::VECTOR_OP_LOG10 || vop == VectorSupport::VECTOR_OP_POW)) { continue; } - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf16_ha_z0", VectorSupport::svmlname[op]); + snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf16_ha_z0", VectorSupport::mathname[op]); StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_512][op] = (address)os::dll_lookup(libjsvml, ebuf); - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s8_ha_z0", VectorSupport::svmlname[op]); + snprintf(ebuf, sizeof(ebuf), "__jsvml_%s8_ha_z0", VectorSupport::mathname[op]); StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_512][op] = (address)os::dll_lookup(libjsvml, ebuf); } } const char* avx_sse_str = (UseAVX >= 2) ? "l9" : ((UseAVX == 1) ? "e9" : "ex"); - for (int op = 0; op < VectorSupport::NUM_SVML_OP; op++) { - int vop = VectorSupport::VECTOR_OP_SVML_START + op; + for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { + int vop = VectorSupport::VECTOR_OP_MATH_START + op; if (vop == VectorSupport::VECTOR_OP_POW) { continue; } - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::svmlname[op], avx_sse_str); + snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::mathname[op], avx_sse_str); StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libjsvml, ebuf); - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::svmlname[op], avx_sse_str); + snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::mathname[op], avx_sse_str); StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libjsvml, ebuf); - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf8_ha_%s", VectorSupport::svmlname[op], avx_sse_str); + snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf8_ha_%s", VectorSupport::mathname[op], avx_sse_str); StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_256][op] = (address)os::dll_lookup(libjsvml, ebuf); - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s1_ha_%s", VectorSupport::svmlname[op], avx_sse_str); + snprintf(ebuf, sizeof(ebuf), "__jsvml_%s1_ha_%s", VectorSupport::mathname[op], avx_sse_str); StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libjsvml, ebuf); - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s2_ha_%s", VectorSupport::svmlname[op], avx_sse_str); + snprintf(ebuf, sizeof(ebuf), "__jsvml_%s2_ha_%s", VectorSupport::mathname[op], avx_sse_str); StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libjsvml, ebuf); - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s4_ha_%s", VectorSupport::svmlname[op], avx_sse_str); + snprintf(ebuf, sizeof(ebuf), "__jsvml_%s4_ha_%s", VectorSupport::mathname[op], avx_sse_str); StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_256][op] = (address)os::dll_lookup(libjsvml, ebuf); } } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 71777fbfffea2..c6fa31c5213b0 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -497,6 +497,10 @@ class StubGenerator: public StubCodeGenerator { address generate_intpoly_montgomeryMult_P256(); address generate_intpoly_assign(); + // SHA3 stubs + void generate_sha3_stubs(); + address generate_sha3_implCompress(bool multiBlock, const char *name); + // BASE64 stubs address base64_shuffle_addr(); @@ -620,6 +624,7 @@ class StubGenerator: public StubCodeGenerator { // shared exception handler for FFM upcall stubs address generate_upcall_stub_exception_handler(); + address generate_upcall_stub_load_target(); // Specialized stub implementations for UseSecondarySupersTable. address generate_lookup_secondary_supers_table_stub(u1 super_klass_index); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp new file mode 100644 index 0000000000000..49c39226708e3 --- /dev/null +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "runtime/stubRoutines.hpp" +#include "macroAssembler_x86.hpp" +#include "stubGenerator_x86_64.hpp" + +#define __ _masm-> + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif // PRODUCT + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +// Constants +ATTRIBUTE_ALIGNED(64) static const uint64_t round_consts_arr[24] = { + 0x0000000000000001L, 0x0000000000008082L, 0x800000000000808AL, + 0x8000000080008000L, 0x000000000000808BL, 0x0000000080000001L, + 0x8000000080008081L, 0x8000000000008009L, 0x000000000000008AL, + 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000AL, + 0x000000008000808BL, 0x800000000000008BL, 0x8000000000008089L, + 0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L, + 0x000000000000800AL, 0x800000008000000AL, 0x8000000080008081L, + 0x8000000000008080L, 0x0000000080000001L, 0x8000000080008008L + }; + +ATTRIBUTE_ALIGNED(64) static const uint64_t permsAndRots[] = { + // permutation in combined rho and pi + 9, 2, 11, 0, 1, 2, 3, 4, // step 1 and 3 + 8, 1, 9, 2, 11, 4, 12, 0, // step 2 + 9, 2, 10, 3, 11, 4, 12, 0, // step 4 + 8, 9, 2, 3, 4, 5, 6, 7, // step 5 + 0, 8, 9, 10, 15, 0, 0, 0, // step 6 + 4, 5, 8, 9, 6, 7, 10, 11, // step 7 and 8 + 0, 1, 2, 3, 13, 0, 0, 0, // step 9 + 2, 3, 0, 1, 11, 0, 0, 0, // step 10 + 4, 5, 6, 7, 14, 0, 0, 0, // step 11 + 14, 15, 12, 13, 4, 0, 0, 0, // step 12 + // size of rotations (after step 5) + 1, 6, 62, 55, 28, 20, 27, 36, + 3, 45, 10, 15, 25, 8, 39, 41, + 44, 43, 21, 18, 2, 61, 56, 14, + // rotation of row elements + 12, 8, 9, 10, 11, 5, 6, 7, + 9, 10, 11, 12, 8, 5, 6, 7 +}; + +static address round_constsAddr() { + return (address) round_consts_arr; +} + +static address permsAndRotsAddr() { + return (address) permsAndRots; +} + +void StubGenerator::generate_sha3_stubs() { + if (UseSHA3Intrinsics) { + StubRoutines::_sha3_implCompress = generate_sha3_implCompress(false,"sha3_implCompress"); + StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress(true, "sha3_implCompressMB"); + } +} + +// Arguments: +// +// Inputs: +// c_rarg0 - byte[] source+offset +// c_rarg1 - long[] SHA3.state +// c_rarg2 - int block_size +// c_rarg3 - int offset +// c_rarg4 - int limit +// +address StubGenerator::generate_sha3_implCompress(bool multiBlock, const char *name) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + + const Register buf = c_rarg0; + const Register state = c_rarg1; + const Register block_size = c_rarg2; + const Register ofs = c_rarg3; +#ifndef _WIN64 + const Register limit = c_rarg4; +#else + const Address limit_mem(rbp, 6 * wordSize); + const Register limit = r12; +#endif + + const Register permsAndRots = r10; + const Register round_consts = r11; + const Register constant2use = r13; + const Register roundsLeft = r14; + + Label sha3_loop; + Label rounds24_loop, block104, block136, block144, block168; + + __ enter(); + + __ push(r12); + __ push(r13); + __ push(r14); + +#ifdef _WIN64 + // on win64, fill limit from stack position + __ movptr(limit, limit_mem); +#endif + + __ lea(permsAndRots, ExternalAddress(permsAndRotsAddr())); + __ lea(round_consts, ExternalAddress(round_constsAddr())); + + // set up the masks + __ movl(rax, 0x1F); + __ kmovwl(k5, rax); + __ kshiftrwl(k4, k5, 1); + __ kshiftrwl(k3, k5, 2); + __ kshiftrwl(k2, k5, 3); + __ kshiftrwl(k1, k5, 4); + + // load the state + __ evmovdquq(xmm0, k5, Address(state, 0), false, Assembler::AVX_512bit); + __ evmovdquq(xmm1, k5, Address(state, 40), false, Assembler::AVX_512bit); + __ evmovdquq(xmm2, k5, Address(state, 80), false, Assembler::AVX_512bit); + __ evmovdquq(xmm3, k5, Address(state, 120), false, Assembler::AVX_512bit); + __ evmovdquq(xmm4, k5, Address(state, 160), false, Assembler::AVX_512bit); + + // load the permutation and rotation constants + __ evmovdquq(xmm17, Address(permsAndRots, 0), Assembler::AVX_512bit); + __ evmovdquq(xmm18, Address(permsAndRots, 64), Assembler::AVX_512bit); + __ evmovdquq(xmm19, Address(permsAndRots, 128), Assembler::AVX_512bit); + __ evmovdquq(xmm20, Address(permsAndRots, 192), Assembler::AVX_512bit); + __ evmovdquq(xmm21, Address(permsAndRots, 256), Assembler::AVX_512bit); + __ evmovdquq(xmm22, Address(permsAndRots, 320), Assembler::AVX_512bit); + __ evmovdquq(xmm23, Address(permsAndRots, 384), Assembler::AVX_512bit); + __ evmovdquq(xmm24, Address(permsAndRots, 448), Assembler::AVX_512bit); + __ evmovdquq(xmm25, Address(permsAndRots, 512), Assembler::AVX_512bit); + __ evmovdquq(xmm26, Address(permsAndRots, 576), Assembler::AVX_512bit); + __ evmovdquq(xmm27, Address(permsAndRots, 640), Assembler::AVX_512bit); + __ evmovdquq(xmm28, Address(permsAndRots, 704), Assembler::AVX_512bit); + __ evmovdquq(xmm29, Address(permsAndRots, 768), Assembler::AVX_512bit); + __ evmovdquq(xmm30, Address(permsAndRots, 832), Assembler::AVX_512bit); + __ evmovdquq(xmm31, Address(permsAndRots, 896), Assembler::AVX_512bit); + + __ BIND(sha3_loop); + + // there will be 24 keccak rounds + __ movl(roundsLeft, 24); + // load round_constants base + __ movptr(constant2use, round_consts); + + // load input: 72, 104, 136, 144 or 168 bytes + // i.e. 5+4, 2*5+3, 3*5+2, 3*5+3 or 4*5+1 longs + __ evpxorq(xmm0, k5, xmm0, Address(buf, 0), true, Assembler::AVX_512bit); + + // if(blockSize == 72) SHA3-512 + __ cmpl(block_size, 72); + __ jcc(Assembler::notEqual, block104); + __ evpxorq(xmm1, k4, xmm1, Address(buf, 40), true, Assembler::AVX_512bit); + __ jmp(rounds24_loop); + + // if(blockSize == 104) SHA3-384 + __ BIND(block104); + __ cmpl(block_size, 104); + __ jcc(Assembler::notEqual, block136); + __ evpxorq(xmm1, k5, xmm1, Address(buf, 40), true, Assembler::AVX_512bit); + __ evpxorq(xmm2, k3, xmm2, Address(buf, 80), true, Assembler::AVX_512bit); + __ jmp(rounds24_loop); + + // if(blockSize == 136) SHA3-256 and SHAKE256 + __ BIND(block136); + __ cmpl(block_size, 136); + __ jcc(Assembler::notEqual, block144); + __ evpxorq(xmm1, k5, xmm1, Address(buf, 40), true, Assembler::AVX_512bit); + __ evpxorq(xmm2, k5, xmm2, Address(buf, 80), true, Assembler::AVX_512bit); + __ evpxorq(xmm3, k2, xmm3, Address(buf, 120), true, Assembler::AVX_512bit); + __ jmp(rounds24_loop); + + // if(blockSize == 144) SHA3-224 + __ BIND(block144); + __ cmpl(block_size, 144); + __ jcc(Assembler::notEqual, block168); + __ evpxorq(xmm1, k5, xmm1, Address(buf, 40), true, Assembler::AVX_512bit); + __ evpxorq(xmm2, k5, xmm2, Address(buf, 80), true, Assembler::AVX_512bit); + __ evpxorq(xmm3, k3, xmm3, Address(buf, 120), true, Assembler::AVX_512bit); + __ jmp(rounds24_loop); + + // if(blockSize == 168) SHAKE128 + __ BIND(block168); + __ evpxorq(xmm1, k5, xmm1, Address(buf, 40), true, Assembler::AVX_512bit); + __ evpxorq(xmm2, k5, xmm2, Address(buf, 80), true, Assembler::AVX_512bit); + __ evpxorq(xmm3, k5, xmm3, Address(buf, 120), true, Assembler::AVX_512bit); + __ evpxorq(xmm4, k1, xmm4, Address(buf, 160), true, Assembler::AVX_512bit); + + // The 24 rounds of the keccak transformation. + // The implementation closely follows the Java version, with the state + // array "rows" in the lowest 5 64-bit slots of zmm0 - zmm4, i.e. + // each row of the SHA3 specification is located in one zmm register. + __ BIND(rounds24_loop); + __ subl(roundsLeft, 1); + + __ evmovdquw(xmm5, xmm0, Assembler::AVX_512bit); + // vpternlogq(x, 150, y, z) does x = x ^ y ^ z + __ vpternlogq(xmm5, 150, xmm1, xmm2, Assembler::AVX_512bit); + __ vpternlogq(xmm5, 150, xmm3, xmm4, Assembler::AVX_512bit); + // Now the "c row", i.e. c0-c4 are in zmm5. + // Rotate each element of the c row by one bit to zmm6, call the + // rotated version c'. + __ evprolq(xmm6, xmm5, 1, Assembler::AVX_512bit); + // Rotate elementwise the c row so that c4 becomes c0, + // c0 becomes c1, etc. + __ evpermt2q(xmm5, xmm30, xmm5, Assembler::AVX_512bit); + // rotate elementwise the c' row so that c'0 becomes c'4, + // c'1 becomes c'0, etc. + __ evpermt2q(xmm6, xmm31, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm0, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm1, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm2, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm3, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm4, 150, xmm5, xmm6, Assembler::AVX_512bit); + // Now the theta mapping has been finished. + + // Do the cyclical permutation of the 24 moving state elements + // and the required rotations within each element (the combined + // rho and sigma steps). + __ evpermt2q(xmm4, xmm17, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm3, xmm18, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm2, xmm17, xmm1, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm19, xmm0, Assembler::AVX_512bit); + __ evpermt2q(xmm4, xmm20, xmm2, Assembler::AVX_512bit); + // The 24 moving elements are now in zmm1, zmm3 and zmm4, + // do the rotations now. + __ evprolvq(xmm1, xmm1, xmm27, Assembler::AVX_512bit); + __ evprolvq(xmm3, xmm3, xmm28, Assembler::AVX_512bit); + __ evprolvq(xmm4, xmm4, xmm29, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm1, Assembler::AVX_512bit); + __ evmovdquw(xmm5, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm0, xmm21, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm22, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm5, xmm22, xmm2, Assembler::AVX_512bit); + __ evmovdquw(xmm3, xmm1, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm23, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm2, xmm24, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm3, xmm25, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm4, xmm26, xmm5, Assembler::AVX_512bit); + // The combined rho and sigma steps are done. + + // Do the chi step (the same operation on all 5 rows). + // vpternlogq(x, 180, y, z) does x = x ^ (y & ~z). + __ evpermt2q(xmm5, xmm31, xmm0, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm0, 180, xmm6, xmm5, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm1, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm1, 180, xmm6, xmm5, Assembler::AVX_512bit); + + // xor the round constant into a0 (the lowest 64 bits of zmm0 + __ evpxorq(xmm0, k1, xmm0, Address(constant2use, 0), true, Assembler::AVX_512bit); + __ addptr(constant2use, 8); + + __ evpermt2q(xmm5, xmm31, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm2, 180, xmm6, xmm5, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm3, 180, xmm6, xmm5, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm4, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ cmpl(roundsLeft, 0); + __ jcc(Assembler::notEqual, rounds24_loop); + + if (multiBlock) { + __ addptr(buf, block_size); + __ addl(ofs, block_size); + __ cmpl(ofs, limit); + __ jcc(Assembler::lessEqual, sha3_loop); + __ movq(rax, ofs); // return ofs + } else { + __ xorq(rax, rax); // return 0 + } + + // store the state + __ evmovdquq(Address(state, 0), k5, xmm0, true, Assembler::AVX_512bit); + __ evmovdquq(Address(state, 40), k5, xmm1, true, Assembler::AVX_512bit); + __ evmovdquq(Address(state, 80), k5, xmm2, true, Assembler::AVX_512bit); + __ evmovdquq(Address(state, 120), k5, xmm3, true, Assembler::AVX_512bit); + __ evmovdquq(Address(state, 160), k5, xmm4, true, Assembler::AVX_512bit); + + __ pop(r14); + __ pop(r13); + __ pop(r12); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; +} diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 5e783225fcbfc..527d961259ecc 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -4048,6 +4048,7 @@ void TemplateTable::_new() { __ push(rcx); // save the contexts of klass for initializing the header // make sure klass is initialized + // init_state needs acquire, but x86 is TSO, and so we are already good. #ifdef _LP64 assert(VM_Version::supports_fast_class_init_checks(), "must support fast class initialization checks"); __ clinit_barrier(rcx, r15_thread, nullptr /*L_fast_path*/, &slow_case); diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp index e5075e180d9d6..d795c751d02b5 100644 --- a/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp +++ b/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "prims/upcallLinker.hpp" -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp index 82179f9022e92..bc261bfd93f44 100644 --- a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp @@ -23,7 +23,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" -#include "code/codeBlob.hpp" +#include "classfile/javaClasses.hpp" #include "code/codeBlob.hpp" #include "code/vmreg.inline.hpp" #include "compiler/disassembler.hpp" @@ -169,10 +169,10 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr __ block_comment("} restore_callee_saved_regs "); } -static const int upcall_stub_code_base_size = 1024; +static const int upcall_stub_code_base_size = 1200; static const int upcall_stub_size_per_arg = 16; -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, @@ -281,7 +281,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ vzeroupper(); __ lea(c_rarg0, Address(rsp, frame_data_offset)); - __ movptr(c_rarg1, (intptr_t)receiver); // stack already aligned __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry))); __ movptr(r15_thread, rax); @@ -297,12 +296,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, arg_shuffle.generate(_masm, shuffle_reg, abi._shadow_space_bytes, 0); __ block_comment("} argument shuffle"); - __ block_comment("{ receiver "); - __ get_vm_result(j_rarg0, r15_thread); - __ block_comment("} receiver "); - - __ mov_metadata(rbx, entry); - __ movptr(Address(r15_thread, JavaThread::callee_target_offset()), rbx); // just in case callee is deoptimized + __ block_comment("{ load target "); + __ movptr(j_rarg0, (intptr_t)receiver); + __ call(RuntimeAddress(StubRoutines::upcall_stub_load_target())); // puts target Method* in rbx + __ block_comment("} load target "); __ push_cont_fastpath(); @@ -377,7 +374,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, #ifndef PRODUCT stringStream ss; - ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + ss.print("upcall_stub_%s", signature->as_C_string()); const char* name = _masm->code_string(ss.freeze()); #else // PRODUCT const char* name = "upcall_stub"; diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 2549feb8a4069..f8c5de551cddb 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -437,6 +437,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ cmpl(rax, 0x80000); __ jcc(Assembler::notEqual, vector_save_restore); +#ifndef PRODUCT bool save_apx = UseAPX; VM_Version::set_apx_cpuFeatures(); UseAPX = true; @@ -453,6 +454,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movq(Address(rsi, 8), r31); UseAPX = save_apx; +#endif #endif __ bind(vector_save_restore); // @@ -1058,6 +1060,7 @@ void VM_Version::get_processor_features() { _features &= ~CPU_AVX; _features &= ~CPU_VZEROUPPER; _features &= ~CPU_F16C; + _features &= ~CPU_SHA512; } if (logical_processors_per_package() == 1) { @@ -1302,7 +1305,7 @@ void VM_Version::get_processor_features() { #ifdef _LP64 // These are only supported on 64-bit - if (UseSHA && supports_avx2() && supports_bmi2()) { + if (UseSHA && supports_avx2() && (supports_bmi2() || supports_sha512())) { if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); } @@ -1313,9 +1316,16 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } - if (UseSHA3Intrinsics) { - warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); - FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); +#ifdef _LP64 + if (supports_evex() && supports_avx512bw()) { + if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) { + UseSHA3Intrinsics = true; + } + } else +#endif + if (UseSHA3Intrinsics) { + warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); + FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) { @@ -3005,6 +3015,8 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const { xem_xcr0_eax.bits.ymm != 0) { result |= CPU_AVX; result |= CPU_VZEROUPPER; + if (sefsl1_cpuid7_eax.bits.sha512 != 0) + result |= CPU_SHA512; if (std_cpuid1_ecx.bits.f16c != 0) result |= CPU_F16C; if (sef_cpuid7_ebx.bits.avx2 != 0) { diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index d58b5a9c09967..791f4a1fec72e 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -283,7 +283,8 @@ class VM_Version : public Abstract_VM_Version { union SefCpuid7SubLeaf1Eax { uint32_t value; struct { - uint32_t : 23, + uint32_t sha512 : 1, + : 22, avx_ifma : 1, : 8; } bits; @@ -415,7 +416,8 @@ class VM_Version : public Abstract_VM_Version { decl(CET_SS, "cet_ss", 57) /* Control Flow Enforcement - Shadow Stack */ \ decl(AVX512_IFMA, "avx512_ifma", 58) /* Integer Vector FMA instructions*/ \ decl(AVX_IFMA, "avx_ifma", 59) /* 256-bit VEX-coded variant of AVX512-IFMA*/ \ - decl(APX_F, "apx_f", 60) /* Intel Advanced Performance Extensions*/ + decl(APX_F, "apx_f", 60) /* Intel Advanced Performance Extensions*/\ + decl(SHA512, "sha512", 61) /* SHA512 instructions*/ #define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1ULL << bit), CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG) @@ -638,9 +640,10 @@ class VM_Version : public Abstract_VM_Version { LP64_ONLY(static void clear_apx_test_state()); static void clean_cpuFeatures() { _features = 0; } - static void set_avx_cpuFeatures() { _features = (CPU_SSE | CPU_SSE2 | CPU_AVX | CPU_VZEROUPPER ); } - static void set_evex_cpuFeatures() { _features = (CPU_AVX512F | CPU_SSE | CPU_SSE2 | CPU_VZEROUPPER ); } + static void set_avx_cpuFeatures() { _features |= (CPU_SSE | CPU_SSE2 | CPU_AVX | CPU_VZEROUPPER ); } + static void set_evex_cpuFeatures() { _features |= (CPU_AVX512F | CPU_SSE | CPU_SSE2 | CPU_VZEROUPPER ); } static void set_apx_cpuFeatures() { _features |= CPU_APX_F; } + static void set_bmi_cpuFeatures() { _features |= (CPU_BMI1 | CPU_BMI2 | CPU_LZCNT); } // Initialization static void initialize(); @@ -757,6 +760,7 @@ class VM_Version : public Abstract_VM_Version { static bool supports_ospke() { return (_features & CPU_OSPKE) != 0; } static bool supports_cet_ss() { return (_features & CPU_CET_SS) != 0; } static bool supports_cet_ibt() { return (_features & CPU_CET_IBT) != 0; } + static bool supports_sha512() { return (_features & CPU_SHA512) != 0; } // // Feature identification not affected by VM flags diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 2b29dd14e4b27..e5222d3863202 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1765,6 +1765,12 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { return false; } break; + case Op_UMinV: + case Op_UMaxV: + if (UseAVX == 0) { + return false; + } + break; case Op_MaxV: case Op_MinV: if (UseSSE < 4 && is_integral_type(bt)) { @@ -1935,6 +1941,29 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { return false; } break; + case Op_SaturatingAddV: + case Op_SaturatingSubV: + if (UseAVX < 1) { + return false; // Implementation limitation + } + if (is_subword_type(bt) && size_in_bits == 512 && !VM_Version::supports_avx512bw()) { + return false; + } + break; + case Op_SelectFromTwoVector: + if (size_in_bits < 128 || (size_in_bits < 512 && !VM_Version::supports_avx512vl())) { + return false; + } + if (bt == T_SHORT && !VM_Version::supports_avx512bw()) { + return false; + } + if (bt == T_BYTE && !VM_Version::supports_avx512_vbmi()) { + return false; + } + if ((bt == T_INT || bt == T_FLOAT || bt == T_DOUBLE) && !VM_Version::supports_evex()) { + return false; + } + break; case Op_MaskAll: if (!VM_Version::supports_evex()) { return false; @@ -2111,6 +2140,8 @@ bool Matcher::match_rule_supported_vector_masked(int opcode, int vlen, BasicType case Op_MaxV: case Op_MinV: + case Op_UMinV: + case Op_UMaxV: if (is_subword_type(bt) && !VM_Version::supports_avx512bw()) { return false; // Implementation limitation } @@ -2118,6 +2149,15 @@ bool Matcher::match_rule_supported_vector_masked(int opcode, int vlen, BasicType return false; // Implementation limitation } return true; + case Op_SaturatingAddV: + case Op_SaturatingSubV: + if (!is_subword_type(bt)) { + return false; + } + if (size_in_bits < 128 || !VM_Version::supports_avx512bw()) { + return false; // Implementation limitation + } + return true; case Op_VectorMaskCmp: if (is_subword_type(bt) && !VM_Version::supports_avx512bw()) { @@ -2231,10 +2271,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return &_VECTMASK_REG_mask; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return new TypeVectMask(elemTy, length); -} - // Max vector size in bytes. 0 if not supported. int Matcher::vector_width_in_bytes(BasicType bt) { assert(is_java_primitive(bt), "only primitive type vectors"); @@ -2457,6 +2493,10 @@ bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { mstack.push(m, Visit); // m = ShiftCntV return true; } + if (is_encode_and_store_pattern(n, m)) { + mstack.push(m, Visit); + return true; + } return false; } @@ -3672,6 +3712,7 @@ instruct vconvF2HF(vec dst, vec src) %{ %} instruct vconvF2HF_mem_reg(memory mem, vec src) %{ + predicate(n->as_StoreVector()->memory_size() >= 16); match(Set mem (StoreVector mem (VectorCastF2HF src))); format %{ "vcvtps2ph $mem,$src" %} ins_encode %{ @@ -6477,6 +6518,80 @@ instruct evminmaxFP_reg_eavx(vec dst, vec a, vec b, vec atmp, vec btmp, kReg ktm ins_pipe( pipe_slow ); %} +// ------------------------------ Unsigned vector Min/Max ---------------------- + +instruct vector_uminmax_reg(vec dst, vec a, vec b) %{ + predicate(VM_Version::supports_avx512vl() || Matcher::vector_element_basic_type(n) != T_LONG); + match(Set dst (UMinV a b)); + match(Set dst (UMaxV a b)); + format %{ "vector_uminmax $dst,$a,$b\t!" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(elem_bt), ""); + __ vpuminmax(opcode, elem_bt, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_uminmax_mem(vec dst, vec a, memory b) %{ + predicate(VM_Version::supports_avx512vl() || Matcher::vector_element_basic_type(n) != T_LONG); + match(Set dst (UMinV a (LoadVector b))); + match(Set dst (UMaxV a (LoadVector b))); + format %{ "vector_uminmax $dst,$a,$b\t!" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(elem_bt), ""); + __ vpuminmax(opcode, elem_bt, $dst$$XMMRegister, $a$$XMMRegister, $b$$Address, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_uminmaxq_reg(vec dst, vec a, vec b, vec xtmp1, vec xtmp2) %{ + predicate(!VM_Version::supports_avx512vl() && Matcher::vector_element_basic_type(n) == T_LONG); + match(Set dst (UMinV a b)); + match(Set dst (UMaxV a b)); + effect(TEMP xtmp1, TEMP xtmp2); + format %{ "vector_uminmaxq $dst,$a,$b\t! using xtmp1 and xtmp2 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen_enc = vector_length_encoding(this); + __ vpuminmaxq(opcode, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_uminmax_reg_masked(vec dst, vec src2, kReg mask) %{ + match(Set dst (UMinV (Binary dst src2) mask)); + match(Set dst (UMaxV (Binary dst src2) mask)); + format %{ "vector_uminmax_masked $dst, $dst, $src2, $mask\t! umin/max masked operation" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType bt = Matcher::vector_element_basic_type(this); + int opc = this->ideal_Opcode(); + __ evmasked_op(opc, bt, $mask$$KRegister, $dst$$XMMRegister, + $dst$$XMMRegister, $src2$$XMMRegister, true, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_uminmax_mem_masked(vec dst, memory src2, kReg mask) %{ + match(Set dst (UMinV (Binary dst (LoadVector src2)) mask)); + match(Set dst (UMaxV (Binary dst (LoadVector src2)) mask)); + format %{ "vector_uminmax_masked $dst, $dst, $src2, $mask\t! umin/max masked operation" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType bt = Matcher::vector_element_basic_type(this); + int opc = this->ideal_Opcode(); + __ evmasked_op(opc, bt, $mask$$KRegister, $dst$$XMMRegister, + $dst$$XMMRegister, $src2$$Address, true, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + // --------------------------------- Signum/CopySign --------------------------- instruct signumF_reg(regF dst, regF zero, regF one, rFlagsReg cr) %{ @@ -10468,3 +10583,246 @@ instruct DoubleClassCheck_reg_reg_vfpclass(rRegI dst, regD src, kReg ktmp, rFlag %} ins_pipe(pipe_slow); %} + +instruct vector_addsub_saturating_subword_reg(vec dst, vec src1, vec src2) +%{ + predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && !n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingAddV src1 src2)); + match(Set dst (SaturatingSubV src1 src2)); + format %{ "vector_addsub_saturating_subword $dst, $src1, $src2" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vector_saturating_op(this->ideal_Opcode(), elem_bt, $dst$$XMMRegister, + $src1$$XMMRegister, $src2$$XMMRegister, false, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_addsub_saturating_unsigned_subword_reg(vec dst, vec src1, vec src2) +%{ + predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingAddV src1 src2)); + match(Set dst (SaturatingSubV src1 src2)); + format %{ "vector_addsub_saturating_unsigned_subword $dst, $src1, $src2" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vector_saturating_op(this->ideal_Opcode(), elem_bt, $dst$$XMMRegister, + $src1$$XMMRegister, $src2$$XMMRegister, true, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_addsub_saturating_reg_evex(vec dst, vec src1, vec src2, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2) +%{ + predicate(!is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && !n->as_SaturatingVector()->is_unsigned() && + (Matcher::vector_length_in_bytes(n) == 64 || VM_Version::supports_avx512vl())); + match(Set dst (SaturatingAddV src1 src2)); + match(Set dst (SaturatingSubV src1 src2)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2); + format %{ "vector_addsub_saturating_evex $dst, $src1, $src2 \t! using $xtmp1, $xtmp2, $ktmp1 and $ktmp2 as TEMP" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vector_addsub_dq_saturating_evex(this->ideal_Opcode(), elem_bt, $dst$$XMMRegister, + $src1$$XMMRegister, $src2$$XMMRegister, + $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, + $ktmp1$$KRegister, $ktmp2$$KRegister, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_addsub_saturating_reg_avx(vec dst, vec src1, vec src2, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4) +%{ + predicate(!is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && !n->as_SaturatingVector()->is_unsigned() && + Matcher::vector_length_in_bytes(n) <= 32 && !VM_Version::supports_avx512vl()); + match(Set dst (SaturatingAddV src1 src2)); + match(Set dst (SaturatingSubV src1 src2)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4); + format %{ "vector_addsub_saturating_avx $dst, $src1, $src2 \t! using $xtmp1, $xtmp2, $xtmp3 and $xtmp4 as TEMP" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vector_addsub_dq_saturating_avx(this->ideal_Opcode(), elem_bt, $dst$$XMMRegister, $src1$$XMMRegister, + $src2$$XMMRegister, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, + $xtmp3$$XMMRegister, $xtmp4$$XMMRegister, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_add_saturating_unsigned_reg_evex(vec dst, vec src1, vec src2, vec xtmp1, vec xtmp2, kReg ktmp) +%{ + predicate(!is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned() && + (Matcher::vector_length_in_bytes(n) == 64 || VM_Version::supports_avx512vl())); + match(Set dst (SaturatingAddV src1 src2)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp); + format %{ "vector_add_saturating_unsigned_evex $dst, $src1, $src2 \t! using $xtmp1, $xtmp2 and $ktmp as TEMP" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vector_add_dq_saturating_unsigned_evex(elem_bt, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, + $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, $ktmp$$KRegister, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_add_saturating_unsigned_reg_avx(vec dst, vec src1, vec src2, vec xtmp1, vec xtmp2, vec xtmp3) +%{ + predicate(!is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned() && + Matcher::vector_length_in_bytes(n) <= 32 && !VM_Version::supports_avx512vl()); + match(Set dst (SaturatingAddV src1 src2)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3); + format %{ "vector_add_saturating_unsigned_avx $dst, $src1, $src2 \t! using $xtmp1, $xtmp2 and $xtmp3 as TEMP" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vector_add_dq_saturating_unsigned_avx(elem_bt, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, + $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, $xtmp3$$XMMRegister, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_sub_saturating_unsigned_reg_evex(vec dst, vec src1, vec src2, kReg ktmp) +%{ + predicate(!is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned() && + (Matcher::vector_length_in_bytes(n) == 64 || VM_Version::supports_avx512vl())); + match(Set dst (SaturatingSubV src1 src2)); + effect(TEMP ktmp); + format %{ "vector_sub_saturating_unsigned_evex $dst, $src1, $src2 \t! using $ktmp as TEMP" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vector_sub_dq_saturating_unsigned_evex(elem_bt, $dst$$XMMRegister, $src1$$XMMRegister, + $src2$$XMMRegister, $ktmp$$KRegister, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_sub_saturating_unsigned_reg_avx(vec dst, vec src1, vec src2, vec xtmp1, vec xtmp2) +%{ + predicate(!is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned() && + Matcher::vector_length_in_bytes(n) <= 32 && !VM_Version::supports_avx512vl()); + match(Set dst (SaturatingSubV src1 src2)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2); + format %{ "vector_sub_saturating_unsigned_avx $dst, $src1, $src2 \t! using $xtmp1 and $xtmp2 as TEMP" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vector_sub_dq_saturating_unsigned_avx(elem_bt, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, + $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_addsub_saturating_subword_mem(vec dst, vec src1, memory src2) +%{ + predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && !n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingAddV src1 (LoadVector src2))); + match(Set dst (SaturatingSubV src1 (LoadVector src2))); + format %{ "vector_addsub_saturating_subword $dst, $src1, $src2" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vector_saturating_op(this->ideal_Opcode(), elem_bt, $dst$$XMMRegister, + $src1$$XMMRegister, $src2$$Address, false, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_addsub_saturating_unsigned_subword_mem(vec dst, vec src1, memory src2) +%{ + predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingAddV src1 (LoadVector src2))); + match(Set dst (SaturatingSubV src1 (LoadVector src2))); + format %{ "vector_addsub_saturating_unsigned_subword $dst, $src1, $src2" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vector_saturating_op(this->ideal_Opcode(), elem_bt, $dst$$XMMRegister, + $src1$$XMMRegister, $src2$$Address, true, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_addsub_saturating_subword_masked_reg(vec dst, vec src, kReg mask) %{ + predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && !n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingAddV (Binary dst src) mask)); + match(Set dst (SaturatingSubV (Binary dst src) mask)); + format %{ "vector_addsub_saturating_subword_masked $dst, $mask, $src" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ evmasked_saturating_op(this->ideal_Opcode(), elem_bt, $mask$$KRegister, $dst$$XMMRegister, + $dst$$XMMRegister, $src$$XMMRegister, false, true, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_addsub_saturating_unsigned_subword_masked_reg(vec dst, vec src, kReg mask) %{ + predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingAddV (Binary dst src) mask)); + match(Set dst (SaturatingSubV (Binary dst src) mask)); + format %{ "vector_addsub_saturating_unsigned_subword_masked $dst, $mask, $src" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ evmasked_saturating_op(this->ideal_Opcode(), elem_bt, $mask$$KRegister, $dst$$XMMRegister, + $dst$$XMMRegister, $src$$XMMRegister, true, true, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_addsub_saturating_subword_masked_mem(vec dst, memory src, kReg mask) %{ + predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && !n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingAddV (Binary dst (LoadVector src)) mask)); + match(Set dst (SaturatingSubV (Binary dst (LoadVector src)) mask)); + format %{ "vector_addsub_saturating_subword_masked $dst, $mask, $src" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ evmasked_saturating_op(this->ideal_Opcode(), elem_bt, $mask$$KRegister, $dst$$XMMRegister, + $dst$$XMMRegister, $src$$Address, false, true, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_addsub_saturating_unsigned_subword_masked_mem(vec dst, memory src, kReg mask) %{ + predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && + n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingAddV (Binary dst (LoadVector src)) mask)); + match(Set dst (SaturatingSubV (Binary dst (LoadVector src)) mask)); + format %{ "vector_addsub_saturating_unsigned_subword_masked $dst, $mask, $src" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ evmasked_saturating_op(this->ideal_Opcode(), elem_bt, $mask$$KRegister, $dst$$XMMRegister, + $dst$$XMMRegister, $src$$Address, true, true, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_selectfrom_twovectors_reg_evex(vec index, vec src1, vec src2) +%{ + match(Set index (SelectFromTwoVector (Binary index src1) src2)); + format %{ "select_from_two_vector $index, $src1, $src2 \t!" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType bt = Matcher::vector_element_basic_type(this); + __ select_from_two_vectors_evex(bt, $index$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vlen_enc); + %} + ins_pipe(pipe_slow); +%} diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index 7aa4f6a29a116..7c9695571daec 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -6322,17 +6322,6 @@ instruct storeImmB(memory mem, immI8 src) %{ ins_pipe( ialu_mem_imm ); %} -// Store CMS card-mark Immediate -instruct storeImmCM(memory mem, immI8 src) %{ - match(Set mem (StoreCM mem src)); - - ins_cost(150); - format %{ "MOV8 $mem,$src\t! CMS card-mark imm0" %} - opcode(0xC6); /* C6 /0 */ - ins_encode( SetInstMark, OpcP, RMopc_Mem(0x00,mem), Con8or32(src), ClearInstMark); - ins_pipe( ialu_mem_imm ); -%} - // Store Double instruct storeDPR( memory mem, regDPR1 src) %{ predicate(UseSSE<=1); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 1b271683bd60d..c3fa4c16e553f 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -4341,6 +4341,7 @@ instruct loadP(rRegP dst, memory mem) // Load Compressed Pointer instruct loadN(rRegN dst, memory mem) %{ + predicate(n->as_Load()->barrier_data() == 0); match(Set dst (LoadN mem)); ins_cost(125); // XXX @@ -5126,6 +5127,7 @@ instruct storeImmP(memory mem, immP31 src) // Store Compressed Pointer instruct storeN(memory mem, rRegN src) %{ + predicate(n->as_Store()->barrier_data() == 0); match(Set mem (StoreN mem src)); ins_cost(125); // XXX @@ -5150,7 +5152,7 @@ instruct storeNKlass(memory mem, rRegN src) instruct storeImmN0(memory mem, immN0 zero) %{ - predicate(CompressedOops::base() == nullptr); + predicate(CompressedOops::base() == nullptr && n->as_Store()->barrier_data() == 0); match(Set mem (StoreN mem zero)); ins_cost(125); // XXX @@ -5163,6 +5165,7 @@ instruct storeImmN0(memory mem, immN0 zero) instruct storeImmN(memory mem, immN src) %{ + predicate(n->as_Store()->barrier_data() == 0); match(Set mem (StoreN mem src)); ins_cost(150); // XXX @@ -5295,32 +5298,6 @@ instruct storeImmB(memory mem, immI8 src) ins_pipe(ialu_mem_imm); %} -// Store CMS card-mark Immediate -instruct storeImmCM0_reg(memory mem, immI_0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); - match(Set mem (StoreCM mem zero)); - - ins_cost(125); // XXX - format %{ "movb $mem, R12\t# CMS card-mark byte 0 (R12_heapbase==0)" %} - ins_encode %{ - __ movb($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeImmCM0(memory mem, immI_0 src) -%{ - match(Set mem (StoreCM mem src)); - - ins_cost(150); // XXX - format %{ "movb $mem, $src\t# CMS card-mark byte 0" %} - ins_encode %{ - __ movb($mem$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - // Store Float instruct storeF(memory mem, regF src) %{ @@ -7162,6 +7139,7 @@ instruct compareAndSwapN(rRegI res, memory mem_ptr, rax_RegN oldval, rRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); @@ -7249,6 +7227,7 @@ instruct compareAndExchangeN( memory mem_ptr, rax_RegN oldval, rRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set oldval (CompareAndExchangeN mem_ptr (Binary oldval newval))); effect(KILL cr); @@ -7470,6 +7449,7 @@ instruct xchgP( memory mem, rRegP newval) %{ %} instruct xchgN( memory mem, rRegN newval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set newval (GetAndSetN mem newval)); format %{ "XCHGL $newval,$mem]" %} ins_encode %{ @@ -11659,6 +11639,7 @@ instruct compN_rReg(rFlagsRegU cr, rRegN op1, rRegN op2) instruct compN_rReg_mem(rFlagsRegU cr, rRegN src, memory mem) %{ + predicate(n->in(2)->as_Load()->barrier_data() == 0); match(Set cr (CmpN src (LoadN mem))); format %{ "cmpl $src, $mem\t# compressed ptr" %} @@ -11680,6 +11661,7 @@ instruct compN_rReg_imm(rFlagsRegU cr, rRegN op1, immN op2) %{ instruct compN_mem_imm(rFlagsRegU cr, memory mem, immN src) %{ + predicate(n->in(2)->as_Load()->barrier_data() == 0); match(Set cr (CmpN src (LoadN mem))); format %{ "cmpl $mem, $src\t# compressed ptr" %} @@ -11720,7 +11702,8 @@ instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{ instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) %{ - predicate(CompressedOops::base() != nullptr); + predicate(CompressedOops::base() != nullptr && + n->in(1)->as_Load()->barrier_data() == 0); match(Set cr (CmpN (LoadN mem) zero)); ins_cost(500); // XXX @@ -11733,7 +11716,8 @@ instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) instruct testN_mem_reg0(rFlagsReg cr, memory mem, immN0 zero) %{ - predicate(CompressedOops::base() == nullptr); + predicate(CompressedOops::base() == nullptr && + n->in(1)->as_Load()->barrier_data() == 0); match(Set cr (CmpN (LoadN mem) zero)); format %{ "cmpl R12, $mem\t# compressed ptr (R12_heapbase==0)" %} diff --git a/src/hotspot/cpu/zero/upcallLinker_zero.cpp b/src/hotspot/cpu/zero/upcallLinker_zero.cpp index 6447dac86c915..408ebc328205d 100644 --- a/src/hotspot/cpu/zero/upcallLinker_zero.cpp +++ b/src/hotspot/cpu/zero/upcallLinker_zero.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "prims/upcallLinker.hpp" -address UpcallLinker::make_upcall_stub(jobject mh, Method* entry, +address UpcallLinker::make_upcall_stub(jobject mh, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp index 1fcf4b1086253..7312dd116468c 100644 --- a/src/hotspot/cpu/zero/vm_version_zero.cpp +++ b/src/hotspot/cpu/zero/vm_version_zero.cpp @@ -116,11 +116,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); } - if ((LockingMode != LM_LEGACY) && (LockingMode != LM_MONITOR)) { - warning("Unsupported locking mode for this CPU."); - FLAG_SET_DEFAULT(LockingMode, LM_LEGACY); - } - // Enable error context decoding on known platforms #if defined(IA32) || defined(AMD64) || defined(ARM) || \ defined(AARCH64) || defined(PPC) || defined(RISCV) || \ diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index 2b53042ef1017..aab43e733964e 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -485,26 +485,30 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { // Unlock if necessary if (monitor) { - BasicLock *lock = monitor->lock(); - markWord header = lock->displaced_header(); - oop rcvr = monitor->obj(); - monitor->set_obj(nullptr); - - bool dec_monitor_count = true; - if (header.to_pointer() != nullptr) { - markWord old_header = markWord::encode(lock); - if (rcvr->cas_set_mark(header, old_header) != old_header) { - monitor->set_obj(rcvr); - dec_monitor_count = false; - InterpreterRuntime::monitorexit(monitor); + bool success = false; + if (LockingMode == LM_LEGACY) { + BasicLock* lock = monitor->lock(); + oop rcvr = monitor->obj(); + monitor->set_obj(nullptr); + success = true; + markWord header = lock->displaced_header(); + if (header.to_pointer() != nullptr) { // Check for recursive lock + markWord old_header = markWord::encode(lock); + if (rcvr->cas_set_mark(header, old_header) != old_header) { + monitor->set_obj(rcvr); + success = false; + } + } + if (success) { + THREAD->dec_held_monitor_count(); } } - if (dec_monitor_count) { - THREAD->dec_held_monitor_count(); + if (!success) { + InterpreterRuntime::monitorexit(monitor); } } - unwind_and_return: + unwind_and_return: // Unwind the current activation thread->pop_zero_frame(); diff --git a/src/hotspot/os/aix/osThread_aix.cpp b/src/hotspot/os/aix/osThread_aix.cpp index 4049d6b58b777..c424b044c09b9 100644 --- a/src/hotspot/os/aix/osThread_aix.cpp +++ b/src/hotspot/os/aix/osThread_aix.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. * Copyright (c) 2012, 2015 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -23,32 +23,26 @@ * */ -// no precompiled headers - -#include "memory/allocation.inline.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/os.hpp" +#include "precompiled.hpp" +#include "memory/allocation.hpp" +#include "runtime/mutex.hpp" #include "runtime/osThread.hpp" -#include "runtime/safepoint.hpp" -#include "runtime/vmThread.hpp" - -void OSThread::pd_initialize() { - _thread_id = 0; - _kernel_thread_id = 0; - _siginfo = nullptr; - _ucontext = nullptr; - _expanding_stack = 0; - _alt_sig_stack = nullptr; - _last_cpu_times.sys = _last_cpu_times.user = 0L; +#include +OSThread::OSThread() + : _thread_id(0), + _kernel_thread_id(0), + _caller_sigmask(), + sr(), + _siginfo(nullptr), + _ucontext(nullptr), + _expanding_stack(0), + _alt_sig_stack(nullptr), + _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) { sigemptyset(&_caller_sigmask); - - _startThread_lock = new Monitor(Mutex::event, "startThread_lock"); - assert(_startThread_lock != nullptr, "check"); } -void OSThread::pd_destroy() { +OSThread::~OSThread() { delete _startThread_lock; } diff --git a/src/hotspot/os/aix/osThread_aix.hpp b/src/hotspot/os/aix/osThread_aix.hpp index 5feb3c5799aa0..514e554101e88 100644 --- a/src/hotspot/os/aix/osThread_aix.hpp +++ b/src/hotspot/os/aix/osThread_aix.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,22 +26,16 @@ #ifndef OS_AIX_OSTHREAD_AIX_HPP #define OS_AIX_OSTHREAD_AIX_HPP - public: - typedef pthread_t thread_id_t; - - private: - int _thread_type; +#include "runtime/osThreadBase.hpp" +#include "suspendResume_posix.hpp" +#include "utilities/globalDefinitions.hpp" - public: +class OSThread : public OSThreadBase { + friend class VMStructs; - int thread_type() const { - return _thread_type; - } - void set_thread_type(int type) { - _thread_type = type; - } + typedef pthread_t thread_id_t; - private: + thread_id_t _thread_id; // On AIX, we use the pthread id as OSThread::thread_id and keep the kernel thread id // separately for diagnostic purposes. @@ -54,15 +48,20 @@ sigset_t _caller_sigmask; // Caller's signal mask public: + OSThread(); + ~OSThread(); // Methods to save/restore caller's signal mask sigset_t caller_sigmask() const { return _caller_sigmask; } void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; } -#ifndef PRODUCT - // Used for debugging, return a unique integer for each thread. - int thread_identifier() const { return _thread_id; } -#endif + thread_id_t thread_id() const { + return _thread_id; + } + void set_thread_id(thread_id_t id) { + _thread_id = id; + } + tid_t kernel_thread_id() const { return _kernel_thread_id; } @@ -71,7 +70,7 @@ } pthread_t pthread_id() const { - // Here: same as OSThread::thread_id() + // Here: same as thread_id() return _thread_id; } @@ -79,7 +78,6 @@ // suspension support. // *************************************************************** - public: // flags that support signal based suspend/resume on Aix are in a // separate class to avoid confusion with many flags in OSThread that // are used by VM level suspend/resume. @@ -125,22 +123,10 @@ return _startThread_lock; } - // *************************************************************** - // Platform dependent initialization and cleanup - // *************************************************************** - - private: - - void pd_initialize(); - void pd_destroy(); - - public: - - // The last measured values of cpu timing to prevent the "stale - // value return" bug in thread_cpu_time. - volatile struct { - jlong sys; - jlong user; - } _last_cpu_times; + // Printing + uintx thread_id_for_printing() const override { + return (uintx)_thread_id; + } +}; #endif // OS_AIX_OSTHREAD_AIX_HPP diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index fd16a7984a6f3..842ab0c6eebd6 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -698,9 +698,6 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, return false; } - // Set the correct thread state. - osthread->set_thread_type(thr_type); - // Initial state is ALLOCATED but not INITIALIZED osthread->set_state(ALLOCATED); @@ -1293,7 +1290,7 @@ void os::jvm_path(char *buf, jint buflen) { Dl_info dlinfo; int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo); assert(ret != 0, "cannot locate libjvm"); - char* rp = os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen); + char* rp = os::realpath((char *)dlinfo.dli_fname, buf, buflen); assert(rp != nullptr, "error in realpath(): maybe the 'path' argument is too long?"); if (Arguments::sun_java_launcher_is_altjvm()) { @@ -1324,7 +1321,7 @@ void os::jvm_path(char *buf, jint buflen) { } assert(strstr(p, "/libjvm") == p, "invalid library name"); - rp = os::Posix::realpath(java_home_var, buf, buflen); + rp = os::realpath(java_home_var, buf, buflen); if (rp == nullptr) { return; } @@ -1345,7 +1342,7 @@ void os::jvm_path(char *buf, jint buflen) { snprintf(buf + len, buflen-len, "/hotspot/libjvm.so"); } else { // Go back to path of .so - rp = os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen); + rp = os::realpath((char *)dlinfo.dli_fname, buf, buflen); if (rp == nullptr) { return; } @@ -2483,16 +2480,6 @@ int os::open(const char *path, int oflag, int mode) { return fd; } -// return current position of file pointer -jlong os::current_file_offset(int fd) { - return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); -} - -// move file pointer to the specified offset -jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); -} - // current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) // are used by JVM M&M and JVMTI to get user+sys or user CPU time // of a thread. diff --git a/src/hotspot/os/aix/vmStructs_aix.hpp b/src/hotspot/os/aix/vmStructs_aix.hpp index 1a2f4c4bf6e21..f3bbc80e62c72 100644 --- a/src/hotspot/os/aix/vmStructs_aix.hpp +++ b/src/hotspot/os/aix/vmStructs_aix.hpp @@ -29,9 +29,20 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + \ + /******************************/ \ + /* Threads (NOTE: incomplete) */ \ + /******************************/ \ + nonstatic_field(OSThread, _thread_id, pthread_t) \ + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + \ + /**********************/ \ + /* Posix Thread IDs */ \ + /**********************/ \ + \ + declare_unsigned_integer_type(pthread_t) #define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os/bsd/gc/x/xPhysicalMemoryBacking_bsd.cpp b/src/hotspot/os/bsd/gc/x/xPhysicalMemoryBacking_bsd.cpp deleted file mode 100644 index 2c64c3788d34d..0000000000000 --- a/src/hotspot/os/bsd/gc/x/xPhysicalMemoryBacking_bsd.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2019, 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. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xErrno.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xLargePages.inline.hpp" -#include "gc/x/xPhysicalMemory.inline.hpp" -#include "gc/x/xPhysicalMemoryBacking_bsd.hpp" -#include "logging/log.hpp" -#include "runtime/globals.hpp" -#include "runtime/os.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" - -#include -#include -#include -#include - -// The backing is represented by a reserved virtual address space, in which -// we commit and uncommit physical memory. Multi-mapping the different heap -// views is done by simply remapping the backing memory using mach_vm_remap(). - -static int vm_flags_superpage() { - if (!XLargePages::is_explicit()) { - return 0; - } - - const int page_size_in_megabytes = XGranuleSize >> 20; - return page_size_in_megabytes << VM_FLAGS_SUPERPAGE_SHIFT; -} - -static XErrno mremap(uintptr_t from_addr, uintptr_t to_addr, size_t size) { - mach_vm_address_t remap_addr = to_addr; - vm_prot_t remap_cur_prot; - vm_prot_t remap_max_prot; - - // Remap memory to an additional location - const kern_return_t res = mach_vm_remap(mach_task_self(), - &remap_addr, - size, - 0 /* mask */, - VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE | vm_flags_superpage(), - mach_task_self(), - from_addr, - FALSE /* copy */, - &remap_cur_prot, - &remap_max_prot, - VM_INHERIT_COPY); - - return (res == KERN_SUCCESS) ? XErrno(0) : XErrno(EINVAL); -} - -XPhysicalMemoryBacking::XPhysicalMemoryBacking(size_t max_capacity) : - _base(0), - _initialized(false) { - - // Reserve address space for backing memory - _base = (uintptr_t)os::reserve_memory(max_capacity); - if (_base == 0) { - // Failed - log_error_pd(gc)("Failed to reserve address space for backing memory"); - return; - } - - // Successfully initialized - _initialized = true; -} - -bool XPhysicalMemoryBacking::is_initialized() const { - return _initialized; -} - -void XPhysicalMemoryBacking::warn_commit_limits(size_t max_capacity) const { - // Does nothing -} - -bool XPhysicalMemoryBacking::commit_inner(size_t offset, size_t length) const { - assert(is_aligned(offset, os::vm_page_size()), "Invalid offset"); - assert(is_aligned(length, os::vm_page_size()), "Invalid length"); - - log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", - offset / M, (offset + length) / M, length / M); - - const uintptr_t addr = _base + offset; - const void* const res = mmap((void*)addr, length, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (res == MAP_FAILED) { - XErrno err; - log_error(gc)("Failed to commit memory (%s)", err.to_string()); - return false; - } - - // Success - return true; -} - -size_t XPhysicalMemoryBacking::commit(size_t offset, size_t length) const { - // Try to commit the whole region - if (commit_inner(offset, length)) { - // Success - return length; - } - - // Failed, try to commit as much as possible - size_t start = offset; - size_t end = offset + length; - - for (;;) { - length = align_down((end - start) / 2, XGranuleSize); - if (length == 0) { - // Done, don't commit more - return start - offset; - } - - if (commit_inner(start, length)) { - // Success, try commit more - start += length; - } else { - // Failed, try commit less - end -= length; - } - } -} - -size_t XPhysicalMemoryBacking::uncommit(size_t offset, size_t length) const { - assert(is_aligned(offset, os::vm_page_size()), "Invalid offset"); - assert(is_aligned(length, os::vm_page_size()), "Invalid length"); - - log_trace(gc, heap)("Uncommitting memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", - offset / M, (offset + length) / M, length / M); - - const uintptr_t start = _base + offset; - const void* const res = mmap((void*)start, length, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); - if (res == MAP_FAILED) { - XErrno err; - log_error(gc)("Failed to uncommit memory (%s)", err.to_string()); - return 0; - } - - return length; -} - -void XPhysicalMemoryBacking::map(uintptr_t addr, size_t size, uintptr_t offset) const { - const XErrno err = mremap(_base + offset, addr, size); - if (err) { - fatal("Failed to remap memory (%s)", err.to_string()); - } -} - -void XPhysicalMemoryBacking::unmap(uintptr_t addr, size_t size) const { - // Note that we must keep the address space reservation intact and just detach - // the backing memory. For this reason we map a new anonymous, non-accessible - // and non-reserved page over the mapping instead of actually unmapping. - const void* const res = mmap((void*)addr, size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); - if (res == MAP_FAILED) { - XErrno err; - fatal("Failed to map memory (%s)", err.to_string()); - } -} diff --git a/src/hotspot/os/bsd/gc/x/xPhysicalMemoryBacking_bsd.hpp b/src/hotspot/os/bsd/gc/x/xPhysicalMemoryBacking_bsd.hpp deleted file mode 100644 index 8b4747026ff23..0000000000000 --- a/src/hotspot/os/bsd/gc/x/xPhysicalMemoryBacking_bsd.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef OS_BSD_GC_X_XPHYSICALMEMORYBACKING_BSD_HPP -#define OS_BSD_GC_X_XPHYSICALMEMORYBACKING_BSD_HPP - -class XPhysicalMemoryBacking { -private: - uintptr_t _base; - bool _initialized; - - bool commit_inner(size_t offset, size_t length) const; - -public: - XPhysicalMemoryBacking(size_t max_capacity); - - bool is_initialized() const; - - void warn_commit_limits(size_t max_capacity) const; - - size_t commit(size_t offset, size_t length) const; - size_t uncommit(size_t offset, size_t length) const; - - void map(uintptr_t addr, size_t size, uintptr_t offset) const; - void unmap(uintptr_t addr, size_t size) const; -}; - -#endif // OS_BSD_GC_X_XPHYSICALMEMORYBACKING_BSD_HPP diff --git a/src/hotspot/os/bsd/osThread_bsd.cpp b/src/hotspot/os/bsd/osThread_bsd.cpp index 7b9ad1f76a855..d9624040bc740 100644 --- a/src/hotspot/os/bsd/osThread_bsd.cpp +++ b/src/hotspot/os/bsd/osThread_bsd.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 @@ -22,30 +22,31 @@ * */ -// no precompiled headers -#include "memory/allocation.inline.hpp" -#include "runtime/mutexLocker.hpp" +#include "precompiled.hpp" +#include "memory/allocation.hpp" +#include "runtime/mutex.hpp" #include "runtime/osThread.hpp" #include -void OSThread::pd_initialize() { +OSThread::OSThread() + : _thread_id( #ifdef __APPLE__ - _thread_id = 0; + 0 #else - _thread_id = nullptr; + nullptr #endif - _unique_thread_id = 0; - _pthread_id = nullptr; - _siginfo = nullptr; - _ucontext = nullptr; - _expanding_stack = 0; - _alt_sig_stack = nullptr; - + ), + _pthread_id(nullptr), + _unique_thread_id(0), + _caller_sigmask(), + sr(), + _siginfo(nullptr), + _ucontext(nullptr), + _expanding_stack(0), + _alt_sig_stack(nullptr), + _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) { sigemptyset(&_caller_sigmask); - - _startThread_lock = new Monitor(Mutex::event, "startThread_lock"); - assert(_startThread_lock !=nullptr, "check"); } // Additional thread_id used to correlate threads in SA @@ -64,6 +65,6 @@ void OSThread::set_unique_thread_id() { #endif } -void OSThread::pd_destroy() { +OSThread::~OSThread() { delete _startThread_lock; } diff --git a/src/hotspot/os/bsd/osThread_bsd.hpp b/src/hotspot/os/bsd/osThread_bsd.hpp index 11376835063c4..21bec3f3836e2 100644 --- a/src/hotspot/os/bsd/osThread_bsd.hpp +++ b/src/hotspot/os/bsd/osThread_bsd.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, 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 @@ -25,19 +25,12 @@ #ifndef OS_BSD_OSTHREAD_BSD_HPP #define OS_BSD_OSTHREAD_BSD_HPP - private: - int _thread_type; +#include "runtime/osThreadBase.hpp" +#include "suspendResume_posix.hpp" +#include "utilities/globalDefinitions.hpp" - public: - - int thread_type() const { - return _thread_type; - } - void set_thread_type(int type) { - _thread_type = type; - } - - private: +class OSThread : public OSThreadBase { + friend class VMStructs; #ifdef __APPLE__ typedef thread_t thread_id_t; @@ -45,6 +38,8 @@ typedef pid_t thread_id_t; #endif + thread_id_t _thread_id; + // _pthread_id is the pthread id, which is used by library calls // (e.g. pthread_kill). pthread_t _pthread_id; @@ -57,15 +52,19 @@ sigset_t _caller_sigmask; // Caller's signal mask public: + OSThread(); + ~OSThread(); // Methods to save/restore caller's signal mask sigset_t caller_sigmask() const { return _caller_sigmask; } void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; } -#ifndef PRODUCT - // Used for debugging, return a unique integer for each thread. - intptr_t thread_identifier() const { return (intptr_t)_pthread_id; } -#endif + thread_id_t thread_id() const { + return _thread_id; + } + void set_thread_id(thread_id_t id) { + _thread_id = id; + } pthread_t pthread_id() const { return _pthread_id; @@ -80,7 +79,6 @@ // suspension support. // *************************************************************** -public: // flags that support signal based suspend/resume on Bsd are in a // separate class to avoid confusion with many flags in OSThread that // are used by VM level suspend/resume. @@ -126,17 +124,9 @@ return _startThread_lock; } - // *************************************************************** - // Platform dependent initialization and cleanup - // *************************************************************** - -private: - - void pd_initialize(); - void pd_destroy(); - -// Reconciliation History -// osThread_solaris.hpp 1.24 99/08/27 13:11:54 -// End + uintx thread_id_for_printing() const override { + return (uintx)_thread_id; + } +}; #endif // OS_BSD_OSTHREAD_BSD_HPP diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 9ad7c35e6bdef..b50ebf2220390 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -633,9 +633,6 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, return false; } - // set the correct thread state - osthread->set_thread_type(thr_type); - // Initial state is ALLOCATED but not INITIALIZED osthread->set_state(ALLOCATED); @@ -1509,7 +1506,7 @@ void os::jvm_path(char *buf, jint buflen) { assert(ret, "cannot locate libjvm"); char *rp = nullptr; if (ret && dli_fname[0] != '\0') { - rp = os::Posix::realpath(dli_fname, buf, buflen); + rp = os::realpath(dli_fname, buf, buflen); } if (rp == nullptr) { return; @@ -1541,7 +1538,7 @@ void os::jvm_path(char *buf, jint buflen) { p = strrchr(buf, '/'); assert(strstr(p, "/libjvm") == p, "invalid library name"); - rp = os::Posix::realpath(java_home_var, buf, buflen); + rp = os::realpath(java_home_var, buf, buflen); if (rp == nullptr) { return; } @@ -1575,7 +1572,7 @@ void os::jvm_path(char *buf, jint buflen) { snprintf(buf + len, buflen-len, "/libjvm%s", JNI_LIB_SUFFIX); } else { // Fall back to path of current library - rp = os::Posix::realpath(dli_fname, buf, buflen); + rp = os::realpath(dli_fname, buf, buflen); if (rp == nullptr) { return; } @@ -2400,16 +2397,6 @@ int os::open(const char *path, int oflag, int mode) { return fd; } -// return current position of file pointer -jlong os::current_file_offset(int fd) { - return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); -} - -// move file pointer to the specified offset -jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); -} - // current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) // are used by JVM M&M and JVMTI to get user+sys or user CPU time // of a thread. diff --git a/src/hotspot/os/bsd/vmStructs_bsd.hpp b/src/hotspot/os/bsd/vmStructs_bsd.hpp index 84c1be77374d0..8c9c132e1c25c 100644 --- a/src/hotspot/os/bsd/vmStructs_bsd.hpp +++ b/src/hotspot/os/bsd/vmStructs_bsd.hpp @@ -31,9 +31,21 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + \ + /******************************/ \ + /* Threads (NOTE: incomplete) */ \ + /******************************/ \ + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ + nonstatic_field(OSThread, _unique_thread_id, uint64_t) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + \ + /**********************/ \ + /* Thread IDs */ \ + /**********************/ \ + \ + declare_unsigned_integer_type(OSThread::thread_id_t) #define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index 527573644a816..56dcadd670f82 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -64,16 +64,16 @@ class CgroupV2CpuController: public CgroupCpuController { bool is_read_only() override { return reader()->is_read_only(); } - const char* subsystem_path() { + const char* subsystem_path() override { return reader()->subsystem_path(); } bool needs_hierarchy_adjustment() override { return reader()->needs_hierarchy_adjustment(); } - void set_subsystem_path(const char* cgroup_path) { + void set_subsystem_path(const char* cgroup_path) override { reader()->set_subsystem_path(cgroup_path); } - const char* mount_point() { return reader()->mount_point(); } + const char* mount_point() override { return reader()->mount_point(); } const char* cgroup_path() override { return reader()->cgroup_path(); } }; @@ -97,16 +97,16 @@ class CgroupV2MemoryController final: public CgroupMemoryController { bool is_read_only() override { return reader()->is_read_only(); } - const char* subsystem_path() { + const char* subsystem_path() override { return reader()->subsystem_path(); } bool needs_hierarchy_adjustment() override { return reader()->needs_hierarchy_adjustment(); } - void set_subsystem_path(const char* cgroup_path) { + void set_subsystem_path(const char* cgroup_path) override { reader()->set_subsystem_path(cgroup_path); } - const char* mount_point() { return reader()->mount_point(); } + const char* mount_point() override { return reader()->mount_point(); } const char* cgroup_path() override { return reader()->cgroup_path(); } }; diff --git a/src/hotspot/os/linux/gc/x/xMountPoint_linux.cpp b/src/hotspot/os/linux/gc/x/xMountPoint_linux.cpp deleted file mode 100644 index 96c0f2f92dbd2..0000000000000 --- a/src/hotspot/os/linux/gc/x/xMountPoint_linux.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xArray.inline.hpp" -#include "gc/x/xErrno.hpp" -#include "gc/x/xMountPoint_linux.hpp" -#include "runtime/globals.hpp" -#include "runtime/os.hpp" -#include "utilities/globalDefinitions.hpp" - -#include -#include - -// Mount information, see proc(5) for more details. -#define PROC_SELF_MOUNTINFO "/proc/self/mountinfo" - -XMountPoint::XMountPoint(const char* filesystem, const char** preferred_mountpoints) { - if (AllocateHeapAt != nullptr) { - // Use specified path - _path = os::strdup(AllocateHeapAt, mtGC); - } else { - // Find suitable path - _path = find_mountpoint(filesystem, preferred_mountpoints); - } -} - -XMountPoint::~XMountPoint() { - os::free(_path); - _path = nullptr; -} - -char* XMountPoint::get_mountpoint(const char* line, const char* filesystem) const { - char* line_mountpoint = nullptr; - char* line_filesystem = nullptr; - - // Parse line and return a newly allocated string containing the mount point if - // the line contains a matching filesystem and the mount point is accessible by - // the current user. - // sscanf, using %m, will return malloced memory. Need raw ::free, not os::free. - if (sscanf(line, "%*u %*u %*u:%*u %*s %ms %*[^-]- %ms", &line_mountpoint, &line_filesystem) != 2 || - strcmp(line_filesystem, filesystem) != 0 || - access(line_mountpoint, R_OK|W_OK|X_OK) != 0) { - // Not a matching or accessible filesystem - ALLOW_C_FUNCTION(::free, ::free(line_mountpoint);) - line_mountpoint = nullptr; - } - - ALLOW_C_FUNCTION(::free, ::free(line_filesystem);) - - return line_mountpoint; -} - -void XMountPoint::get_mountpoints(const char* filesystem, XArray* mountpoints) const { - FILE* fd = os::fopen(PROC_SELF_MOUNTINFO, "r"); - if (fd == nullptr) { - XErrno err; - log_error_p(gc)("Failed to open %s: %s", PROC_SELF_MOUNTINFO, err.to_string()); - return; - } - - char* line = nullptr; - size_t length = 0; - - while (getline(&line, &length, fd) != -1) { - char* const mountpoint = get_mountpoint(line, filesystem); - if (mountpoint != nullptr) { - mountpoints->append(mountpoint); - } - } - - // readline will return malloced memory. Need raw ::free, not os::free. - ALLOW_C_FUNCTION(::free, ::free(line);) - fclose(fd); -} - -void XMountPoint::free_mountpoints(XArray* mountpoints) const { - XArrayIterator iter(mountpoints); - for (char* mountpoint; iter.next(&mountpoint);) { - ALLOW_C_FUNCTION(::free, ::free(mountpoint);) // *not* os::free - } - mountpoints->clear(); -} - -char* XMountPoint::find_preferred_mountpoint(const char* filesystem, - XArray* mountpoints, - const char** preferred_mountpoints) const { - // Find preferred mount point - XArrayIterator iter1(mountpoints); - for (char* mountpoint; iter1.next(&mountpoint);) { - for (const char** preferred = preferred_mountpoints; *preferred != nullptr; preferred++) { - if (!strcmp(mountpoint, *preferred)) { - // Preferred mount point found - return os::strdup(mountpoint, mtGC); - } - } - } - - // Preferred mount point not found - log_error_p(gc)("More than one %s filesystem found:", filesystem); - XArrayIterator iter2(mountpoints); - for (char* mountpoint; iter2.next(&mountpoint);) { - log_error_p(gc)(" %s", mountpoint); - } - - return nullptr; -} - -char* XMountPoint::find_mountpoint(const char* filesystem, const char** preferred_mountpoints) const { - char* path = nullptr; - XArray mountpoints; - - get_mountpoints(filesystem, &mountpoints); - - if (mountpoints.length() == 0) { - // No mount point found - log_error_p(gc)("Failed to find an accessible %s filesystem", filesystem); - } else if (mountpoints.length() == 1) { - // One mount point found - path = os::strdup(mountpoints.at(0), mtGC); - } else { - // More than one mount point found - path = find_preferred_mountpoint(filesystem, &mountpoints, preferred_mountpoints); - } - - free_mountpoints(&mountpoints); - - return path; -} - -const char* XMountPoint::get() const { - return _path; -} diff --git a/src/hotspot/os/linux/gc/x/xMountPoint_linux.hpp b/src/hotspot/os/linux/gc/x/xMountPoint_linux.hpp deleted file mode 100644 index e0ca126e0667a..0000000000000 --- a/src/hotspot/os/linux/gc/x/xMountPoint_linux.hpp +++ /dev/null @@ -1,52 +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. - */ - -#ifndef OS_LINUX_GC_X_XMOUNTPOINT_LINUX_HPP -#define OS_LINUX_GC_X_XMOUNTPOINT_LINUX_HPP - -#include "gc/x/xArray.hpp" -#include "memory/allocation.hpp" - -class XMountPoint : public StackObj { -private: - char* _path; - - char* get_mountpoint(const char* line, - const char* filesystem) const; - void get_mountpoints(const char* filesystem, - XArray* mountpoints) const; - void free_mountpoints(XArray* mountpoints) const; - char* find_preferred_mountpoint(const char* filesystem, - XArray* mountpoints, - const char** preferred_mountpoints) const; - char* find_mountpoint(const char* filesystem, - const char** preferred_mountpoints) const; - -public: - XMountPoint(const char* filesystem, const char** preferred_mountpoints); - ~XMountPoint(); - - const char* get() const; -}; - -#endif // OS_LINUX_GC_X_XMOUNTPOINT_LINUX_HPP diff --git a/src/hotspot/os/linux/gc/x/xNUMA_linux.cpp b/src/hotspot/os/linux/gc/x/xNUMA_linux.cpp deleted file mode 100644 index 0cc557dde6e86..0000000000000 --- a/src/hotspot/os/linux/gc/x/xNUMA_linux.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "gc/x/xCPU.inline.hpp" -#include "gc/x/xErrno.hpp" -#include "gc/x/xNUMA.hpp" -#include "gc/x/xSyscall_linux.hpp" -#include "os_linux.hpp" -#include "runtime/globals.hpp" -#include "runtime/os.hpp" -#include "utilities/debug.hpp" - -void XNUMA::pd_initialize() { - _enabled = UseNUMA; -} - -uint32_t XNUMA::count() { - if (!_enabled) { - // NUMA support not enabled - return 1; - } - - return os::Linux::numa_max_node() + 1; -} - -uint32_t XNUMA::id() { - if (!_enabled) { - // NUMA support not enabled - return 0; - } - - return os::Linux::get_node_by_cpu(XCPU::id()); -} - -uint32_t XNUMA::memory_id(uintptr_t addr) { - if (!_enabled) { - // NUMA support not enabled, assume everything belongs to node zero - return 0; - } - - uint32_t id = (uint32_t)-1; - - if (XSyscall::get_mempolicy((int*)&id, nullptr, 0, (void*)addr, MPOL_F_NODE | MPOL_F_ADDR) == -1) { - XErrno err; - fatal("Failed to get NUMA id for memory at " PTR_FORMAT " (%s)", addr, err.to_string()); - } - - assert(id < count(), "Invalid NUMA id"); - - return id; -} diff --git a/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp deleted file mode 100644 index 35625f613d349..0000000000000 --- a/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp +++ /dev/null @@ -1,724 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xArray.inline.hpp" -#include "gc/x/xErrno.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xLargePages.inline.hpp" -#include "gc/x/xMountPoint_linux.hpp" -#include "gc/x/xNUMA.inline.hpp" -#include "gc/x/xPhysicalMemoryBacking_linux.hpp" -#include "gc/x/xSyscall_linux.hpp" -#include "logging/log.hpp" -#include "os_linux.hpp" -#include "runtime/init.hpp" -#include "runtime/os.hpp" -#include "runtime/safefetch.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" -#include "utilities/growableArray.hpp" - -#include -#include -#include -#include -#include -#include -#include - -// -// Support for building on older Linux systems -// - -// memfd_create(2) flags -#ifndef MFD_CLOEXEC -#define MFD_CLOEXEC 0x0001U -#endif -#ifndef MFD_HUGETLB -#define MFD_HUGETLB 0x0004U -#endif -#ifndef MFD_HUGE_2MB -#define MFD_HUGE_2MB 0x54000000U -#endif - -// open(2) flags -#ifndef O_CLOEXEC -#define O_CLOEXEC 02000000 -#endif -#ifndef O_TMPFILE -#define O_TMPFILE (020000000 | O_DIRECTORY) -#endif - -// fallocate(2) flags -#ifndef FALLOC_FL_KEEP_SIZE -#define FALLOC_FL_KEEP_SIZE 0x01 -#endif -#ifndef FALLOC_FL_PUNCH_HOLE -#define FALLOC_FL_PUNCH_HOLE 0x02 -#endif - -// Filesystem types, see statfs(2) -#ifndef TMPFS_MAGIC -#define TMPFS_MAGIC 0x01021994 -#endif -#ifndef HUGETLBFS_MAGIC -#define HUGETLBFS_MAGIC 0x958458f6 -#endif - -// Filesystem names -#define XFILESYSTEM_TMPFS "tmpfs" -#define XFILESYSTEM_HUGETLBFS "hugetlbfs" - -// Proc file entry for max map mount -#define XFILENAME_PROC_MAX_MAP_COUNT "/proc/sys/vm/max_map_count" - -// Sysfs file for transparent huge page on tmpfs -#define XFILENAME_SHMEM_ENABLED "/sys/kernel/mm/transparent_hugepage/shmem_enabled" - -// Java heap filename -#define XFILENAME_HEAP "java_heap" - -// Preferred tmpfs mount points, ordered by priority -static const char* z_preferred_tmpfs_mountpoints[] = { - "/dev/shm", - "/run/shm", - nullptr -}; - -// Preferred hugetlbfs mount points, ordered by priority -static const char* z_preferred_hugetlbfs_mountpoints[] = { - "/dev/hugepages", - "/hugepages", - nullptr -}; - -static int z_fallocate_hugetlbfs_attempts = 3; -static bool z_fallocate_supported = true; - -XPhysicalMemoryBacking::XPhysicalMemoryBacking(size_t max_capacity) : - _fd(-1), - _filesystem(0), - _block_size(0), - _available(0), - _initialized(false) { - - // Create backing file - _fd = create_fd(XFILENAME_HEAP); - if (_fd == -1) { - return; - } - - // Truncate backing file - while (ftruncate(_fd, max_capacity) == -1) { - if (errno != EINTR) { - XErrno err; - log_error_p(gc)("Failed to truncate backing file (%s)", err.to_string()); - return; - } - } - - // Get filesystem statistics - struct statfs buf; - if (fstatfs(_fd, &buf) == -1) { - XErrno err; - log_error_p(gc)("Failed to determine filesystem type for backing file (%s)", err.to_string()); - return; - } - - _filesystem = buf.f_type; - _block_size = buf.f_bsize; - _available = buf.f_bavail * _block_size; - - log_info_p(gc, init)("Heap Backing Filesystem: %s (" UINT64_FORMAT_X ")", - is_tmpfs() ? XFILESYSTEM_TMPFS : is_hugetlbfs() ? XFILESYSTEM_HUGETLBFS : "other", _filesystem); - - // Make sure the filesystem type matches requested large page type - if (XLargePages::is_transparent() && !is_tmpfs()) { - log_error_p(gc)("-XX:+UseTransparentHugePages can only be enabled when using a %s filesystem", - XFILESYSTEM_TMPFS); - return; - } - - if (XLargePages::is_transparent() && !tmpfs_supports_transparent_huge_pages()) { - log_error_p(gc)("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel", - XFILESYSTEM_TMPFS); - return; - } - - if (XLargePages::is_explicit() && !is_hugetlbfs()) { - log_error_p(gc)("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled " - "when using a %s filesystem", XFILESYSTEM_HUGETLBFS); - return; - } - - if (!XLargePages::is_explicit() && is_hugetlbfs()) { - log_error_p(gc)("-XX:+UseLargePages must be enabled when using a %s filesystem", - XFILESYSTEM_HUGETLBFS); - return; - } - - // Make sure the filesystem block size is compatible - if (XGranuleSize % _block_size != 0) { - log_error_p(gc)("Filesystem backing the heap has incompatible block size (" SIZE_FORMAT ")", - _block_size); - return; - } - - if (is_hugetlbfs() && _block_size != XGranuleSize) { - log_error_p(gc)("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")", - XFILESYSTEM_HUGETLBFS, _block_size, XGranuleSize); - return; - } - - // Successfully initialized - _initialized = true; -} - -int XPhysicalMemoryBacking::create_mem_fd(const char* name) const { - assert(XGranuleSize == 2 * M, "Granule size must match MFD_HUGE_2MB"); - - // Create file name - char filename[PATH_MAX]; - snprintf(filename, sizeof(filename), "%s%s", name, XLargePages::is_explicit() ? ".hugetlb" : ""); - - // Create file - const int extra_flags = XLargePages::is_explicit() ? (MFD_HUGETLB | MFD_HUGE_2MB) : 0; - const int fd = XSyscall::memfd_create(filename, MFD_CLOEXEC | extra_flags); - if (fd == -1) { - XErrno err; - log_debug_p(gc, init)("Failed to create memfd file (%s)", - (XLargePages::is_explicit() && (err == EINVAL || err == ENODEV)) ? - "Hugepages (2M) not available" : err.to_string()); - return -1; - } - - log_info_p(gc, init)("Heap Backing File: /memfd:%s", filename); - - return fd; -} - -int XPhysicalMemoryBacking::create_file_fd(const char* name) const { - const char* const filesystem = XLargePages::is_explicit() - ? XFILESYSTEM_HUGETLBFS - : XFILESYSTEM_TMPFS; - const char** const preferred_mountpoints = XLargePages::is_explicit() - ? z_preferred_hugetlbfs_mountpoints - : z_preferred_tmpfs_mountpoints; - - // Find mountpoint - XMountPoint mountpoint(filesystem, preferred_mountpoints); - if (mountpoint.get() == nullptr) { - log_error_p(gc)("Use -XX:AllocateHeapAt to specify the path to a %s filesystem", filesystem); - return -1; - } - - // Try to create an anonymous file using the O_TMPFILE flag. Note that this - // flag requires kernel >= 3.11. If this fails we fall back to open/unlink. - const int fd_anon = os::open(mountpoint.get(), O_TMPFILE|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR); - if (fd_anon == -1) { - XErrno err; - log_debug_p(gc, init)("Failed to create anonymous file in %s (%s)", mountpoint.get(), - (err == EINVAL ? "Not supported" : err.to_string())); - } else { - // Get inode number for anonymous file - struct stat stat_buf; - if (fstat(fd_anon, &stat_buf) == -1) { - XErrno err; - log_error_pd(gc)("Failed to determine inode number for anonymous file (%s)", err.to_string()); - return -1; - } - - log_info_p(gc, init)("Heap Backing File: %s/#" UINT64_FORMAT, mountpoint.get(), (uint64_t)stat_buf.st_ino); - - return fd_anon; - } - - log_debug_p(gc, init)("Falling back to open/unlink"); - - // Create file name - char filename[PATH_MAX]; - snprintf(filename, sizeof(filename), "%s/%s.%d", mountpoint.get(), name, os::current_process_id()); - - // Create file - const int fd = os::open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR); - if (fd == -1) { - XErrno err; - log_error_p(gc)("Failed to create file %s (%s)", filename, err.to_string()); - return -1; - } - - // Unlink file - if (unlink(filename) == -1) { - XErrno err; - log_error_p(gc)("Failed to unlink file %s (%s)", filename, err.to_string()); - return -1; - } - - log_info_p(gc, init)("Heap Backing File: %s", filename); - - return fd; -} - -int XPhysicalMemoryBacking::create_fd(const char* name) const { - if (AllocateHeapAt == nullptr) { - // If the path is not explicitly specified, then we first try to create a memfd file - // instead of looking for a tmpfd/hugetlbfs mount point. Note that memfd_create() might - // not be supported at all (requires kernel >= 3.17), or it might not support large - // pages (requires kernel >= 4.14). If memfd_create() fails, then we try to create a - // file on an accessible tmpfs or hugetlbfs mount point. - const int fd = create_mem_fd(name); - if (fd != -1) { - return fd; - } - - log_debug_p(gc)("Falling back to searching for an accessible mount point"); - } - - return create_file_fd(name); -} - -bool XPhysicalMemoryBacking::is_initialized() const { - return _initialized; -} - -void XPhysicalMemoryBacking::warn_available_space(size_t max_capacity) const { - // Note that the available space on a tmpfs or a hugetlbfs filesystem - // will be zero if no size limit was specified when it was mounted. - if (_available == 0) { - // No size limit set, skip check - log_info_p(gc, init)("Available space on backing filesystem: N/A"); - return; - } - - log_info_p(gc, init)("Available space on backing filesystem: " SIZE_FORMAT "M", _available / M); - - // Warn if the filesystem doesn't currently have enough space available to hold - // the max heap size. The max heap size will be capped if we later hit this limit - // when trying to expand the heap. - if (_available < max_capacity) { - log_warning_p(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****"); - log_warning_p(gc)("Not enough space available on the backing filesystem to hold the current max Java heap"); - log_warning_p(gc)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem accordingly " - "(available", max_capacity / M); - log_warning_p(gc)("space is currently " SIZE_FORMAT "M). Continuing execution with the current filesystem " - "size could", _available / M); - log_warning_p(gc)("lead to a premature OutOfMemoryError being thrown, due to failure to commit memory."); - } -} - -void XPhysicalMemoryBacking::warn_max_map_count(size_t max_capacity) const { - const char* const filename = XFILENAME_PROC_MAX_MAP_COUNT; - FILE* const file = os::fopen(filename, "r"); - if (file == nullptr) { - // Failed to open file, skip check - log_debug_p(gc, init)("Failed to open %s", filename); - return; - } - - size_t actual_max_map_count = 0; - const int result = fscanf(file, SIZE_FORMAT, &actual_max_map_count); - fclose(file); - if (result != 1) { - // Failed to read file, skip check - log_debug_p(gc, init)("Failed to read %s", filename); - return; - } - - // The required max map count is impossible to calculate exactly since subsystems - // other than ZGC are also creating memory mappings, and we have no control over that. - // However, ZGC tends to create the most mappings and dominate the total count. - // In the worst cases, ZGC will map each granule three times, i.e. once per heap view. - // We speculate that we need another 20% to allow for non-ZGC subsystems to map memory. - const size_t required_max_map_count = (max_capacity / XGranuleSize) * 3 * 1.2; - if (actual_max_map_count < required_max_map_count) { - log_warning_p(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****"); - log_warning_p(gc)("The system limit on number of memory mappings per process might be too low for the given"); - log_warning_p(gc)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at", - max_capacity / M, filename); - log_warning_p(gc)("least " SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). Continuing execution " - "with the current", required_max_map_count, actual_max_map_count); - log_warning_p(gc)("limit could lead to a premature OutOfMemoryError being thrown, due to failure to map memory."); - } -} - -void XPhysicalMemoryBacking::warn_commit_limits(size_t max_capacity) const { - // Warn if available space is too low - warn_available_space(max_capacity); - - // Warn if max map count is too low - warn_max_map_count(max_capacity); -} - -bool XPhysicalMemoryBacking::is_tmpfs() const { - return _filesystem == TMPFS_MAGIC; -} - -bool XPhysicalMemoryBacking::is_hugetlbfs() const { - return _filesystem == HUGETLBFS_MAGIC; -} - -bool XPhysicalMemoryBacking::tmpfs_supports_transparent_huge_pages() const { - // If the shmem_enabled file exists and is readable then we - // know the kernel supports transparent huge pages for tmpfs. - return access(XFILENAME_SHMEM_ENABLED, R_OK) == 0; -} - -XErrno XPhysicalMemoryBacking::fallocate_compat_mmap_hugetlbfs(size_t offset, size_t length, bool touch) const { - // On hugetlbfs, mapping a file segment will fail immediately, without - // the need to touch the mapped pages first, if there aren't enough huge - // pages available to back the mapping. - void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset); - if (addr == MAP_FAILED) { - // Failed - return errno; - } - - // Once mapped, the huge pages are only reserved. We need to touch them - // to associate them with the file segment. Note that we can not punch - // hole in file segments which only have reserved pages. - if (touch) { - char* const start = (char*)addr; - char* const end = start + length; - os::pretouch_memory(start, end, _block_size); - } - - // Unmap again. From now on, the huge pages that were mapped are allocated - // to this file. There's no risk of getting a SIGBUS when mapping and - // touching these pages again. - if (munmap(addr, length) == -1) { - // Failed - return errno; - } - - // Success - return 0; -} - -static bool safe_touch_mapping(void* addr, size_t length, size_t page_size) { - char* const start = (char*)addr; - char* const end = start + length; - - // Touching a mapping that can't be backed by memory will generate a - // SIGBUS. By using SafeFetch32 any SIGBUS will be safely caught and - // handled. On tmpfs, doing a fetch (rather than a store) is enough - // to cause backing pages to be allocated (there's no zero-page to - // worry about). - for (char *p = start; p < end; p += page_size) { - if (SafeFetch32((int*)p, -1) == -1) { - // Failed - return false; - } - } - - // Success - return true; -} - -XErrno XPhysicalMemoryBacking::fallocate_compat_mmap_tmpfs(size_t offset, size_t length) const { - // On tmpfs, we need to touch the mapped pages to figure out - // if there are enough pages available to back the mapping. - void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset); - if (addr == MAP_FAILED) { - // Failed - return errno; - } - - // Advise mapping to use transparent huge pages - os::realign_memory((char*)addr, length, XGranuleSize); - - // Touch the mapping (safely) to make sure it's backed by memory - const bool backed = safe_touch_mapping(addr, length, _block_size); - - // Unmap again. If successfully touched, the backing memory will - // be allocated to this file. There's no risk of getting a SIGBUS - // when mapping and touching these pages again. - if (munmap(addr, length) == -1) { - // Failed - return errno; - } - - // Success - return backed ? 0 : ENOMEM; -} - -XErrno XPhysicalMemoryBacking::fallocate_compat_pwrite(size_t offset, size_t length) const { - uint8_t data = 0; - - // Allocate backing memory by writing to each block - for (size_t pos = offset; pos < offset + length; pos += _block_size) { - if (pwrite(_fd, &data, sizeof(data), pos) == -1) { - // Failed - return errno; - } - } - - // Success - return 0; -} - -XErrno XPhysicalMemoryBacking::fallocate_fill_hole_compat(size_t offset, size_t length) const { - // fallocate(2) is only supported by tmpfs since Linux 3.5, and by hugetlbfs - // since Linux 4.3. When fallocate(2) is not supported we emulate it using - // mmap/munmap (for hugetlbfs and tmpfs with transparent huge pages) or pwrite - // (for tmpfs without transparent huge pages and other filesystem types). - if (XLargePages::is_explicit()) { - return fallocate_compat_mmap_hugetlbfs(offset, length, false /* touch */); - } else if (XLargePages::is_transparent()) { - return fallocate_compat_mmap_tmpfs(offset, length); - } else { - return fallocate_compat_pwrite(offset, length); - } -} - -XErrno XPhysicalMemoryBacking::fallocate_fill_hole_syscall(size_t offset, size_t length) const { - const int mode = 0; // Allocate - const int res = XSyscall::fallocate(_fd, mode, offset, length); - if (res == -1) { - // Failed - return errno; - } - - // Success - return 0; -} - -XErrno XPhysicalMemoryBacking::fallocate_fill_hole(size_t offset, size_t length) const { - // Using compat mode is more efficient when allocating space on hugetlbfs. - // Note that allocating huge pages this way will only reserve them, and not - // associate them with segments of the file. We must guarantee that we at - // some point touch these segments, otherwise we can not punch hole in them. - // Also note that we need to use compat mode when using transparent huge pages, - // since we need to use madvise(2) on the mapping before the page is allocated. - if (z_fallocate_supported && !XLargePages::is_enabled()) { - const XErrno err = fallocate_fill_hole_syscall(offset, length); - if (!err) { - // Success - return 0; - } - - if (err != ENOSYS && err != EOPNOTSUPP) { - // Failed - return err; - } - - // Not supported - log_debug_p(gc)("Falling back to fallocate() compatibility mode"); - z_fallocate_supported = false; - } - - return fallocate_fill_hole_compat(offset, length); -} - -XErrno XPhysicalMemoryBacking::fallocate_punch_hole(size_t offset, size_t length) const { - if (XLargePages::is_explicit()) { - // We can only punch hole in pages that have been touched. Non-touched - // pages are only reserved, and not associated with any specific file - // segment. We don't know which pages have been previously touched, so - // we always touch them here to guarantee that we can punch hole. - const XErrno err = fallocate_compat_mmap_hugetlbfs(offset, length, true /* touch */); - if (err) { - // Failed - return err; - } - } - - const int mode = FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE; - if (XSyscall::fallocate(_fd, mode, offset, length) == -1) { - // Failed - return errno; - } - - // Success - return 0; -} - -XErrno XPhysicalMemoryBacking::split_and_fallocate(bool punch_hole, size_t offset, size_t length) const { - // Try first half - const size_t offset0 = offset; - const size_t length0 = align_up(length / 2, _block_size); - const XErrno err0 = fallocate(punch_hole, offset0, length0); - if (err0) { - return err0; - } - - // Try second half - const size_t offset1 = offset0 + length0; - const size_t length1 = length - length0; - const XErrno err1 = fallocate(punch_hole, offset1, length1); - if (err1) { - return err1; - } - - // Success - return 0; -} - -XErrno XPhysicalMemoryBacking::fallocate(bool punch_hole, size_t offset, size_t length) const { - assert(is_aligned(offset, _block_size), "Invalid offset"); - assert(is_aligned(length, _block_size), "Invalid length"); - - const XErrno err = punch_hole ? fallocate_punch_hole(offset, length) : fallocate_fill_hole(offset, length); - if (err == EINTR && length > _block_size) { - // Calling fallocate(2) with a large length can take a long time to - // complete. When running profilers, such as VTune, this syscall will - // be constantly interrupted by signals. Expanding the file in smaller - // steps avoids this problem. - return split_and_fallocate(punch_hole, offset, length); - } - - return err; -} - -bool XPhysicalMemoryBacking::commit_inner(size_t offset, size_t length) const { - log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", - offset / M, (offset + length) / M, length / M); - -retry: - const XErrno err = fallocate(false /* punch_hole */, offset, length); - if (err) { - if (err == ENOSPC && !is_init_completed() && XLargePages::is_explicit() && z_fallocate_hugetlbfs_attempts-- > 0) { - // If we fail to allocate during initialization, due to lack of space on - // the hugetlbfs filesystem, then we wait and retry a few times before - // giving up. Otherwise there is a risk that running JVMs back-to-back - // will fail, since there is a delay between process termination and the - // huge pages owned by that process being returned to the huge page pool - // and made available for new allocations. - log_debug_p(gc, init)("Failed to commit memory (%s), retrying", err.to_string()); - - // Wait and retry in one second, in the hope that huge pages will be - // available by then. - sleep(1); - goto retry; - } - - // Failed - log_error_p(gc)("Failed to commit memory (%s)", err.to_string()); - return false; - } - - // Success - return true; -} - -static int offset_to_node(size_t offset) { - const GrowableArray* mapping = os::Linux::numa_nindex_to_node(); - const size_t nindex = (offset >> XGranuleSizeShift) % mapping->length(); - return mapping->at((int)nindex); -} - -size_t XPhysicalMemoryBacking::commit_numa_interleaved(size_t offset, size_t length) const { - size_t committed = 0; - - // Commit one granule at a time, so that each granule - // can be allocated from a different preferred node. - while (committed < length) { - const size_t granule_offset = offset + committed; - - // Setup NUMA policy to allocate memory from a preferred node - os::Linux::numa_set_preferred(offset_to_node(granule_offset)); - - if (!commit_inner(granule_offset, XGranuleSize)) { - // Failed - break; - } - - committed += XGranuleSize; - } - - // Restore NUMA policy - os::Linux::numa_set_preferred(-1); - - return committed; -} - -size_t XPhysicalMemoryBacking::commit_default(size_t offset, size_t length) const { - // Try to commit the whole region - if (commit_inner(offset, length)) { - // Success - return length; - } - - // Failed, try to commit as much as possible - size_t start = offset; - size_t end = offset + length; - - for (;;) { - length = align_down((end - start) / 2, XGranuleSize); - if (length < XGranuleSize) { - // Done, don't commit more - return start - offset; - } - - if (commit_inner(start, length)) { - // Success, try commit more - start += length; - } else { - // Failed, try commit less - end -= length; - } - } -} - -size_t XPhysicalMemoryBacking::commit(size_t offset, size_t length) const { - if (XNUMA::is_enabled() && !XLargePages::is_explicit()) { - // To get granule-level NUMA interleaving when using non-large pages, - // we must explicitly interleave the memory at commit/fallocate time. - return commit_numa_interleaved(offset, length); - } - - return commit_default(offset, length); -} - -size_t XPhysicalMemoryBacking::uncommit(size_t offset, size_t length) const { - log_trace(gc, heap)("Uncommitting memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", - offset / M, (offset + length) / M, length / M); - - const XErrno err = fallocate(true /* punch_hole */, offset, length); - if (err) { - log_error(gc)("Failed to uncommit memory (%s)", err.to_string()); - return 0; - } - - return length; -} - -void XPhysicalMemoryBacking::map(uintptr_t addr, size_t size, uintptr_t offset) const { - const void* const res = mmap((void*)addr, size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, _fd, offset); - if (res == MAP_FAILED) { - XErrno err; - fatal("Failed to map memory (%s)", err.to_string()); - } -} - -void XPhysicalMemoryBacking::unmap(uintptr_t addr, size_t size) const { - // Note that we must keep the address space reservation intact and just detach - // the backing memory. For this reason we map a new anonymous, non-accessible - // and non-reserved page over the mapping instead of actually unmapping. - const void* const res = mmap((void*)addr, size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); - if (res == MAP_FAILED) { - XErrno err; - fatal("Failed to map memory (%s)", err.to_string()); - } -} diff --git a/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.hpp b/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.hpp deleted file mode 100644 index 253a3f87ef427..0000000000000 --- a/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef OS_LINUX_GC_X_XPHYSICALMEMORYBACKING_LINUX_HPP -#define OS_LINUX_GC_X_XPHYSICALMEMORYBACKING_LINUX_HPP - -class XErrno; - -class XPhysicalMemoryBacking { -private: - int _fd; - size_t _size; - uint64_t _filesystem; - size_t _block_size; - size_t _available; - bool _initialized; - - void warn_available_space(size_t max_capacity) const; - void warn_max_map_count(size_t max_capacity) const; - - int create_mem_fd(const char* name) const; - int create_file_fd(const char* name) const; - int create_fd(const char* name) const; - - bool is_tmpfs() const; - bool is_hugetlbfs() const; - bool tmpfs_supports_transparent_huge_pages() const; - - XErrno fallocate_compat_mmap_hugetlbfs(size_t offset, size_t length, bool touch) const; - XErrno fallocate_compat_mmap_tmpfs(size_t offset, size_t length) const; - XErrno fallocate_compat_pwrite(size_t offset, size_t length) const; - XErrno fallocate_fill_hole_compat(size_t offset, size_t length) const; - XErrno fallocate_fill_hole_syscall(size_t offset, size_t length) const; - XErrno fallocate_fill_hole(size_t offset, size_t length) const; - XErrno fallocate_punch_hole(size_t offset, size_t length) const; - XErrno split_and_fallocate(bool punch_hole, size_t offset, size_t length) const; - XErrno fallocate(bool punch_hole, size_t offset, size_t length) const; - - bool commit_inner(size_t offset, size_t length) const; - size_t commit_numa_interleaved(size_t offset, size_t length) const; - size_t commit_default(size_t offset, size_t length) const; - -public: - XPhysicalMemoryBacking(size_t max_capacity); - - bool is_initialized() const; - - void warn_commit_limits(size_t max_capacity) const; - - size_t commit(size_t offset, size_t length) const; - size_t uncommit(size_t offset, size_t length) const; - - void map(uintptr_t addr, size_t size, uintptr_t offset) const; - void unmap(uintptr_t addr, size_t size) const; -}; - -#endif // OS_LINUX_GC_X_XPHYSICALMEMORYBACKING_LINUX_HPP diff --git a/src/hotspot/os/linux/gc/x/xSyscall_linux.cpp b/src/hotspot/os/linux/gc/x/xSyscall_linux.cpp deleted file mode 100644 index 6035eaae61bd1..0000000000000 --- a/src/hotspot/os/linux/gc/x/xSyscall_linux.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, 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. - */ - -#include "precompiled.hpp" -#include "gc/x/xSyscall_linux.hpp" -#include OS_CPU_HEADER(gc/x/xSyscall) - -#include - -int XSyscall::memfd_create(const char *name, unsigned int flags) { - return syscall(SYS_memfd_create, name, flags); -} - -int XSyscall::fallocate(int fd, int mode, size_t offset, size_t length) { - return syscall(SYS_fallocate, fd, mode, offset, length); -} - -long XSyscall::get_mempolicy(int* mode, unsigned long* nodemask, unsigned long maxnode, void* addr, unsigned long flags) { - return syscall(SYS_get_mempolicy, mode, nodemask, maxnode, addr, flags); -} diff --git a/src/hotspot/os/linux/gc/x/xSyscall_linux.hpp b/src/hotspot/os/linux/gc/x/xSyscall_linux.hpp deleted file mode 100644 index f16d2b2ffdcc6..0000000000000 --- a/src/hotspot/os/linux/gc/x/xSyscall_linux.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 OS_LINUX_GC_X_XSYSCALL_LINUX_HPP -#define OS_LINUX_GC_X_XSYSCALL_LINUX_HPP - -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" - -// Flags for get_mempolicy() -#ifndef MPOL_F_NODE -#define MPOL_F_NODE (1<<0) -#endif -#ifndef MPOL_F_ADDR -#define MPOL_F_ADDR (1<<1) -#endif - -class XSyscall : public AllStatic { -public: - static int memfd_create(const char* name, unsigned int flags); - static int fallocate(int fd, int mode, size_t offset, size_t length); - static long get_mempolicy(int* mode, unsigned long* nodemask, unsigned long maxnode, void* addr, unsigned long flags); -}; - -#endif // OS_LINUX_GC_X_XSYSCALL_LINUX_HPP diff --git a/src/hotspot/os/linux/osThread_linux.cpp b/src/hotspot/os/linux/osThread_linux.cpp index 9c77cb32f6d1c..c9a44eb413f43 100644 --- a/src/hotspot/os/linux/osThread_linux.cpp +++ b/src/hotspot/os/linux/osThread_linux.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 @@ -22,27 +22,26 @@ * */ -// no precompiled headers -#include "memory/allocation.inline.hpp" +#include "precompiled.hpp" +#include "memory/allocation.hpp" #include "runtime/mutex.hpp" #include "runtime/osThread.hpp" #include -void OSThread::pd_initialize() { - _thread_id = 0; - _pthread_id = 0; - _siginfo = nullptr; - _ucontext = nullptr; - _expanding_stack = 0; - _alt_sig_stack = nullptr; - +OSThread::OSThread() + : _thread_id(0), + _pthread_id(0), + _caller_sigmask(), + sr(), + _siginfo(nullptr), + _ucontext(nullptr), + _expanding_stack(0), + _alt_sig_stack(nullptr), + _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) { sigemptyset(&_caller_sigmask); - - _startThread_lock = new Monitor(Mutex::event, "startThread_lock"); - assert(_startThread_lock !=nullptr, "check"); } -void OSThread::pd_destroy() { +OSThread::~OSThread() { delete _startThread_lock; } diff --git a/src/hotspot/os/linux/osThread_linux.hpp b/src/hotspot/os/linux/osThread_linux.hpp index a849673af62db..5ed2d07850a97 100644 --- a/src/hotspot/os/linux/osThread_linux.hpp +++ b/src/hotspot/os/linux/osThread_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, 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 @@ -24,20 +24,17 @@ #ifndef OS_LINUX_OSTHREAD_LINUX_HPP #define OS_LINUX_OSTHREAD_LINUX_HPP - public: - typedef pid_t thread_id_t; - private: - int _thread_type; +#include "runtime/osThreadBase.hpp" +#include "suspendResume_posix.hpp" +#include "utilities/globalDefinitions.hpp" - public: +class OSThread : public OSThreadBase { + friend class VMStructs; - int thread_type() const { - return _thread_type; - } - void set_thread_type(int type) { - _thread_type = type; - } + typedef pid_t thread_id_t; + + thread_id_t _thread_id; // _pthread_id is the pthread id, which is used by library calls // (e.g. pthread_kill). @@ -46,15 +43,19 @@ sigset_t _caller_sigmask; // Caller's signal mask public: + OSThread(); + ~OSThread(); // Methods to save/restore caller's signal mask sigset_t caller_sigmask() const { return _caller_sigmask; } void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; } -#ifndef PRODUCT - // Used for debugging, return a unique integer for each thread. - int thread_identifier() const { return _thread_id; } -#endif + thread_id_t thread_id() const { + return _thread_id; + } + void set_thread_id(thread_id_t id) { + _thread_id = id; + } pthread_t pthread_id() const { return _pthread_id; @@ -67,7 +68,6 @@ // suspension support. // *************************************************************** -public: // flags that support signal based suspend/resume on Linux are in a // separate class to avoid confusion with many flags in OSThread that // are used by VM level suspend/resume. @@ -113,17 +113,10 @@ return _startThread_lock; } - // *************************************************************** - // Platform dependent initialization and cleanup - // *************************************************************** - -private: - - void pd_initialize(); - void pd_destroy(); - -// Reconciliation History -// osThread_solaris.hpp 1.24 99/08/27 13:11:54 -// End + // Printing + uintx thread_id_for_printing() const override { + return (uintx)_thread_id; + } +}; #endif // OS_LINUX_OSTHREAD_LINUX_HPP diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 609317df45fc2..b2b9a798119d2 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -817,7 +817,7 @@ static void *thread_native_entry(Thread *thread) { OSThread* osthread = thread->osthread(); Monitor* sync = osthread->startThread_lock(); - osthread->set_thread_id(checked_cast(os::current_thread_id())); + osthread->set_thread_id(checked_cast(os::current_thread_id())); if (UseNUMA) { int lgrp_id = os::numa_get_group_id(); @@ -974,9 +974,6 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, return false; } - // set the correct thread state - osthread->set_thread_type(thr_type); - // Initial state is ALLOCATED but not INITIALIZED osthread->set_state(ALLOCATED); @@ -2763,7 +2760,7 @@ void os::jvm_path(char *buf, jint buflen) { assert(ret, "cannot locate libjvm"); char *rp = nullptr; if (ret && dli_fname[0] != '\0') { - rp = os::Posix::realpath(dli_fname, buf, buflen); + rp = os::realpath(dli_fname, buf, buflen); } if (rp == nullptr) { return; @@ -2797,7 +2794,7 @@ void os::jvm_path(char *buf, jint buflen) { } assert(strstr(p, "/libjvm") == p, "invalid library name"); - rp = os::Posix::realpath(java_home_var, buf, buflen); + rp = os::realpath(java_home_var, buf, buflen); if (rp == nullptr) { return; } @@ -2818,7 +2815,7 @@ void os::jvm_path(char *buf, jint buflen) { snprintf(buf + len, buflen-len, "/hotspot/libjvm.so"); } else { // Go back to path of .so - rp = os::Posix::realpath(dli_fname, buf, buflen); + rp = os::realpath(dli_fname, buf, buflen); if (rp == nullptr) { return; } @@ -5053,16 +5050,6 @@ int os::open(const char *path, int oflag, int mode) { return fd; } -// return current position of file pointer -jlong os::current_file_offset(int fd) { - return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); -} - -// move file pointer to the specified offset -jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); -} - static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time); static jlong fast_cpu_time(Thread *thread) { diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index a31a58e55af93..996f83611b048 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -789,7 +789,7 @@ char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() { jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name); buffer[PATH_MAX - 1] = '\0'; - return os::Posix::realpath(buffer, _exePath, PATH_MAX); + return os::realpath(buffer, _exePath, PATH_MAX); } char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const { diff --git a/src/hotspot/os/linux/vmStructs_linux.hpp b/src/hotspot/os/linux/vmStructs_linux.hpp index 818f6bb188fe8..3b82ac58ac697 100644 --- a/src/hotspot/os/linux/vmStructs_linux.hpp +++ b/src/hotspot/os/linux/vmStructs_linux.hpp @@ -31,9 +31,22 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + \ + /******************************/ \ + /* Threads (NOTE: incomplete) */ \ + /******************************/ \ + nonstatic_field(OSThread, _thread_id, pid_t) \ + nonstatic_field(OSThread, _pthread_id, pthread_t) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + \ + /**********************/ \ + /* Posix Thread IDs */ \ + /**********************/ \ + \ + declare_integer_type(pid_t) \ + declare_unsigned_integer_type(pthread_t) #define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os/posix/gc/x/xArguments_posix.cpp b/src/hotspot/os/posix/gc/x/xArguments_posix.cpp deleted file mode 100644 index 6df0a9bd07460..0000000000000 --- a/src/hotspot/os/posix/gc/x/xArguments_posix.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xArguments.hpp" - -bool XArguments::is_os_supported() { - return true; -} diff --git a/src/hotspot/os/posix/gc/x/xInitialize_posix.cpp b/src/hotspot/os/posix/gc/x/xInitialize_posix.cpp deleted file mode 100644 index acf71e9890178..0000000000000 --- a/src/hotspot/os/posix/gc/x/xInitialize_posix.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xInitialize.hpp" - -void XInitialize::pd_initialize() { - // Does nothing -} diff --git a/src/hotspot/os/posix/gc/x/xUtils_posix.cpp b/src/hotspot/os/posix/gc/x/xUtils_posix.cpp deleted file mode 100644 index eee3e5cfbe60d..0000000000000 --- a/src/hotspot/os/posix/gc/x/xUtils_posix.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xUtils.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" - -#include - -uintptr_t XUtils::alloc_aligned(size_t alignment, size_t size) { - void* res = nullptr; - - // Use raw posix_memalign as long as we have no wrapper for it - ALLOW_C_FUNCTION(::posix_memalign, int rc = posix_memalign(&res, alignment, size);) - if (rc != 0) { - fatal("posix_memalign() failed"); - } - - memset(res, 0, size); - - return (uintptr_t)res; -} diff --git a/src/hotspot/os/posix/gc/x/xVirtualMemory_posix.cpp b/src/hotspot/os/posix/gc/x/xVirtualMemory_posix.cpp deleted file mode 100644 index e2422eb0978fc..0000000000000 --- a/src/hotspot/os/posix/gc/x/xVirtualMemory_posix.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xVirtualMemory.hpp" -#include "logging/log.hpp" - -#include -#include - -void XVirtualMemoryManager::pd_initialize_before_reserve() { - // Does nothing -} - -void XVirtualMemoryManager::pd_initialize_after_reserve() { - // Does nothing -} - -bool XVirtualMemoryManager::pd_reserve(uintptr_t addr, size_t size) { - const uintptr_t res = (uintptr_t)mmap((void*)addr, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); - if (res == (uintptr_t)MAP_FAILED) { - // Failed to reserve memory - return false; - } - - if (res != addr) { - // Failed to reserve memory at the requested address - munmap((void*)res, size); - return false; - } - - // Success - return true; -} - -void XVirtualMemoryManager::pd_unreserve(uintptr_t addr, size_t size) { - const int res = munmap((void*)addr, size); - assert(res == 0, "Failed to unmap memory"); -} diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 60efdeb2ef59a..75253843593c6 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -104,49 +104,44 @@ static int clock_tics_per_sec = 100; size_t os::_os_min_stack_allowed = PTHREAD_STACK_MIN; // Check core dump limit and report possible place where core can be found -void os::check_dump_limit(char* buffer, size_t bufferSize) { +void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) { if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) { jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line"); VMError::record_coredump_status(buffer, false); - return; - } - - int n; - struct rlimit rlim; - bool success; - - char core_path[PATH_MAX]; - n = get_core_path(core_path, PATH_MAX); - - if (n <= 0) { - jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id()); - success = true; + } else { + struct rlimit rlim; + bool success = true; + bool warn = true; + char core_path[PATH_MAX]; + if (get_core_path(core_path, PATH_MAX) <= 0) { + jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id()); #ifdef LINUX - } else if (core_path[0] == '"') { // redirect to user process - jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path); - success = true; + } else if (core_path[0] == '"') { // redirect to user process + jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path); #endif - } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) { - jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path); - success = true; - } else { - switch(rlim.rlim_cur) { - case RLIM_INFINITY: - jio_snprintf(buffer, bufferSize, "%s", core_path); - success = true; - break; - case 0: - jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again"); - success = false; - break; - default: - jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K); - success = true; - break; + } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) { + jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path); + } else { + switch(rlim.rlim_cur) { + case RLIM_INFINITY: + jio_snprintf(buffer, bufferSize, "%s", core_path); + warn = false; + break; + case 0: + jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again"); + success = false; + break; + default: + jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K); + break; + } + } + if (!check_only) { + VMError::record_coredump_status(buffer, success); + } else if (warn) { + warning("CreateCoredumpOnCrash specified, but %s", buffer); } } - - VMError::record_coredump_status(buffer, success); } bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) { @@ -348,6 +343,16 @@ int os::create_file_for_heap(const char* dir) { return fd; } +// return current position of file pointer +jlong os::current_file_offset(int fd) { + return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); +} + +// move file pointer to the specified offset +jlong os::seek_to_file_offset(int fd, jlong offset) { + return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); +} + // Is a (classpath) directory empty? bool os::dir_is_empty(const char* path) { DIR *dir = nullptr; @@ -1024,10 +1029,10 @@ char* os::Posix::describe_pthread_attr(char* buf, size_t buflen, const pthread_a return buf; } -char* os::Posix::realpath(const char* filename, char* outbuf, size_t outbuflen) { +char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { if (filename == nullptr || outbuf == nullptr || outbuflen < 1) { - assert(false, "os::Posix::realpath: invalid arguments."); + assert(false, "os::realpath: invalid arguments."); errno = EINVAL; return nullptr; } @@ -1062,7 +1067,6 @@ char* os::Posix::realpath(const char* filename, char* outbuf, size_t outbuflen) } } return result; - } int os::stat(const char *path, struct stat *sbuf) { diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index d872a6dae899e..cac5b250cdfa0 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -73,13 +73,6 @@ class os::Posix { // to buf with len buflen; buf is returned. static char* describe_pthread_attr(char* buf, size_t buflen, const pthread_attr_t* attr); - // A safe implementation of realpath which will not cause a buffer overflow if the resolved path - // is longer than PATH_MAX. - // On success, returns 'outbuf', which now contains the path. - // On error, it will return null and set errno. The content of 'outbuf' is undefined. - // On truncation error ('outbuf' too small), it will return null and set errno to ENAMETOOLONG. - static char* realpath(const char* filename, char* outbuf, size_t outbuflen); - // Returns true if given uid is root. static bool is_root(uid_t uid); diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index 4eb46169878cd..17bf63092c208 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -1086,7 +1086,7 @@ static char* mmap_create_shared(size_t size) { static void unmap_shared(char* addr, size_t bytes) { int res; if (MemTracker::enabled()) { - ThreadCritical tc; + NmtVirtualMemoryLocker ml; res = ::munmap(addr, bytes); if (res == 0) { MemTracker::record_virtual_memory_release((address)addr, bytes); diff --git a/src/hotspot/os/windows/attachListener_windows.cpp b/src/hotspot/os/windows/attachListener_windows.cpp index 3f6ca941c209b..bfa377d52cf2f 100644 --- a/src/hotspot/os/windows/attachListener_windows.cpp +++ b/src/hotspot/os/windows/attachListener_windows.cpp @@ -32,17 +32,24 @@ #include // SIGBREAK #include -// The AttachListener thread services a queue of operations. It blocks in the dequeue -// function until an operation is enqueued. A client enqueues an operation by creating +// The AttachListener thread services a queue of operation requests. It blocks in the dequeue +// function until a request is enqueued. A client enqueues a request by creating // a thread in this process using the Win32 CreateRemoteThread function. That thread // executes a small stub generated by the client. The stub invokes the -// JVM_EnqueueOperation function which checks the operation parameters and enqueues -// the operation to the queue serviced by the attach listener. The thread created by +// JVM_EnqueueOperation or JVM_EnqueueOperation_v2 function which checks the operation parameters +// and enqueues the operation request to the queue. The thread created by // the client is a native thread and is restricted to a single page of stack. To keep -// it simple operations are pre-allocated at initialization time. An enqueue thus -// takes a preallocated operation, populates the operation parameters, adds it to +// it simple operation requests are pre-allocated at initialization time. An enqueue thus +// takes a preallocated request, populates the operation parameters, adds it to // queue and wakes up the attach listener. // +// Differences between Attach API v1 and v2: +// In v1 (jdk6+) client calls JVM_EnqueueOperation function and passes all operation parameters +// as arguments of the function. +// In v2 (jdk24+) client calls JVM_EnqueueOperation_v2 function and passes only pipe name. +// Attach listeners connects to the pipe (in read/write mode) and reads all operation parameters +// (the same way as other platform implementations read them using sockets). +// // When an operation has completed the attach listener is required to send the // operation result and any result data to the client. In this implementation the // client is a pipe server. In the enqueue operation it provides the name of pipe @@ -55,8 +62,154 @@ // this wasn't worth worrying about. -// forward reference -class Win32AttachOperation; +class PipeChannel : public AttachOperation::RequestReader, public AttachOperation::ReplyWriter { +private: + HANDLE _hPipe; +public: + PipeChannel() : _hPipe(INVALID_HANDLE_VALUE) {} + ~PipeChannel() { + close(); + } + + bool opened() const { + return _hPipe != INVALID_HANDLE_VALUE; + } + + bool open(const char* pipe, bool write_only) { + _hPipe = ::CreateFile(pipe, + GENERIC_WRITE | (write_only ? 0 : GENERIC_READ), + 0, // no sharing + nullptr, // default security attributes + OPEN_EXISTING, // opens existing pipe + 0, // default attributes + nullptr); // no template file + if (_hPipe == INVALID_HANDLE_VALUE) { + log_error(attach)("could not open (%d) pipe %s", GetLastError(), pipe); + return false; + } + return true; + } + + void close() { + if (opened()) { + CloseHandle(_hPipe); + _hPipe = INVALID_HANDLE_VALUE; + } + } + + // RequestReader + int read(void* buffer, int size) override { + assert(opened(), "must be"); + DWORD nread; + BOOL fSuccess = ReadFile(_hPipe, + buffer, + (DWORD)size, + &nread, + nullptr); // not overlapped + return fSuccess ? (int)nread : -1; + } + + // ReplyWriter + int write(const void* buffer, int size) override { + assert(opened(), "must be"); + DWORD written; + BOOL fSuccess = WriteFile(_hPipe, + buffer, + (DWORD)size, + &written, + nullptr); // not overlapped + return fSuccess ? (int)written : -1; + } + + void flush() override { + assert(opened(), "must be"); + FlushFileBuffers(_hPipe); + } +}; + +class Win32AttachOperation: public AttachOperation { +public: + enum { + pipe_name_max = 256 // maximum pipe name + }; + +private: + PipeChannel _pipe; + +public: + // for v1 pipe must be write-only + void open_pipe(const char* pipe_name, bool write_only) { + _pipe.open(pipe_name, write_only); + } + + bool read_request() { + return AttachOperation::read_request(&_pipe); + } + +public: + void complete(jint result, bufferedStream* result_stream) override; +}; + + +// Win32AttachOperationRequest is an element of AttachOperation request list. +class Win32AttachOperationRequest { +private: + AttachAPIVersion _ver; + char _name[AttachOperation::name_length_max + 1]; + char _arg[AttachOperation::arg_count_max][AttachOperation::arg_length_max + 1]; + char _pipe[Win32AttachOperation::pipe_name_max + 1]; + + Win32AttachOperationRequest* _next; + + void set_value(char* dst, const char* str, size_t dst_size) { + if (str != nullptr) { + assert(strlen(str) < dst_size, "exceeds maximum length"); + strncpy(dst, str, dst_size - 1); + dst[dst_size - 1] = '\0'; + } else { + strcpy(dst, ""); + } + } + +public: + void set(AttachAPIVersion ver, const char* pipename, + const char* cmd = nullptr, + const char* arg0 = nullptr, + const char* arg1 = nullptr, + const char* arg2 = nullptr) { + _ver = ver; + set_value(_name, cmd, sizeof(_name)); + set_value(_arg[0], arg0, sizeof(_arg[0])); + set_value(_arg[1], arg1, sizeof(_arg[1])); + set_value(_arg[2], arg2, sizeof(_arg[2])); + set_value(_pipe, pipename, sizeof(_pipe)); + } + AttachAPIVersion ver() const { + return _ver; + } + const char* cmd() const { + return _name; + } + const char* arg(int i) const { + return (i >= 0 && i < AttachOperation::arg_count_max) ? _arg[i] : nullptr; + } + const char* pipe() const { + return _pipe; + } + + Win32AttachOperationRequest* next() const { + return _next; + } + void set_next(Win32AttachOperationRequest* next) { + _next = next; + } + + // noarg constructor as operation is preallocated + Win32AttachOperationRequest() { + set(ATTACH_API_V1, ""); + set_next(nullptr); + } +}; class Win32AttachListener: AllStatic { @@ -69,18 +222,18 @@ class Win32AttachListener: AllStatic { static HANDLE _mutex; // head of preallocated operations list - static Win32AttachOperation* _avail; + static Win32AttachOperationRequest* _avail; // head and tail of enqueue operations list - static Win32AttachOperation* _head; - static Win32AttachOperation* _tail; + static Win32AttachOperationRequest* _head; + static Win32AttachOperationRequest* _tail; - static Win32AttachOperation* head() { return _head; } - static void set_head(Win32AttachOperation* head) { _head = head; } + static Win32AttachOperationRequest* head() { return _head; } + static void set_head(Win32AttachOperationRequest* head) { _head = head; } - static Win32AttachOperation* tail() { return _tail; } - static void set_tail(Win32AttachOperation* tail) { _tail = tail; } + static Win32AttachOperationRequest* tail() { return _tail; } + static void set_tail(Win32AttachOperationRequest* tail) { _tail = tail; } // A semaphore is used for communication about enqueued operations. @@ -101,11 +254,12 @@ class Win32AttachListener: AllStatic { static int init(); static HANDLE mutex() { return _mutex; } - static Win32AttachOperation* available() { return _avail; } - static void set_available(Win32AttachOperation* avail) { _avail = avail; } + static Win32AttachOperationRequest* available() { return _avail; } + static void set_available(Win32AttachOperationRequest* avail) { _avail = avail; } // enqueue an operation to the end of the list - static int enqueue(char* cmd, char* arg1, char* arg2, char* arg3, char* pipename); + static int enqueue(AttachAPIVersion ver, const char* cmd, + const char* arg1, const char* arg2, const char* arg3, const char* pipename); // dequeue an operation from from head of the list static Win32AttachOperation* dequeue(); @@ -114,48 +268,9 @@ class Win32AttachListener: AllStatic { // statics HANDLE Win32AttachListener::_mutex; HANDLE Win32AttachListener::_enqueued_ops_semaphore; -Win32AttachOperation* Win32AttachListener::_avail; -Win32AttachOperation* Win32AttachListener::_head; -Win32AttachOperation* Win32AttachListener::_tail; - - -// Win32AttachOperation is an AttachOperation that additionally encapsulates the name -// of a pipe which is used to send the operation reply/output to the client. -// Win32AttachOperation can also be linked in a list. - -class Win32AttachOperation: public AttachOperation { - private: - friend class Win32AttachListener; - - enum { - pipe_name_max = 256 // maximum pipe name - }; - - char _pipe[pipe_name_max + 1]; - - const char* pipe() const { return _pipe; } - void set_pipe(const char* pipe) { - assert(strlen(pipe) <= pipe_name_max, "exceeds maximum length of pipe name"); - os::snprintf(_pipe, sizeof(_pipe), "%s", pipe); - } - - HANDLE open_pipe(); - static BOOL write_pipe(HANDLE hPipe, char* buf, int len); - - Win32AttachOperation* _next; - - Win32AttachOperation* next() const { return _next; } - void set_next(Win32AttachOperation* next) { _next = next; } - - // noarg constructor as operation is preallocated - Win32AttachOperation() : AttachOperation("") { - set_pipe(""); - set_next(nullptr); - } - - public: - void complete(jint result, bufferedStream* result_stream); -}; +Win32AttachOperationRequest* Win32AttachListener::_avail; +Win32AttachOperationRequest* Win32AttachListener::_head; +Win32AttachOperationRequest* Win32AttachListener::_tail; // Preallocate the maximum number of operations that can be enqueued. @@ -171,18 +286,24 @@ int Win32AttachListener::init() { set_available(nullptr); for (int i=0; iset_next(available()); set_available(op); } + AttachListener::set_supported_version(ATTACH_API_V2); + return 0; } // Enqueue an operation. This is called from a native thread that is not attached to VM. // Also we need to be careful not to execute anything that results in more than a 4k stack. // -int Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) { +int Win32AttachListener::enqueue(AttachAPIVersion ver, const char* cmd, + const char* arg0, const char* arg1, const char* arg2, const char* pipename) { + + log_debug(attach)("AttachListener::enqueue, ver = %d, cmd = %s", (int)ver, cmd); + // wait up to 10 seconds for listener to be up and running int sleep_count = 0; while (!AttachListener::is_initialized()) { @@ -210,7 +331,7 @@ int Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2, } // try to get an operation from the available list - Win32AttachOperation* op = available(); + Win32AttachOperationRequest* op = available(); if (op != nullptr) { set_available(op->next()); @@ -223,11 +344,7 @@ int Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2, } set_tail(op); - op->set_name(cmd); - op->set_arg(0, arg0); - op->set_arg(1, arg1); - op->set_arg(2, arg2); - op->set_pipe(pipename); + op->set(ver, pipename, cmd, arg0, arg1, arg2); // Increment number of enqueued operations. // Side effect: Semaphore will be signaled and will release @@ -236,6 +353,7 @@ int Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2, ::ReleaseSemaphore(enqueued_ops_semaphore(), 1, nullptr); guarantee(not_exceeding_semaphore_maximum_count, "invariant"); } + ::ReleaseMutex(mutex()); return (op != nullptr) ? 0 : ATTACH_ERROR_RESOURCE; @@ -255,107 +373,63 @@ Win32AttachOperation* Win32AttachListener::dequeue() { guarantee(res != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); guarantee(res == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", res); + Win32AttachOperation* op = nullptr; + Win32AttachOperationRequest* request = head(); + if (request != nullptr) { + log_debug(attach)("AttachListener::dequeue, got request, ver = %d, cmd = %s", request->ver(), request->cmd()); - Win32AttachOperation* op = head(); - if (op != nullptr) { - set_head(op->next()); + set_head(request->next()); if (head() == nullptr) { // list is empty set_tail(nullptr); } + + switch (request->ver()) { + case ATTACH_API_V1: + op = new Win32AttachOperation(); + op->set_name(request->cmd()); + for (int i = 0; i < AttachOperation::arg_count_max; i++) { + op->append_arg(request->arg(i)); + } + op->open_pipe(request->pipe(), true/*write-only*/); + break; + case ATTACH_API_V2: + op = new Win32AttachOperation(); + op->open_pipe(request->pipe(), false/*write-only*/); + if (!op->read_request()) { + log_error(attach)("AttachListener::dequeue, reading request ERROR"); + delete op; + op = nullptr; + } + break; + default: + log_error(attach)("AttachListener::dequeue, unsupported version: %d", request->ver(), request->cmd()); + break; + } } + // put the operation back on the available list + request->set_next(Win32AttachListener::available()); + Win32AttachListener::set_available(request); + ::ReleaseMutex(mutex()); if (op != nullptr) { + log_debug(attach)("AttachListener::dequeue, return op: %s", op->name()); return op; } } } - -// open the pipe to the client -HANDLE Win32AttachOperation::open_pipe() { - HANDLE hPipe = ::CreateFile( pipe(), // pipe name - GENERIC_WRITE, // write only - 0, // no sharing - nullptr, // default security attributes - OPEN_EXISTING, // opens existing pipe - 0, // default attributes - nullptr); // no template file - return hPipe; -} - -// write to the pipe -BOOL Win32AttachOperation::write_pipe(HANDLE hPipe, char* buf, int len) { - do { - DWORD nwrote; - - BOOL fSuccess = WriteFile( hPipe, // pipe handle - (LPCVOID)buf, // message - (DWORD)len, // message length - &nwrote, // bytes written - nullptr); // not overlapped - if (!fSuccess) { - return fSuccess; - } - buf += nwrote; - len -= nwrote; - } while (len > 0); - return TRUE; -} - -// Complete the operation: -// - open the pipe to the client -// - write the operation result (a jint) -// - write the operation output (the result stream) -// void Win32AttachOperation::complete(jint result, bufferedStream* result_stream) { JavaThread* thread = JavaThread::current(); ThreadBlockInVM tbivm(thread); - HANDLE hPipe = open_pipe(); - int lastError = (int)::GetLastError(); - if (hPipe != INVALID_HANDLE_VALUE) { - BOOL fSuccess; - - char msg[32]; - os::snprintf(msg, sizeof(msg), "%d\n", result); - msg[sizeof(msg) - 1] = '\0'; - - fSuccess = write_pipe(hPipe, msg, (int)strlen(msg)); - if (fSuccess) { - fSuccess = write_pipe(hPipe, (char*)result_stream->base(), (int)(result_stream->size())); - } - lastError = (int)::GetLastError(); - - // Need to flush buffers - FlushFileBuffers(hPipe); - CloseHandle(hPipe); + write_reply(&_pipe, result, result_stream); - if (fSuccess) { - log_debug(attach)("wrote result of attach operation %s to pipe %s", name(), pipe()); - } else { - log_error(attach)("failure (%d) writing result of operation %s to pipe %s", lastError, name(), pipe()); - } - } else { - log_error(attach)("could not open (%d) pipe %s to send result of operation %s", lastError, pipe(), name()); - } - - DWORD res = ::WaitForSingleObject(Win32AttachListener::mutex(), INFINITE); - assert(res != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); - assert(res == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", res); - - if (res == WAIT_OBJECT_0) { - - // put the operation back on the available list - set_next(Win32AttachListener::available()); - Win32AttachListener::set_available(this); - - ::ReleaseMutex(Win32AttachListener::mutex()); - } + delete this; } -// AttachOperation functions +// AttachListener functions AttachOperation* AttachListener::dequeue() { JavaThread* thread = JavaThread::current(); @@ -404,8 +478,12 @@ void AttachListener::pd_detachall() { // Native thread started by remote client executes this. extern "C" { JNIEXPORT jint JNICALL - JVM_EnqueueOperation(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) { - return (jint)Win32AttachListener::enqueue(cmd, arg0, arg1, arg2, pipename); - } + JVM_EnqueueOperation(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) { + return (jint)Win32AttachListener::enqueue(ATTACH_API_V1, cmd, arg0, arg1, arg2, pipename); + } + JNIEXPORT jint JNICALL + JVM_EnqueueOperation_v2(char* pipename) { + return (jint)Win32AttachListener::enqueue(ATTACH_API_V2, "", "", "", "", pipename); + } } // extern diff --git a/src/hotspot/os/windows/gc/x/xArguments_windows.cpp b/src/hotspot/os/windows/gc/x/xArguments_windows.cpp deleted file mode 100644 index fc5f7eccb911f..0000000000000 --- a/src/hotspot/os/windows/gc/x/xArguments_windows.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xArguments.hpp" -#include "gc/x/xSyscall_windows.hpp" - -bool XArguments::is_os_supported() { - return XSyscall::is_supported(); -} diff --git a/src/hotspot/os/windows/gc/x/xInitialize_windows.cpp b/src/hotspot/os/windows/gc/x/xInitialize_windows.cpp deleted file mode 100644 index 99f6432803326..0000000000000 --- a/src/hotspot/os/windows/gc/x/xInitialize_windows.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xInitialize.hpp" -#include "gc/x/xSyscall_windows.hpp" - -void XInitialize::pd_initialize() { - XSyscall::initialize(); -} diff --git a/src/hotspot/os/windows/gc/x/xMapper_windows.cpp b/src/hotspot/os/windows/gc/x/xMapper_windows.cpp deleted file mode 100644 index e69b6ec56e293..0000000000000 --- a/src/hotspot/os/windows/gc/x/xMapper_windows.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xMapper_windows.hpp" -#include "gc/x/xSyscall_windows.hpp" -#include "logging/log.hpp" -#include "utilities/debug.hpp" - -#include - -// Memory reservation, commit, views, and placeholders. -// -// To be able to up-front reserve address space for the heap views, and later -// multi-map the heap views to the same physical memory, without ever losing the -// reservation of the reserved address space, we use "placeholders". -// -// These placeholders block out the address space from being used by other parts -// of the process. To commit memory in this address space, the placeholder must -// be replaced by anonymous memory, or replaced by mapping a view against a -// paging file mapping. We use the later to support multi-mapping. -// -// We want to be able to dynamically commit and uncommit the physical memory of -// the heap (and also unmap ZPages), in granules of ZGranuleSize bytes. There is -// no way to grow and shrink the committed memory of a paging file mapping. -// Therefore, we create multiple granule-sized page file mappings. The memory is -// committed by creating a page file mapping, map a view against it, commit the -// memory, unmap the view. The memory will stay committed until all views are -// unmapped, and the paging file mapping handle is closed. -// -// When replacing a placeholder address space reservation with a mapped view -// against a paging file mapping, the virtual address space must exactly match -// an existing placeholder's address and size. Therefore we only deal with -// granule-sized placeholders at this layer. Higher layers that keep track of -// reserved available address space can (and will) coalesce placeholders, but -// they will be split before being used. - -#define fatal_error(msg, addr, size) \ - fatal(msg ": " PTR_FORMAT " " SIZE_FORMAT "M (%d)", \ - (addr), (size) / M, GetLastError()) - -uintptr_t XMapper::reserve(uintptr_t addr, size_t size) { - void* const res = XSyscall::VirtualAlloc2( - GetCurrentProcess(), // Process - (void*)addr, // BaseAddress - size, // Size - MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, // AllocationType - PAGE_NOACCESS, // PageProtection - nullptr, // ExtendedParameters - 0 // ParameterCount - ); - - // Caller responsible for error handling - return (uintptr_t)res; -} - -void XMapper::unreserve(uintptr_t addr, size_t size) { - const bool res = XSyscall::VirtualFreeEx( - GetCurrentProcess(), // hProcess - (void*)addr, // lpAddress - size, // dwSize - MEM_RELEASE // dwFreeType - ); - - if (!res) { - fatal_error("Failed to unreserve memory", addr, size); - } -} - -HANDLE XMapper::create_paging_file_mapping(size_t size) { - // Create mapping with SEC_RESERVE instead of SEC_COMMIT. - // - // We use MapViewOfFile3 for two different reasons: - // 1) When committing memory for the created paging file - // 2) When mapping a view of the memory created in (2) - // - // The non-platform code is only setup to deal with out-of-memory - // errors in (1). By using SEC_RESERVE, we prevent MapViewOfFile3 - // from failing because of "commit limit" checks. To actually commit - // memory in (1), a call to VirtualAlloc2 is done. - - HANDLE const res = XSyscall::CreateFileMappingW( - INVALID_HANDLE_VALUE, // hFile - nullptr, // lpFileMappingAttribute - PAGE_READWRITE | SEC_RESERVE, // flProtect - size >> 32, // dwMaximumSizeHigh - size & 0xFFFFFFFF, // dwMaximumSizeLow - nullptr // lpName - ); - - // Caller responsible for error handling - return res; -} - -bool XMapper::commit_paging_file_mapping(HANDLE file_handle, uintptr_t file_offset, size_t size) { - const uintptr_t addr = map_view_no_placeholder(file_handle, file_offset, size); - if (addr == 0) { - log_error(gc)("Failed to map view of paging file mapping (%d)", GetLastError()); - return false; - } - - const uintptr_t res = commit(addr, size); - if (res != addr) { - log_error(gc)("Failed to commit memory (%d)", GetLastError()); - } - - unmap_view_no_placeholder(addr, size); - - return res == addr; -} - -uintptr_t XMapper::map_view_no_placeholder(HANDLE file_handle, uintptr_t file_offset, size_t size) { - void* const res = XSyscall::MapViewOfFile3( - file_handle, // FileMapping - GetCurrentProcess(), // ProcessHandle - nullptr, // BaseAddress - file_offset, // Offset - size, // ViewSize - 0, // AllocationType - PAGE_NOACCESS, // PageProtection - nullptr, // ExtendedParameters - 0 // ParameterCount - ); - - // Caller responsible for error handling - return (uintptr_t)res; -} - -void XMapper::unmap_view_no_placeholder(uintptr_t addr, size_t size) { - const bool res = XSyscall::UnmapViewOfFile2( - GetCurrentProcess(), // ProcessHandle - (void*)addr, // BaseAddress - 0 // UnmapFlags - ); - - if (!res) { - fatal_error("Failed to unmap memory", addr, size); - } -} - -uintptr_t XMapper::commit(uintptr_t addr, size_t size) { - void* const res = XSyscall::VirtualAlloc2( - GetCurrentProcess(), // Process - (void*)addr, // BaseAddress - size, // Size - MEM_COMMIT, // AllocationType - PAGE_NOACCESS, // PageProtection - nullptr, // ExtendedParameters - 0 // ParameterCount - ); - - // Caller responsible for error handling - return (uintptr_t)res; -} - -HANDLE XMapper::create_and_commit_paging_file_mapping(size_t size) { - HANDLE const file_handle = create_paging_file_mapping(size); - if (file_handle == 0) { - log_error(gc)("Failed to create paging file mapping (%d)", GetLastError()); - return 0; - } - - const bool res = commit_paging_file_mapping(file_handle, 0 /* file_offset */, size); - if (!res) { - close_paging_file_mapping(file_handle); - return 0; - } - - return file_handle; -} - -void XMapper::close_paging_file_mapping(HANDLE file_handle) { - const bool res = CloseHandle( - file_handle // hObject - ); - - if (!res) { - fatal("Failed to close paging file handle (%d)", GetLastError()); - } -} - -HANDLE XMapper::create_shared_awe_section() { - MEM_EXTENDED_PARAMETER parameter = { 0 }; - parameter.Type = MemSectionExtendedParameterUserPhysicalFlags; - parameter.ULong64 = 0; - - HANDLE section = XSyscall::CreateFileMapping2( - INVALID_HANDLE_VALUE, // File - nullptr, // SecurityAttributes - SECTION_MAP_READ | SECTION_MAP_WRITE, // DesiredAccess - PAGE_READWRITE, // PageProtection - SEC_RESERVE | SEC_LARGE_PAGES, // AllocationAttributes - 0, // MaximumSize - nullptr, // Name - ¶meter, // ExtendedParameters - 1 // ParameterCount - ); - - if (section == nullptr) { - fatal("Could not create shared AWE section (%d)", GetLastError()); - } - - return section; -} - -uintptr_t XMapper::reserve_for_shared_awe(HANDLE awe_section, uintptr_t addr, size_t size) { - MEM_EXTENDED_PARAMETER parameter = { 0 }; - parameter.Type = MemExtendedParameterUserPhysicalHandle; - parameter.Handle = awe_section; - - void* const res = XSyscall::VirtualAlloc2( - GetCurrentProcess(), // Process - (void*)addr, // BaseAddress - size, // Size - MEM_RESERVE | MEM_PHYSICAL, // AllocationType - PAGE_READWRITE, // PageProtection - ¶meter, // ExtendedParameters - 1 // ParameterCount - ); - - // Caller responsible for error handling - return (uintptr_t)res; -} - -void XMapper::unreserve_for_shared_awe(uintptr_t addr, size_t size) { - bool res = VirtualFree( - (void*)addr, // lpAddress - 0, // dwSize - MEM_RELEASE // dwFreeType - ); - - if (!res) { - fatal("Failed to unreserve memory: " PTR_FORMAT " " SIZE_FORMAT "M (%d)", - addr, size / M, GetLastError()); - } -} - -void XMapper::split_placeholder(uintptr_t addr, size_t size) { - const bool res = VirtualFree( - (void*)addr, // lpAddress - size, // dwSize - MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER // dwFreeType - ); - - if (!res) { - fatal_error("Failed to split placeholder", addr, size); - } -} - -void XMapper::coalesce_placeholders(uintptr_t addr, size_t size) { - const bool res = VirtualFree( - (void*)addr, // lpAddress - size, // dwSize - MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS // dwFreeType - ); - - if (!res) { - fatal_error("Failed to coalesce placeholders", addr, size); - } -} - -void XMapper::map_view_replace_placeholder(HANDLE file_handle, uintptr_t file_offset, uintptr_t addr, size_t size) { - void* const res = XSyscall::MapViewOfFile3( - file_handle, // FileMapping - GetCurrentProcess(), // ProcessHandle - (void*)addr, // BaseAddress - file_offset, // Offset - size, // ViewSize - MEM_REPLACE_PLACEHOLDER, // AllocationType - PAGE_READWRITE, // PageProtection - nullptr, // ExtendedParameters - 0 // ParameterCount - ); - - if (res == nullptr) { - fatal_error("Failed to map memory", addr, size); - } -} - -void XMapper::unmap_view_preserve_placeholder(uintptr_t addr, size_t size) { - const bool res = XSyscall::UnmapViewOfFile2( - GetCurrentProcess(), // ProcessHandle - (void*)addr, // BaseAddress - MEM_PRESERVE_PLACEHOLDER // UnmapFlags - ); - - if (!res) { - fatal_error("Failed to unmap memory", addr, size); - } -} diff --git a/src/hotspot/os/windows/gc/x/xMapper_windows.hpp b/src/hotspot/os/windows/gc/x/xMapper_windows.hpp deleted file mode 100644 index 0f266d3fab7c6..0000000000000 --- a/src/hotspot/os/windows/gc/x/xMapper_windows.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 - * 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 OS_WINDOWS_GC_X_XMAPPER_WINDOWS_HPP -#define OS_WINDOWS_GC_X_XMAPPER_WINDOWS_HPP - -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" - -#include - -class XMapper : public AllStatic { -private: - // Create paging file mapping - static HANDLE create_paging_file_mapping(size_t size); - - // Commit paging file mapping - static bool commit_paging_file_mapping(HANDLE file_handle, uintptr_t file_offset, size_t size); - - // Map a view anywhere without a placeholder - static uintptr_t map_view_no_placeholder(HANDLE file_handle, uintptr_t file_offset, size_t size); - - // Unmap a view without preserving a placeholder - static void unmap_view_no_placeholder(uintptr_t addr, size_t size); - - // Commit memory covering the given virtual address range - static uintptr_t commit(uintptr_t addr, size_t size); - -public: - // Reserve memory with a placeholder - static uintptr_t reserve(uintptr_t addr, size_t size); - - // Unreserve memory - static void unreserve(uintptr_t addr, size_t size); - - // Create and commit paging file mapping - static HANDLE create_and_commit_paging_file_mapping(size_t size); - - // Close paging file mapping - static void close_paging_file_mapping(HANDLE file_handle); - - // Create a shared AWE section - static HANDLE create_shared_awe_section(); - - // Reserve memory attached to the shared AWE section - static uintptr_t reserve_for_shared_awe(HANDLE awe_section, uintptr_t addr, size_t size); - - // Unreserve memory attached to a shared AWE section - static void unreserve_for_shared_awe(uintptr_t addr, size_t size); - - // Split a placeholder - // - // A view can only replace an entire placeholder, so placeholders need to be - // split and coalesced to be the exact size of the new views. - // [addr, addr + size) needs to be a proper sub-placeholder of an existing - // placeholder. - static void split_placeholder(uintptr_t addr, size_t size); - - // Coalesce a placeholder - // - // [addr, addr + size) is the new placeholder. A sub-placeholder needs to - // exist within that range. - static void coalesce_placeholders(uintptr_t addr, size_t size); - - // Map a view of the file handle and replace the placeholder covering the - // given virtual address range - static void map_view_replace_placeholder(HANDLE file_handle, uintptr_t file_offset, uintptr_t addr, size_t size); - - // Unmap the view and reinstate a placeholder covering the given virtual - // address range - static void unmap_view_preserve_placeholder(uintptr_t addr, size_t size); -}; - -#endif // OS_WINDOWS_GC_X_XMAPPER_WINDOWS_HPP diff --git a/src/hotspot/os/windows/gc/x/xNUMA_windows.cpp b/src/hotspot/os/windows/gc/x/xNUMA_windows.cpp deleted file mode 100644 index 47a84df962e92..0000000000000 --- a/src/hotspot/os/windows/gc/x/xNUMA_windows.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xNUMA.hpp" - -void XNUMA::pd_initialize() { - _enabled = false; -} - -uint32_t XNUMA::count() { - return 1; -} - -uint32_t XNUMA::id() { - return 0; -} - -uint32_t XNUMA::memory_id(uintptr_t addr) { - // NUMA support not enabled, assume everything belongs to node zero - return 0; -} diff --git a/src/hotspot/os/windows/gc/x/xPhysicalMemoryBacking_windows.cpp b/src/hotspot/os/windows/gc/x/xPhysicalMemoryBacking_windows.cpp deleted file mode 100644 index 92d47dfb7c84c..0000000000000 --- a/src/hotspot/os/windows/gc/x/xPhysicalMemoryBacking_windows.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xGranuleMap.inline.hpp" -#include "gc/x/xLargePages.inline.hpp" -#include "gc/x/xMapper_windows.hpp" -#include "gc/x/xPhysicalMemoryBacking_windows.hpp" -#include "logging/log.hpp" -#include "runtime/globals.hpp" -#include "utilities/debug.hpp" - -class XPhysicalMemoryBackingImpl : public CHeapObj { -public: - virtual size_t commit(size_t offset, size_t size) = 0; - virtual size_t uncommit(size_t offset, size_t size) = 0; - virtual void map(uintptr_t addr, size_t size, size_t offset) const = 0; - virtual void unmap(uintptr_t addr, size_t size) const = 0; -}; - -// Implements small pages (paged) support using placeholder reservation. -// -// The backing commits and uncommits physical memory, that can be -// multi-mapped into the virtual address space. To support fine-graned -// committing and uncommitting, each XGranuleSize'd chunk is mapped to -// a separate paging file mapping. - -class XPhysicalMemoryBackingSmallPages : public XPhysicalMemoryBackingImpl { -private: - XGranuleMap _handles; - - HANDLE get_handle(uintptr_t offset) const { - HANDLE const handle = _handles.get(offset); - assert(handle != 0, "Should be set"); - return handle; - } - - void put_handle(uintptr_t offset, HANDLE handle) { - assert(handle != INVALID_HANDLE_VALUE, "Invalid handle"); - assert(_handles.get(offset) == 0, "Should be cleared"); - _handles.put(offset, handle); - } - - void clear_handle(uintptr_t offset) { - assert(_handles.get(offset) != 0, "Should be set"); - _handles.put(offset, 0); - } - -public: - XPhysicalMemoryBackingSmallPages(size_t max_capacity) : - XPhysicalMemoryBackingImpl(), - _handles(max_capacity) {} - - size_t commit(size_t offset, size_t size) { - for (size_t i = 0; i < size; i += XGranuleSize) { - HANDLE const handle = XMapper::create_and_commit_paging_file_mapping(XGranuleSize); - if (handle == 0) { - return i; - } - - put_handle(offset + i, handle); - } - - return size; - } - - size_t uncommit(size_t offset, size_t size) { - for (size_t i = 0; i < size; i += XGranuleSize) { - HANDLE const handle = get_handle(offset + i); - clear_handle(offset + i); - XMapper::close_paging_file_mapping(handle); - } - - return size; - } - - void map(uintptr_t addr, size_t size, size_t offset) const { - assert(is_aligned(offset, XGranuleSize), "Misaligned"); - assert(is_aligned(addr, XGranuleSize), "Misaligned"); - assert(is_aligned(size, XGranuleSize), "Misaligned"); - - for (size_t i = 0; i < size; i += XGranuleSize) { - HANDLE const handle = get_handle(offset + i); - XMapper::map_view_replace_placeholder(handle, 0 /* offset */, addr + i, XGranuleSize); - } - } - - void unmap(uintptr_t addr, size_t size) const { - assert(is_aligned(addr, XGranuleSize), "Misaligned"); - assert(is_aligned(size, XGranuleSize), "Misaligned"); - - for (size_t i = 0; i < size; i += XGranuleSize) { - XMapper::unmap_view_preserve_placeholder(addr + i, XGranuleSize); - } - } -}; - -// Implements Large Pages (locked) support using shared AWE physical memory. -// -// Shared AWE physical memory also works with small pages, but it has -// a few drawbacks that makes it a no-go to use it at this point: -// -// 1) It seems to use 8 bytes of committed memory per *reserved* memory. -// Given our scheme to use a large address space range this turns out to -// use too much memory. -// -// 2) It requires memory locking privileges, even for small pages. This -// has always been a requirement for large pages, and would be an extra -// restriction for usage with small pages. -// -// Note: The large pages size is tied to our XGranuleSize. - -extern HANDLE XAWESection; - -class XPhysicalMemoryBackingLargePages : public XPhysicalMemoryBackingImpl { -private: - ULONG_PTR* const _page_array; - - static ULONG_PTR* alloc_page_array(size_t max_capacity) { - const size_t npages = max_capacity / XGranuleSize; - const size_t array_size = npages * sizeof(ULONG_PTR); - - return (ULONG_PTR*)os::malloc(array_size, mtGC); - } - -public: - XPhysicalMemoryBackingLargePages(size_t max_capacity) : - XPhysicalMemoryBackingImpl(), - _page_array(alloc_page_array(max_capacity)) {} - - size_t commit(size_t offset, size_t size) { - const size_t index = offset >> XGranuleSizeShift; - const size_t npages = size >> XGranuleSizeShift; - - size_t npages_res = npages; - const bool res = AllocateUserPhysicalPages(XAWESection, &npages_res, &_page_array[index]); - if (!res) { - fatal("Failed to allocate physical memory " SIZE_FORMAT "M @ " PTR_FORMAT " (%d)", - size / M, offset, GetLastError()); - } else { - log_debug(gc)("Allocated physical memory: " SIZE_FORMAT "M @ " PTR_FORMAT, size / M, offset); - } - - // AllocateUserPhysicalPages might not be able to allocate the requested amount of memory. - // The allocated number of pages are written in npages_res. - return npages_res << XGranuleSizeShift; - } - - size_t uncommit(size_t offset, size_t size) { - const size_t index = offset >> XGranuleSizeShift; - const size_t npages = size >> XGranuleSizeShift; - - size_t npages_res = npages; - const bool res = FreeUserPhysicalPages(XAWESection, &npages_res, &_page_array[index]); - if (!res) { - fatal("Failed to uncommit physical memory " SIZE_FORMAT "M @ " PTR_FORMAT " (%d)", - size, offset, GetLastError()); - } - - return npages_res << XGranuleSizeShift; - } - - void map(uintptr_t addr, size_t size, size_t offset) const { - const size_t npages = size >> XGranuleSizeShift; - const size_t index = offset >> XGranuleSizeShift; - - const bool res = MapUserPhysicalPages((char*)addr, npages, &_page_array[index]); - if (!res) { - fatal("Failed to map view " PTR_FORMAT " " SIZE_FORMAT "M @ " PTR_FORMAT " (%d)", - addr, size / M, offset, GetLastError()); - } - } - - void unmap(uintptr_t addr, size_t size) const { - const size_t npages = size >> XGranuleSizeShift; - - const bool res = MapUserPhysicalPages((char*)addr, npages, nullptr); - if (!res) { - fatal("Failed to unmap view " PTR_FORMAT " " SIZE_FORMAT "M (%d)", - addr, size / M, GetLastError()); - } - } -}; - -static XPhysicalMemoryBackingImpl* select_impl(size_t max_capacity) { - if (XLargePages::is_enabled()) { - return new XPhysicalMemoryBackingLargePages(max_capacity); - } - - return new XPhysicalMemoryBackingSmallPages(max_capacity); -} - -XPhysicalMemoryBacking::XPhysicalMemoryBacking(size_t max_capacity) : - _impl(select_impl(max_capacity)) {} - -bool XPhysicalMemoryBacking::is_initialized() const { - return true; -} - -void XPhysicalMemoryBacking::warn_commit_limits(size_t max_capacity) const { - // Does nothing -} - -size_t XPhysicalMemoryBacking::commit(size_t offset, size_t length) { - log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", - offset / M, (offset + length) / M, length / M); - - return _impl->commit(offset, length); -} - -size_t XPhysicalMemoryBacking::uncommit(size_t offset, size_t length) { - log_trace(gc, heap)("Uncommitting memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", - offset / M, (offset + length) / M, length / M); - - return _impl->uncommit(offset, length); -} - -void XPhysicalMemoryBacking::map(uintptr_t addr, size_t size, size_t offset) const { - assert(is_aligned(offset, XGranuleSize), "Misaligned: " PTR_FORMAT, offset); - assert(is_aligned(addr, XGranuleSize), "Misaligned: " PTR_FORMAT, addr); - assert(is_aligned(size, XGranuleSize), "Misaligned: " PTR_FORMAT, size); - - _impl->map(addr, size, offset); -} - -void XPhysicalMemoryBacking::unmap(uintptr_t addr, size_t size) const { - assert(is_aligned(addr, XGranuleSize), "Misaligned"); - assert(is_aligned(size, XGranuleSize), "Misaligned"); - - _impl->unmap(addr, size); -} diff --git a/src/hotspot/os/windows/gc/x/xPhysicalMemoryBacking_windows.hpp b/src/hotspot/os/windows/gc/x/xPhysicalMemoryBacking_windows.hpp deleted file mode 100644 index d6e123f21e51a..0000000000000 --- a/src/hotspot/os/windows/gc/x/xPhysicalMemoryBacking_windows.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef OS_WINDOWS_GC_X_XPHYSICALMEMORYBACKING_WINDOWS_HPP -#define OS_WINDOWS_GC_X_XPHYSICALMEMORYBACKING_WINDOWS_HPP - -#include "utilities/globalDefinitions.hpp" - -#include - -class XPhysicalMemoryBackingImpl; - -class XPhysicalMemoryBacking { -private: - XPhysicalMemoryBackingImpl* _impl; - -public: - XPhysicalMemoryBacking(size_t max_capacity); - - bool is_initialized() const; - - void warn_commit_limits(size_t max_capacity) const; - - size_t commit(size_t offset, size_t length); - size_t uncommit(size_t offset, size_t length); - - void map(uintptr_t addr, size_t size, size_t offset) const; - void unmap(uintptr_t addr, size_t size) const; -}; - -#endif // OS_WINDOWS_GC_X_XPHYSICALMEMORYBACKING_WINDOWS_HPP diff --git a/src/hotspot/os/windows/gc/x/xSyscall_windows.cpp b/src/hotspot/os/windows/gc/x/xSyscall_windows.cpp deleted file mode 100644 index f22966a54898d..0000000000000 --- a/src/hotspot/os/windows/gc/x/xSyscall_windows.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xSyscall_windows.hpp" -#include "runtime/java.hpp" -#include "runtime/os.hpp" - -XSyscall::CreateFileMappingWFn XSyscall::CreateFileMappingW; -XSyscall::CreateFileMapping2Fn XSyscall::CreateFileMapping2; -XSyscall::VirtualAlloc2Fn XSyscall::VirtualAlloc2; -XSyscall::VirtualFreeExFn XSyscall::VirtualFreeEx; -XSyscall::MapViewOfFile3Fn XSyscall::MapViewOfFile3; -XSyscall::UnmapViewOfFile2Fn XSyscall::UnmapViewOfFile2; - -static void* lookup_kernelbase_library() { - const char* const name = "KernelBase"; - char ebuf[1024]; - void* const handle = os::dll_load(name, ebuf, sizeof(ebuf)); - if (handle == nullptr) { - log_error_p(gc)("Failed to load library: %s", name); - } - return handle; -} - -static void* lookup_kernelbase_symbol(const char* name) { - static void* const handle = lookup_kernelbase_library(); - if (handle == nullptr) { - return nullptr; - } - return os::dll_lookup(handle, name); -} - -static bool has_kernelbase_symbol(const char* name) { - return lookup_kernelbase_symbol(name) != nullptr; -} - -template -static void install_kernelbase_symbol(Fn*& fn, const char* name) { - fn = reinterpret_cast(lookup_kernelbase_symbol(name)); -} - -template -static void install_kernelbase_1803_symbol_or_exit(Fn*& fn, const char* name) { - install_kernelbase_symbol(fn, name); - if (fn == nullptr) { - log_error_p(gc)("Failed to lookup symbol: %s", name); - vm_exit_during_initialization("ZGC requires Windows version 1803 or later"); - } -} - -void XSyscall::initialize() { - // Required - install_kernelbase_1803_symbol_or_exit(CreateFileMappingW, "CreateFileMappingW"); - install_kernelbase_1803_symbol_or_exit(VirtualAlloc2, "VirtualAlloc2"); - install_kernelbase_1803_symbol_or_exit(VirtualFreeEx, "VirtualFreeEx"); - install_kernelbase_1803_symbol_or_exit(MapViewOfFile3, "MapViewOfFile3"); - install_kernelbase_1803_symbol_or_exit(UnmapViewOfFile2, "UnmapViewOfFile2"); - - // Optional - for large pages support - install_kernelbase_symbol(CreateFileMapping2, "CreateFileMapping2"); -} - -bool XSyscall::is_supported() { - // Available in Windows version 1803 and later - return has_kernelbase_symbol("VirtualAlloc2"); -} - -bool XSyscall::is_large_pages_supported() { - // Available in Windows version 1809 and later - return has_kernelbase_symbol("CreateFileMapping2"); -} diff --git a/src/hotspot/os/windows/gc/x/xSyscall_windows.hpp b/src/hotspot/os/windows/gc/x/xSyscall_windows.hpp deleted file mode 100644 index 89ba2573b10cc..0000000000000 --- a/src/hotspot/os/windows/gc/x/xSyscall_windows.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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 - * 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 OS_WINDOWS_GC_X_XSYSCALL_WINDOWS_HPP -#define OS_WINDOWS_GC_X_XSYSCALL_WINDOWS_HPP - -#include "utilities/globalDefinitions.hpp" - -#include -#include - -class XSyscall { -private: - typedef HANDLE (*CreateFileMappingWFn)(HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCWSTR); - typedef HANDLE (*CreateFileMapping2Fn)(HANDLE, LPSECURITY_ATTRIBUTES, ULONG, ULONG, ULONG, ULONG64, PCWSTR, PMEM_EXTENDED_PARAMETER, ULONG); - typedef PVOID (*VirtualAlloc2Fn)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG); - typedef BOOL (*VirtualFreeExFn)(HANDLE, LPVOID, SIZE_T, DWORD); - typedef PVOID (*MapViewOfFile3Fn)(HANDLE, HANDLE, PVOID, ULONG64, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG); - typedef BOOL (*UnmapViewOfFile2Fn)(HANDLE, PVOID, ULONG); - -public: - static CreateFileMappingWFn CreateFileMappingW; - static CreateFileMapping2Fn CreateFileMapping2; - static VirtualAlloc2Fn VirtualAlloc2; - static VirtualFreeExFn VirtualFreeEx; - static MapViewOfFile3Fn MapViewOfFile3; - static UnmapViewOfFile2Fn UnmapViewOfFile2; - - static void initialize(); - - static bool is_supported(); - static bool is_large_pages_supported(); -}; - -#endif // OS_WINDOWS_GC_X_XSYSCALL_WINDOWS_HPP diff --git a/src/hotspot/os/windows/gc/x/xUtils_windows.cpp b/src/hotspot/os/windows/gc/x/xUtils_windows.cpp deleted file mode 100644 index 788da80834ab3..0000000000000 --- a/src/hotspot/os/windows/gc/x/xUtils_windows.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xUtils.hpp" -#include "utilities/debug.hpp" - -#include - -uintptr_t XUtils::alloc_aligned(size_t alignment, size_t size) { - void* const res = _aligned_malloc(size, alignment); - - if (res == nullptr) { - fatal("_aligned_malloc failed"); - } - - memset(res, 0, size); - - return (uintptr_t)res; -} diff --git a/src/hotspot/os/windows/gc/x/xVirtualMemory_windows.cpp b/src/hotspot/os/windows/gc/x/xVirtualMemory_windows.cpp deleted file mode 100644 index a54f1e3cbaefc..0000000000000 --- a/src/hotspot/os/windows/gc/x/xVirtualMemory_windows.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xLargePages.inline.hpp" -#include "gc/x/xMapper_windows.hpp" -#include "gc/x/xSyscall_windows.hpp" -#include "gc/x/xVirtualMemory.inline.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" - -class XVirtualMemoryManagerImpl : public CHeapObj { -public: - virtual void initialize_before_reserve() {} - virtual void initialize_after_reserve(XMemoryManager* manager) {} - virtual bool reserve(uintptr_t addr, size_t size) = 0; - virtual void unreserve(uintptr_t addr, size_t size) = 0; -}; - -// Implements small pages (paged) support using placeholder reservation. -class XVirtualMemoryManagerSmallPages : public XVirtualMemoryManagerImpl { -private: - class PlaceholderCallbacks : public AllStatic { - public: - static void split_placeholder(uintptr_t start, size_t size) { - XMapper::split_placeholder(XAddress::marked0(start), size); - XMapper::split_placeholder(XAddress::marked1(start), size); - XMapper::split_placeholder(XAddress::remapped(start), size); - } - - static void coalesce_placeholders(uintptr_t start, size_t size) { - XMapper::coalesce_placeholders(XAddress::marked0(start), size); - XMapper::coalesce_placeholders(XAddress::marked1(start), size); - XMapper::coalesce_placeholders(XAddress::remapped(start), size); - } - - static void split_into_placeholder_granules(uintptr_t start, size_t size) { - for (uintptr_t addr = start; addr < start + size; addr += XGranuleSize) { - split_placeholder(addr, XGranuleSize); - } - } - - static void coalesce_into_one_placeholder(uintptr_t start, size_t size) { - assert(is_aligned(size, XGranuleSize), "Must be granule aligned"); - - if (size > XGranuleSize) { - coalesce_placeholders(start, size); - } - } - - static void create_callback(const XMemory* area) { - assert(is_aligned(area->size(), XGranuleSize), "Must be granule aligned"); - coalesce_into_one_placeholder(area->start(), area->size()); - } - - static void destroy_callback(const XMemory* area) { - assert(is_aligned(area->size(), XGranuleSize), "Must be granule aligned"); - // Don't try split the last granule - VirtualFree will fail - split_into_placeholder_granules(area->start(), area->size() - XGranuleSize); - } - - static void shrink_from_front_callback(const XMemory* area, size_t size) { - assert(is_aligned(size, XGranuleSize), "Must be granule aligned"); - split_into_placeholder_granules(area->start(), size); - } - - static void shrink_from_back_callback(const XMemory* area, size_t size) { - assert(is_aligned(size, XGranuleSize), "Must be granule aligned"); - // Don't try split the last granule - VirtualFree will fail - split_into_placeholder_granules(area->end() - size, size - XGranuleSize); - } - - static void grow_from_front_callback(const XMemory* area, size_t size) { - assert(is_aligned(area->size(), XGranuleSize), "Must be granule aligned"); - coalesce_into_one_placeholder(area->start() - size, area->size() + size); - } - - static void grow_from_back_callback(const XMemory* area, size_t size) { - assert(is_aligned(area->size(), XGranuleSize), "Must be granule aligned"); - coalesce_into_one_placeholder(area->start(), area->size() + size); - } - - static void register_with(XMemoryManager* manager) { - // Each reserved virtual memory address area registered in _manager is - // exactly covered by a single placeholder. Callbacks are installed so - // that whenever a memory area changes, the corresponding placeholder - // is adjusted. - // - // The create and grow callbacks are called when virtual memory is - // returned to the memory manager. The new memory area is then covered - // by a new single placeholder. - // - // The destroy and shrink callbacks are called when virtual memory is - // allocated from the memory manager. The memory area is then is split - // into granule-sized placeholders. - // - // See comment in zMapper_windows.cpp explaining why placeholders are - // split into XGranuleSize sized placeholders. - - XMemoryManager::Callbacks callbacks; - - callbacks._create = &create_callback; - callbacks._destroy = &destroy_callback; - callbacks._shrink_from_front = &shrink_from_front_callback; - callbacks._shrink_from_back = &shrink_from_back_callback; - callbacks._grow_from_front = &grow_from_front_callback; - callbacks._grow_from_back = &grow_from_back_callback; - - manager->register_callbacks(callbacks); - } - }; - - virtual void initialize_after_reserve(XMemoryManager* manager) { - PlaceholderCallbacks::register_with(manager); - } - - virtual bool reserve(uintptr_t addr, size_t size) { - const uintptr_t res = XMapper::reserve(addr, size); - - assert(res == addr || res == 0, "Should not reserve other memory than requested"); - return res == addr; - } - - virtual void unreserve(uintptr_t addr, size_t size) { - XMapper::unreserve(addr, size); - } -}; - -// Implements Large Pages (locked) support using shared AWE physical memory. - -// XPhysicalMemory layer needs access to the section -HANDLE XAWESection; - -class XVirtualMemoryManagerLargePages : public XVirtualMemoryManagerImpl { -private: - virtual void initialize_before_reserve() { - XAWESection = XMapper::create_shared_awe_section(); - } - - virtual bool reserve(uintptr_t addr, size_t size) { - const uintptr_t res = XMapper::reserve_for_shared_awe(XAWESection, addr, size); - - assert(res == addr || res == 0, "Should not reserve other memory than requested"); - return res == addr; - } - - virtual void unreserve(uintptr_t addr, size_t size) { - XMapper::unreserve_for_shared_awe(addr, size); - } -}; - -static XVirtualMemoryManagerImpl* _impl = nullptr; - -void XVirtualMemoryManager::pd_initialize_before_reserve() { - if (XLargePages::is_enabled()) { - _impl = new XVirtualMemoryManagerLargePages(); - } else { - _impl = new XVirtualMemoryManagerSmallPages(); - } - _impl->initialize_before_reserve(); -} - -void XVirtualMemoryManager::pd_initialize_after_reserve() { - _impl->initialize_after_reserve(&_manager); -} - -bool XVirtualMemoryManager::pd_reserve(uintptr_t addr, size_t size) { - return _impl->reserve(addr, size); -} - -void XVirtualMemoryManager::pd_unreserve(uintptr_t addr, size_t size) { - _impl->unreserve(addr, size); -} diff --git a/src/hotspot/os/windows/globals_windows.hpp b/src/hotspot/os/windows/globals_windows.hpp index 78cbac6e9ccc5..8f0a6261cc0db 100644 --- a/src/hotspot/os/windows/globals_windows.hpp +++ b/src/hotspot/os/windows/globals_windows.hpp @@ -38,6 +38,10 @@ product(bool, UseAllWindowsProcessorGroups, false, \ "Use all processor groups on supported Windows versions") \ \ +product(bool, EnableAllLargePageSizesForWindows, false, \ + "Enable support for multiple large page sizes on " \ + "Windows Server") \ + \ product(bool, UseOSErrorReporting, false, \ "Let VM fatal error propagate to the OS (ie. WER on Windows)") diff --git a/src/hotspot/os/windows/osThread_windows.cpp b/src/hotspot/os/windows/osThread_windows.cpp index 5f369bb7aa05b..922b4b0104be4 100644 --- a/src/hotspot/os/windows/osThread_windows.cpp +++ b/src/hotspot/os/windows/osThread_windows.cpp @@ -22,17 +22,17 @@ * */ -// no precompiled headers -#include "runtime/os.hpp" +#include "precompiled.hpp" #include "runtime/osThread.hpp" -void OSThread::pd_initialize() { - set_thread_handle(nullptr); - set_thread_id(0); - set_interrupt_event(nullptr); -} +#include + +OSThread::OSThread() + : _thread_id(0), + _thread_handle(nullptr), + _interrupt_event(nullptr) {} -void OSThread::pd_destroy() { +OSThread::~OSThread() { if (_interrupt_event != nullptr) { CloseHandle(_interrupt_event); } diff --git a/src/hotspot/os/windows/osThread_windows.hpp b/src/hotspot/os/windows/osThread_windows.hpp index 5bd07646b1718..e54783aef1c15 100644 --- a/src/hotspot/os/windows/osThread_windows.hpp +++ b/src/hotspot/os/windows/osThread_windows.hpp @@ -25,17 +25,29 @@ #ifndef OS_WINDOWS_OSTHREAD_WINDOWS_HPP #define OS_WINDOWS_OSTHREAD_WINDOWS_HPP - typedef void* HANDLE; - public: +#include "runtime/osThreadBase.hpp" +#include "utilities/globalDefinitions.hpp" + +class OSThread : public OSThreadBase { + friend class VMStructs; + typedef unsigned long thread_id_t; + typedef void* HANDLE; + + thread_id_t _thread_id; - private: // Win32-specific thread information HANDLE _thread_handle; // Win32 thread handle HANDLE _interrupt_event; // Event signalled on thread interrupt for use by // Process.waitFor(). public: + OSThread(); + ~OSThread(); + + thread_id_t thread_id() const { return _thread_id; } + void set_thread_id(thread_id_t id) { _thread_id = id; } + // The following will only apply in the Win32 implementation, and should only // be visible in the concrete class, not this which should be an abstract base class HANDLE thread_handle() const { return _thread_handle; } @@ -45,13 +57,9 @@ // This is specialized on Windows to interact with the _interrupt_event. void set_interrupted(bool z); -#ifndef PRODUCT - // Used for debugging, return a unique integer for each thread. - int thread_identifier() const { return _thread_id; } -#endif - - private: - void pd_initialize(); - void pd_destroy(); + uintx thread_id_for_printing() const override { + return (uintx)_thread_id; + } +}; #endif // OS_WINDOWS_OSTHREAD_WINDOWS_HPP diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 817757f1ac6a2..71efb57e0f2c5 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -63,6 +63,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/statSampler.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/suspendedThreadTask.hpp" #include "runtime/threadCritical.hpp" #include "runtime/threads.hpp" #include "runtime/timer.hpp" @@ -1286,38 +1287,50 @@ void os::shutdown() { static HANDLE dumpFile = nullptr; -// Check if dump file can be created. -void os::check_dump_limit(char* buffer, size_t buffsz) { - bool status = true; +// Check if core dump is active and if a core dump file can be created +void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) { if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) { - jio_snprintf(buffer, buffsz, "CreateCoredumpOnCrash is disabled from command line"); - status = false; - } - + jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line"); + VMError::record_coredump_status(buffer, false); + } else { + bool success = true; + bool warn = true; #ifndef ASSERT - if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) { - jio_snprintf(buffer, buffsz, "Minidumps are not enabled by default on client versions of Windows"); - status = false; - } + if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) { + jio_snprintf(buffer, bufferSize, "Minidumps are not enabled by default on client versions of Windows"); + success = false; + warn = true; + } #endif - if (status) { - const char* cwd = get_current_directory(nullptr, 0); - int pid = current_process_id(); - if (cwd != nullptr) { - jio_snprintf(buffer, buffsz, "%s\\hs_err_pid%u.mdmp", cwd, pid); - } else { - jio_snprintf(buffer, buffsz, ".\\hs_err_pid%u.mdmp", pid); + if (success) { + if (!check_only) { + const char* cwd = get_current_directory(nullptr, 0); + int pid = current_process_id(); + if (cwd != nullptr) { + jio_snprintf(buffer, bufferSize, "%s\\hs_err_pid%u.mdmp", cwd, pid); + } else { + jio_snprintf(buffer, bufferSize, ".\\hs_err_pid%u.mdmp", pid); + } + + if (dumpFile == nullptr && + (dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)) + == INVALID_HANDLE_VALUE) { + jio_snprintf(buffer, bufferSize, "Failed to create minidump file (0x%x).", GetLastError()); + success = false; + } + } else { + // For now on Windows, there are no more checks that we can do + warn = false; + } } - if (dumpFile == nullptr && - (dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)) - == INVALID_HANDLE_VALUE) { - jio_snprintf(buffer, buffsz, "Failed to create minidump file (0x%x).", GetLastError()); - status = false; + if (!check_only) { + VMError::record_coredump_status(buffer, success); + } else if (warn) { + warning("CreateCoredumpOnCrash specified, but %s", buffer); } } - VMError::record_coredump_status(buffer, status); } void os::abort(bool dump_core, void* siginfo, const void* context) { @@ -3126,7 +3139,7 @@ class NUMANodeListHolder { static size_t _large_page_size = 0; -static bool request_lock_memory_privilege() { +bool os::win32::request_lock_memory_privilege() { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, os::current_process_id()); @@ -3310,14 +3323,14 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, return p_buf; } -static size_t large_page_init_decide_size() { +size_t os::win32::large_page_init_decide_size() { // print a warning if any large page related flag is specified on command line bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) || !FLAG_IS_DEFAULT(LargePageSizeInBytes); -#define WARN(msg) if (warn_on_failure) { warning(msg); } +#define WARN(...) if (warn_on_failure) { warning(__VA_ARGS__); } - if (!request_lock_memory_privilege()) { + if (!os::win32::request_lock_memory_privilege()) { WARN("JVM cannot use large page memory because it does not have enough privilege to lock pages in memory."); return 0; } @@ -3328,15 +3341,26 @@ static size_t large_page_init_decide_size() { return 0; } -#if defined(IA32) || defined(AMD64) - if (size > 4*M || LargePageSizeInBytes > 4*M) { +#if defined(IA32) + if (size > 4 * M || LargePageSizeInBytes > 4 * M) { WARN("JVM cannot use large pages bigger than 4mb."); return 0; } +#elif defined(AMD64) + if (!EnableAllLargePageSizesForWindows) { + if (size > 4 * M || LargePageSizeInBytes > 4 * M) { + WARN("JVM cannot use large pages bigger than 4mb."); + return 0; + } + } #endif - if (LargePageSizeInBytes > 0 && LargePageSizeInBytes % size == 0) { - size = LargePageSizeInBytes; + if (LargePageSizeInBytes > 0) { + if (LargePageSizeInBytes % size == 0) { + size = LargePageSizeInBytes; + } else { + WARN("The specified large page size (%d) is not a multiple of the minimum large page size (%d), defaulting to minimum page size.", LargePageSizeInBytes, size); + } } #undef WARN @@ -3349,12 +3373,23 @@ void os::large_page_init() { return; } - _large_page_size = large_page_init_decide_size(); + _large_page_size = os::win32::large_page_init_decide_size(); const size_t default_page_size = os::vm_page_size(); if (_large_page_size > default_page_size) { +#if !defined(IA32) + if (EnableAllLargePageSizesForWindows) { + size_t min_size = GetLargePageMinimum(); + + // Populate _page_sizes with large page sizes less than or equal to _large_page_size, ensuring each page size is double the size of the previous one. + for (size_t page_size = min_size; page_size < _large_page_size; page_size *= 2) { + _page_sizes.add(page_size); + } + } +#endif + _page_sizes.add(_large_page_size); } - + // Set UseLargePages based on whether a large page size was successfully determined UseLargePages = _large_page_size != 0; } @@ -3618,7 +3653,6 @@ static char* reserve_large_pages_aligned(size_t size, size_t alignment, bool exe char* os::pd_reserve_memory_special(size_t bytes, size_t alignment, size_t page_size, char* addr, bool exec) { assert(UseLargePages, "only for large pages"); - assert(page_size == os::large_page_size(), "Currently only support one large page size on Windows"); assert(is_aligned(addr, alignment), "Must be"); assert(is_aligned(addr, page_size), "Must be"); @@ -3627,11 +3661,17 @@ char* os::pd_reserve_memory_special(size_t bytes, size_t alignment, size_t page_ return nullptr; } + // Ensure GetLargePageMinimum() returns a valid positive value + size_t large_page_min = GetLargePageMinimum(); + if (large_page_min <= 0) { + return nullptr; + } + // The requested alignment can be larger than the page size, for example with G1 // the alignment is bound to the heap region size. So this reservation needs to // ensure that the requested alignment is met. When there is a requested address // this solves it self, since it must be properly aligned already. - if (addr == nullptr && alignment > page_size) { + if (addr == nullptr && alignment > large_page_min) { return reserve_large_pages_aligned(bytes, alignment, exec); } @@ -3785,7 +3825,8 @@ bool os::pd_release_memory(char* addr, size_t bytes) { if (err != nullptr) { log_warning(os)("bad release: [" PTR_FORMAT "-" PTR_FORMAT "): %s", p2i(start), p2i(end), err); #ifdef ASSERT - os::print_memory_mappings((char*)start, bytes, tty); + fileStream fs(stdout); + os::print_memory_mappings((char*)start, bytes, &fs); assert(false, "bad release: [" PTR_FORMAT "-" PTR_FORMAT "): %s", p2i(start), p2i(end), err); #endif return false; @@ -5357,6 +5398,28 @@ void os::funlockfile(FILE* fp) { _unlock_file(fp); } +char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { + + if (filename == nullptr || outbuf == nullptr || outbuflen < 1) { + assert(false, "os::realpath: invalid arguments."); + errno = EINVAL; + return nullptr; + } + + char* result = nullptr; + ALLOW_C_FUNCTION(::_fullpath, char* p = ::_fullpath(nullptr, filename, 0);) + if (p != nullptr) { + if (strlen(p) < outbuflen) { + strcpy(outbuf, p); + result = outbuf; + } else { + errno = ENAMETOOLONG; + } + ALLOW_C_FUNCTION(::free, ::free(p);) // *not* os::free + } + return result; +} + // Map a block of memory. char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only, @@ -5691,7 +5754,15 @@ void PlatformEvent::park() { // TODO: consider a brief spin here, gated on the success of recent // spin attempts by this thread. while (_Event < 0) { + // The following code is only here to maintain the + // characteristics/performance from when an ObjectMonitor + // "responsible" thread used to issue timed parks. + HighResolutionInterval *phri = nullptr; + if (!ForceTimeHighResolution) { + phri = new HighResolutionInterval((jlong)1); + } DWORD rv = ::WaitForSingleObject(_ParkHandle, INFINITE); + delete phri; // if it is null, harmless assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", rv); } @@ -5965,7 +6036,7 @@ static void do_resume(HANDLE* h) { // retrieve a suspend/resume context capable handle // from the tid. Caller validates handle return value. void get_thread_handle_for_extended_context(HANDLE* h, - OSThread::thread_id_t tid) { + DWORD tid) { if (h != nullptr) { *h = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, tid); } diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index 3bc5ab9eef1f3..1d5237243000b 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -65,6 +65,8 @@ class os::win32 { static void setmode_streams(); static bool is_windows_11_or_greater(); static bool is_windows_server_2022_or_greater(); + static bool request_lock_memory_privilege(); + static size_t large_page_init_decide_size(); static int windows_major_version() { assert(_major_version > 0, "windows version not initialized."); return _major_version; diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index 06b057315cbdd..959be982fabbe 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -1803,7 +1803,7 @@ void PerfMemory::detach(char* addr, size_t bytes) { if (MemTracker::enabled()) { // it does not go through os api, the operation has to record from here - ThreadCritical tc; + NmtVirtualMemoryLocker ml; remove_file_mapping(addr); MemTracker::record_virtual_memory_release((address)addr, bytes); } else { diff --git a/src/hotspot/os/windows/vmStructs_windows.hpp b/src/hotspot/os/windows/vmStructs_windows.hpp index 2550e685f16e2..93f4ea7c8111d 100644 --- a/src/hotspot/os/windows/vmStructs_windows.hpp +++ b/src/hotspot/os/windows/vmStructs_windows.hpp @@ -29,9 +29,18 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + \ + /******************************/ \ + /* Threads (NOTE: incomplete) */ \ + /******************************/ \ + \ + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ + unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */ + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + \ + declare_unsigned_integer_type(OSThread::thread_id_t) #define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index b45d38650c076..f83aa6030622a 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -462,12 +462,6 @@ void os::print_tos_pc(outputStream *st, const void *context) { address pc = os::Posix::ucontext_get_pc(uc); print_instructions(st, pc); st->cr(); - - // Try to decode the instructions. - st->print_cr("Decoded instructions: (pc=" PTR_FORMAT ")", p2i(pc)); - st->print(""); - // TODO: PPC port Disassembler::decode(pc, 16, 16, st); - st->cr(); } void os::print_register_info(outputStream *st, const void *context, int& continuation) { diff --git a/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp b/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp index 157d57f8e0fa2..123cd67248f86 100644 --- a/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp +++ b/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp @@ -30,21 +30,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, pthread_t) \ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp b/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp index 07b878106cfcd..c384afac7ecff 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp +++ b/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp @@ -31,22 +31,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _unique_thread_id, uint64_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp index fb43541fa775a..b48ea82712ecd 100644 --- a/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp @@ -29,22 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _unique_thread_id, uint64_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S index 2724e78862de3..b3e7f64397970 100644 --- a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S @@ -26,6 +26,7 @@ .align 5 DECLARE_FUNC(aarch64_atomic_fetch_add_8_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS ldaddal x1, x2, [x0] #else @@ -41,6 +42,7 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_8_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_fetch_add_4_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS ldaddal w1, w2, [x0] #else @@ -56,8 +58,9 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_4_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_fetch_add_8_relaxed_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS - ldadd x1, x2, [x0] + ldadd x1, x2, [x0] #else prfm pstl1strm, [x0] 0: ldxr x2, [x0] @@ -70,8 +73,9 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_8_relaxed_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_fetch_add_4_relaxed_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS - ldadd w1, w2, [x0] + ldadd w1, w2, [x0] #else prfm pstl1strm, [x0] 0: ldxr w2, [x0] @@ -84,6 +88,7 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_4_relaxed_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_xchg_4_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS swpal w1, w2, [x0] #else @@ -98,6 +103,7 @@ DECLARE_FUNC(aarch64_atomic_xchg_4_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_xchg_8_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS swpal x1, x2, [x0] #else @@ -112,6 +118,7 @@ DECLARE_FUNC(aarch64_atomic_xchg_8_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_cmpxchg_1_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casalb w3, w2, [x0] @@ -131,6 +138,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_1_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_cmpxchg_4_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casal w3, w2, [x0] @@ -149,6 +157,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_cmpxchg_8_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casal x3, x2, [x0] @@ -167,6 +176,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_cmpxchg_4_release_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casl w3, w2, [x0] @@ -183,6 +193,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_release_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_cmpxchg_8_release_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casl x3, x2, [x0] @@ -199,6 +210,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_release_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_cmpxchg_4_seq_cst_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casal w3, w2, [x0] @@ -215,6 +227,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_seq_cst_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_cmpxchg_8_seq_cst_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casal x3, x2, [x0] @@ -231,6 +244,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_seq_cst_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_cmpxchg_1_relaxed_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casb w3, w2, [x0] @@ -248,6 +262,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_1_relaxed_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_cmpxchg_4_relaxed_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 cas w3, w2, [x0] @@ -264,6 +279,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_relaxed_default_impl): .align 5 DECLARE_FUNC(aarch64_atomic_cmpxchg_8_relaxed_default_impl): + hint #0x22 // bti c #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 cas x3, x2, [x0] @@ -277,3 +293,35 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_relaxed_default_impl): #endif 1: mov x0, x3 ret + +/* Emit .note.gnu.property section in case of PAC or BTI being enabled. + * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)". + * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst + */ +#ifdef __ARM_FEATURE_BTI_DEFAULT + #ifdef __ARM_FEATURE_PAC_DEFAULT + #define GNU_PROPERTY_AARCH64_FEATURE 3 + #else + #define GNU_PROPERTY_AARCH64_FEATURE 1 + #endif +#else + #ifdef __ARM_FEATURE_PAC_DEFAULT + #define GNU_PROPERTY_AARCH64_FEATURE 2 + #else + #define GNU_PROPERTY_AARCH64_FEATURE 0 + #endif +#endif + +#if (GNU_PROPERTY_AARCH64_FEATURE != 0) + .pushsection .note.gnu.property, "a" + .align 3 + .long 4 /* name length */ + .long 0x10 /* data length */ + .long 5 /* note type: NT_GNU_PROPERTY_TYPE_0 */ + .string "GNU" /* vendor name */ + .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ + .long 4 /* pr_datasze */ + .long GNU_PROPERTY_AARCH64_FEATURE + .long 0 + .popsection +#endif diff --git a/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S index f9702d5e55419..33fe81d920653 100644 --- a/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S @@ -83,29 +83,41 @@ fwd_copy_drain: br t0 .align 5 - ret // -8 == 0 words + // -8 == 0 words + hint #0x24 // bti j + ret .align 5 - ldr t0, [s, #16] // -7 == 1 word + // -7 == 1 word + hint #0x24 // bti j + ldr t0, [s, #16] str t0, [d, #16] ret .align 5 - ldp t0, t1, [s, #16] // -6 = 2 words + // -6 == 2 words + hint #0x24 // bti j + ldp t0, t1, [s, #16] stp t0, t1, [d, #16] ret .align 5 - ldp t0, t1, [s, #16] // -5 = 3 words + // -5 == 3 words + hint #0x24 // bti j + ldp t0, t1, [s, #16] ldr t2, [s, #32] stp t0, t1, [d, #16] str t2, [d, #32] ret .align 5 - ldp t0, t1, [s, #16] // -4 = 4 words + // -4 == 4 words + hint #0x24 // bti j + ldp t0, t1, [s, #16] ldp t2, t3, [s, #32] stp t0, t1, [d, #16] stp t2, t3, [d, #32] ret .align 5 - ldp t0, t1, [s, #16] // -3 = 5 words + // -3 == 5 words + hint #0x24 // bti j + ldp t0, t1, [s, #16] ldp t2, t3, [s, #32] ldr t4, [s, #48] stp t0, t1, [d, #16] @@ -113,7 +125,9 @@ fwd_copy_drain: str t4, [d, #48] ret .align 5 - ldp t0, t1, [s, #16] // -2 = 6 words + // -2 == 6 words + hint #0x24 // bti j + ldp t0, t1, [s, #16] ldp t2, t3, [s, #32] ldp t4, t5, [s, #48] stp t0, t1, [d, #16] @@ -121,18 +135,20 @@ fwd_copy_drain: stp t4, t5, [d, #48] ret .align 5 - ldp t0, t1, [s, #16] // -1 = 7 words + // -1 == 7 words + hint #0x24 // bti j + ldp t0, t1, [s, #16] ldp t2, t3, [s, #32] ldp t4, t5, [s, #48] ldr t6, [s, #64] stp t0, t1, [d, #16] stp t2, t3, [d, #32] stp t4, t5, [d, #48] - str t6, [d, #64] - // Is always aligned here, code for 7 words is one instruction + // Is always aligned here, code for 7 words is two instructions // too large so it just falls through. .align 5 0: + str t6, [d, #64] ret .align 6 @@ -184,29 +200,41 @@ bwd_copy_drain: br t0 .align 5 - ret // -8 == 0 words + // -8 == 0 words + hint #0x24 // bti j + ret .align 5 - ldr t0, [s, #-8] // -7 == 1 word + // -7 == 1 word + hint #0x24 // bti j + ldr t0, [s, #-8] str t0, [d, #-8] ret .align 5 - ldp t0, t1, [s, #-16] // -6 = 2 words + // -6 == 2 words + hint #0x24 // bti j + ldp t0, t1, [s, #-16] stp t0, t1, [d, #-16] ret .align 5 - ldp t0, t1, [s, #-16] // -5 = 3 words + // -5 == 3 words + hint #0x24 // bti j + ldp t0, t1, [s, #-16] ldr t2, [s, #-24] stp t0, t1, [d, #-16] str t2, [d, #-24] ret .align 5 - ldp t0, t1, [s, #-16] // -4 = 4 words + // -4 == 4 words + hint #0x24 // bti j + ldp t0, t1, [s, #-16] ldp t2, t3, [s, #-32] stp t0, t1, [d, #-16] stp t2, t3, [d, #-32] ret .align 5 - ldp t0, t1, [s, #-16] // -3 = 5 words + // -3 == 5 words + hint #0x24 // bti j + ldp t0, t1, [s, #-16] ldp t2, t3, [s, #-32] ldr t4, [s, #-40] stp t0, t1, [d, #-16] @@ -214,7 +242,9 @@ bwd_copy_drain: str t4, [d, #-40] ret .align 5 - ldp t0, t1, [s, #-16] // -2 = 6 words + // -2 == 6 words + hint #0x24 // bti j + ldp t0, t1, [s, #-16] ldp t2, t3, [s, #-32] ldp t4, t5, [s, #-48] stp t0, t1, [d, #-16] @@ -222,16 +252,50 @@ bwd_copy_drain: stp t4, t5, [d, #-48] ret .align 5 - ldp t0, t1, [s, #-16] // -1 = 7 words + // -1 == 7 words + hint #0x24 // bti j + ldp t0, t1, [s, #-16] ldp t2, t3, [s, #-32] ldp t4, t5, [s, #-48] ldr t6, [s, #-56] stp t0, t1, [d, #-16] stp t2, t3, [d, #-32] stp t4, t5, [d, #-48] - str t6, [d, #-56] - // Is always aligned here, code for 7 words is one instruction + // Is always aligned here, code for 7 words is two instructions // too large so it just falls through. .align 5 0: + str t6, [d, #-56] ret + +/* Emit .note.gnu.property section in case of PAC or BTI being enabled. + * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)". + * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst + */ +#ifdef __ARM_FEATURE_BTI_DEFAULT + #ifdef __ARM_FEATURE_PAC_DEFAULT + #define GNU_PROPERTY_AARCH64_FEATURE 3 + #else + #define GNU_PROPERTY_AARCH64_FEATURE 1 + #endif +#else + #ifdef __ARM_FEATURE_PAC_DEFAULT + #define GNU_PROPERTY_AARCH64_FEATURE 2 + #else + #define GNU_PROPERTY_AARCH64_FEATURE 0 + #endif +#endif + +#if (GNU_PROPERTY_AARCH64_FEATURE != 0) + .pushsection .note.gnu.property, "a" + .align 3 + .long 4 /* name length */ + .long 0x10 /* data length */ + .long 5 /* note type: NT_GNU_PROPERTY_TYPE_0 */ + .string "GNU" /* vendor name */ + .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ + .long 4 /* pr_datasze */ + .long GNU_PROPERTY_AARCH64_FEATURE + .long 0 + .popsection +#endif diff --git a/src/hotspot/os_cpu/linux_aarch64/gc/x/xSyscall_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/gc/x/xSyscall_linux_aarch64.hpp deleted file mode 100644 index b4c49f477a677..0000000000000 --- a/src/hotspot/os_cpu/linux_aarch64/gc/x/xSyscall_linux_aarch64.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 - * 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 OS_CPU_LINUX_AARCH64_GC_X_XSYSCALL_LINUX_AARCH64_HPP -#define OS_CPU_LINUX_AARCH64_GC_X_XSYSCALL_LINUX_AARCH64_HPP - -#include - -// -// Support for building on older Linux systems -// - -#ifndef SYS_memfd_create -#define SYS_memfd_create 279 -#endif -#ifndef SYS_fallocate -#define SYS_fallocate 47 -#endif - -#endif // OS_CPU_LINUX_AARCH64_GC_X_XSYSCALL_LINUX_AARCH64_HPP diff --git a/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S index 82d989a9b8830..a26aab44ac43d 100644 --- a/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S @@ -48,3 +48,35 @@ DECLARE_FUNC(_SafeFetchN_fault): DECLARE_FUNC(_SafeFetchN_continuation): mov x0, x1 ret + +/* Emit .note.gnu.property section in case of PAC or BTI being enabled. + * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)". + * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst + */ +#ifdef __ARM_FEATURE_BTI_DEFAULT + #ifdef __ARM_FEATURE_PAC_DEFAULT + #define GNU_PROPERTY_AARCH64_FEATURE 3 + #else + #define GNU_PROPERTY_AARCH64_FEATURE 1 + #endif +#else + #ifdef __ARM_FEATURE_PAC_DEFAULT + #define GNU_PROPERTY_AARCH64_FEATURE 2 + #else + #define GNU_PROPERTY_AARCH64_FEATURE 0 + #endif +#endif + +#if (GNU_PROPERTY_AARCH64_FEATURE != 0) + .pushsection .note.gnu.property, "a" + .align 3 + .long 4 /* name length */ + .long 0x10 /* data length */ + .long 5 /* note type: NT_GNU_PROPERTY_TYPE_0 */ + .string "GNU" /* vendor name */ + .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ + .long 4 /* pr_datasze */ + .long GNU_PROPERTY_AARCH64_FEATURE + .long 0 + .popsection +#endif diff --git a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S index ca31585871dd1..55a252301d793 100644 --- a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S @@ -44,3 +44,35 @@ DECLARE_FUNC(_ZN10JavaThread25aarch64_get_thread_helperEv): ret .size _ZN10JavaThread25aarch64_get_thread_helperEv, .-_ZN10JavaThread25aarch64_get_thread_helperEv + +/* Emit .note.gnu.property section in case of PAC or BTI being enabled. + * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)". + * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst + */ +#ifdef __ARM_FEATURE_BTI_DEFAULT + #ifdef __ARM_FEATURE_PAC_DEFAULT + #define GNU_PROPERTY_AARCH64_FEATURE 3 + #else + #define GNU_PROPERTY_AARCH64_FEATURE 1 + #endif +#else + #ifdef __ARM_FEATURE_PAC_DEFAULT + #define GNU_PROPERTY_AARCH64_FEATURE 2 + #else + #define GNU_PROPERTY_AARCH64_FEATURE 0 + #endif +#endif + +#if (GNU_PROPERTY_AARCH64_FEATURE != 0) + .pushsection .note.gnu.property, "a" + .align 3 + .long 4 /* name length */ + .long 0x10 /* data length */ + .long 5 /* note type: NT_GNU_PROPERTY_TYPE_0 */ + .string "GNU" /* vendor name */ + .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ + .long 4 /* pr_datasze */ + .long GNU_PROPERTY_AARCH64_FEATURE + .long 0 + .popsection +#endif diff --git a/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp index f2ad002996b5c..3c8e9c4441477 100644 --- a/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp @@ -30,23 +30,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp index 9b4bd0faf0ad9..120726bf55fcd 100644 --- a/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp +++ b/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp @@ -29,22 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp index 9464c35977078..ae948c7303101 100644 --- a/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp +++ b/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp @@ -30,23 +30,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, pid_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(pid_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_riscv/gc/x/xSyscall_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/gc/x/xSyscall_linux_riscv.hpp deleted file mode 100644 index bfd49b0bf4e4d..0000000000000 --- a/src/hotspot/os_cpu/linux_riscv/gc/x/xSyscall_linux_riscv.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 OS_CPU_LINUX_RISCV_GC_X_XSYSCALL_LINUX_RISCV_HPP -#define OS_CPU_LINUX_RISCV_GC_X_XSYSCALL_LINUX_RISCV_HPP - -#include - -// -// Support for building on older Linux systems -// - -#ifndef SYS_memfd_create -#define SYS_memfd_create 279 -#endif -#ifndef SYS_fallocate -#define SYS_fallocate 47 -#endif - -#endif // OS_CPU_LINUX_RISCV_GC_X_XSYSCALL_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index df4a2e347ccac..2020e2fdb2429 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -74,7 +74,7 @@ #define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28) #define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29) #define RISCV_HWPROBE_EXT_ZVFH (1 << 30) -#define RISCV_HWPROBE_EXT_ZVFHMIN (1 << 31) +#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31) #define RISCV_HWPROBE_EXT_ZFA (1ULL << 32) #define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33) #define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) @@ -178,6 +178,9 @@ void RiscvHwprobe::add_features_from_query_result() { if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFH)) { VM_Version::ext_Zfh.enable_feature(); } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVFH)) { + VM_Version::ext_Zvfh.enable_feature(); + } if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) { VM_Version::unaligned_access.enable_feature( query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK); diff --git a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp index 6cf7683a58602..3946394c19b1f 100644 --- a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp +++ b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp @@ -30,23 +30,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp b/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp index 0442510fa247a..a0fb5eb1a6ab9 100644 --- a/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp +++ b/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp @@ -30,23 +30,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, pid_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(pid_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_x86/gc/x/xSyscall_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/gc/x/xSyscall_linux_x86.hpp deleted file mode 100644 index 2709b373b2812..0000000000000 --- a/src/hotspot/os_cpu/linux_x86/gc/x/xSyscall_linux_x86.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 - * 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 OS_CPU_LINUX_X86_GC_X_XSYSCALL_LINUX_X86_HPP -#define OS_CPU_LINUX_X86_GC_X_XSYSCALL_LINUX_X86_HPP - -#include - -// -// Support for building on older Linux systems -// - -#ifndef SYS_memfd_create -#define SYS_memfd_create 319 -#endif -#ifndef SYS_fallocate -#define SYS_fallocate 285 -#endif - -#endif // OS_CPU_LINUX_X86_GC_X_XSYSCALL_LINUX_X86_HPP diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index 0d5d07fc8a804..8fdcbe63c7e8b 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -544,6 +544,21 @@ void os::print_context(outputStream *st, const void *context) { st->print(", ERR=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_ERR]); st->cr(); st->print(" TRAPNO=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_TRAPNO]); + // Add XMM registers + MXCSR. Note that C2 uses XMM to spill GPR values including pointers. + st->cr(); + st->cr(); + // Sanity check: fpregs should point into the context. + if ((address)uc->uc_mcontext.fpregs < (address)uc || + pointer_delta(uc->uc_mcontext.fpregs, uc, 1) >= sizeof(ucontext_t)) { + st->print_cr("bad uc->uc_mcontext.fpregs: " INTPTR_FORMAT " (uc: " INTPTR_FORMAT ")", + p2i(uc->uc_mcontext.fpregs), p2i(uc)); + } else { + for (int i = 0; i < 16; ++i) { + const int64_t* xmm_val_addr = (int64_t*)&(uc->uc_mcontext.fpregs->_xmm[i]); + st->print_cr("XMM[%d]=" INTPTR_FORMAT " " INTPTR_FORMAT, i, xmm_val_addr[1], xmm_val_addr[0]); + } + st->print(" MXCSR=" UINT32_FORMAT_X_0, uc->uc_mcontext.fpregs->mxcsr); + } #else st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]); st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]); diff --git a/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp index 277486549c035..8f6d365723700 100644 --- a/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp @@ -29,23 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp index 220787823dc69..18a5588b743b9 100644 --- a/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp @@ -29,18 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp index 62022d780a20b..de59a74cc24cc 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -437,6 +437,15 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); st->print( "RIP=" INTPTR_FORMAT, uc->Rip); st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags); + // Add XMM registers + MXCSR. Note that C2 uses XMM to spill GPR values including pointers. + st->cr(); + st->cr(); + for (int i = 0; i < 16; ++i) { + const uint64_t *xmm = ((const uint64_t*)&(uc->Xmm0)) + 2 * i; + st->print_cr("XMM[%d]=" INTPTR_FORMAT " " INTPTR_FORMAT, + i, xmm[1], xmm[0]); + } + st->print(" MXCSR=" UINT32_FORMAT_X_0, uc->MxCsr); #else st->print( "EAX=" INTPTR_FORMAT, uc->Eax); st->print(", EBX=" INTPTR_FORMAT, uc->Ebx); diff --git a/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp index 9f50a7ed9ae29..985a6a331daba 100644 --- a/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp +++ b/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp @@ -29,18 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/share/adlc/forms.cpp b/src/hotspot/share/adlc/forms.cpp index 068d745254e3d..c34a73ea1e13f 100644 --- a/src/hotspot/share/adlc/forms.cpp +++ b/src/hotspot/share/adlc/forms.cpp @@ -276,7 +276,6 @@ Form::DataType Form::is_load_from_memory(const char *opType) const { Form::DataType Form::is_store_to_memory(const char *opType) const { if( strcmp(opType,"StoreB")==0) return Form::idealB; - if( strcmp(opType,"StoreCM")==0) return Form::idealB; if( strcmp(opType,"StoreC")==0) return Form::idealC; if( strcmp(opType,"StoreD")==0) return Form::idealD; if( strcmp(opType,"StoreF")==0) return Form::idealF; diff --git a/src/hotspot/share/adlc/formsopt.cpp b/src/hotspot/share/adlc/formsopt.cpp index e1e4ed96c2ea0..5de8974e2c096 100644 --- a/src/hotspot/share/adlc/formsopt.cpp +++ b/src/hotspot/share/adlc/formsopt.cpp @@ -171,9 +171,13 @@ int RegisterForm::RegMask_Size() { // on the stack (stack registers) up to some interesting limit. Methods // that need more parameters will NOT be compiled. On Intel, the limit // is something like 90+ parameters. - // Add a few (3 words == 96 bits) for incoming & outgoing arguments to calls. - // Round up to the next doubleword size. - return (words_for_regs + 3 + 1) & ~1; + // - Add a few (3 words == 96 bits) for incoming & outgoing arguments to + // calls. + // - Round up to the next doubleword size. + // - Add one more word to accommodate a reasonable number of stack locations + // in the register mask regardless of how much slack is created by rounding. + // This was found necessary after adding 16 new registers for APX. + return (words_for_regs + 3 + 1 + 1) & ~1; } void RegisterForm::dump() { // Debug printer diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 15bc7ddc67d60..dfa414ef56484 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -3654,7 +3654,6 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const { #if INCLUDE_SHENANDOAHGC "ShenandoahCompareAndSwapN", "ShenandoahCompareAndSwapP", "ShenandoahWeakCompareAndSwapP", "ShenandoahWeakCompareAndSwapN", "ShenandoahCompareAndExchangeP", "ShenandoahCompareAndExchangeN", #endif - "StoreCM", "GetAndSetB", "GetAndSetS", "GetAndAddI", "GetAndSetI", "GetAndSetP", "GetAndAddB", "GetAndAddS", "GetAndAddL", "GetAndSetL", "GetAndSetN", "ClearArray" @@ -3958,15 +3957,15 @@ void MatchNode::count_commutative_op(int& count) { "AndI","AndL", "MaxI","MinI","MaxF","MinF","MaxD","MinD", "MulI","MulL","MulF","MulD", - "OrI","OrL", - "XorI","XorL" + "OrI","OrL", "XorI","XorL", + "UMax","UMin" }; static const char *commut_vector_op_list[] = { "AddVB", "AddVS", "AddVI", "AddVL", "AddVF", "AddVD", "MulVB", "MulVS", "MulVI", "MulVL", "MulVF", "MulVD", "AndV", "OrV", "XorV", - "MaxV", "MinV" + "MaxV", "MinV", "UMax","UMin" }; if (_lChild && _rChild && (_lChild->_lChild || _rChild->_lChild)) { @@ -4340,7 +4339,7 @@ bool MatchRule::is_vector() const { "NegVF","NegVD","NegVI","NegVL", "SqrtVD","SqrtVF", "AndV" ,"XorV" ,"OrV", - "MaxV", "MinV", + "MaxV", "MinV", "UMinV", "UMaxV", "CompressV", "ExpandV", "CompressM", "CompressBitsV", "ExpandBitsV", "AddReductionVI", "AddReductionVL", "AddReductionVF", "AddReductionVD", @@ -4356,14 +4355,14 @@ bool MatchRule::is_vector() const { "Replicate","ReverseV","ReverseBytesV", "RoundDoubleModeV","RotateLeftV" , "RotateRightV", "LoadVector","StoreVector", "LoadVectorGather", "StoreVectorScatter", "LoadVectorGatherMasked", "StoreVectorScatterMasked", - "VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert", + "SelectFromTwoVector", "VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert", "VectorRearrange", "VectorLoadShuffle", "VectorLoadConst", "VectorCastB2X", "VectorCastS2X", "VectorCastI2X", "VectorCastL2X", "VectorCastF2X", "VectorCastD2X", "VectorCastF2HF", "VectorCastHF2F", "VectorUCastB2X", "VectorUCastS2X", "VectorUCastI2X", "VectorMaskWrapper","VectorMaskCmp","VectorReinterpret","LoadVectorMasked","StoreVectorMasked", "FmaVD","FmaVF","PopCountVI","PopCountVL","PopulateIndex","VectorLongToMask", - "CountLeadingZerosV", "CountTrailingZerosV", "SignumVF", "SignumVD", + "CountLeadingZerosV", "CountTrailingZerosV", "SignumVF", "SignumVD", "SaturatingAddV", "SaturatingSubV", // Next are vector mask ops. "MaskAll", "AndVMask", "OrVMask", "XorVMask", "VectorMaskCast", "RoundVF", "RoundVD", diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index d9c3e9d3cb68f..c568caeca4b30 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -29,6 +29,7 @@ #include "c1/c1_ValueType.hpp" #include "oops/method.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" class BlockBegin; class BlockList; @@ -1122,7 +1123,7 @@ class LIR_Op: public CompilationResourceObj { } #endif - virtual const char * name() const PRODUCT_RETURN0; + virtual const char * name() const PRODUCT_RETURN_NULL; virtual void visit(LIR_OpVisitState* state); int id() const { return _id; } @@ -1400,7 +1401,7 @@ class LIR_Op1: public LIR_Op { virtual bool is_patching() { return _patch != lir_patch_none; } virtual void emit_code(LIR_Assembler* masm); virtual LIR_Op1* as_Op1() { return this; } - virtual const char * name() const PRODUCT_RETURN0; + virtual const char * name() const PRODUCT_RETURN_NULL; void set_in_opr(LIR_Opr opr) { _opr = opr; } diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 915f00f77c523..3ebd1f42f366d 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -887,7 +887,7 @@ static Klass* resolve_field_return_klass(const methodHandle& caller, int bci, TR // movl reg, [reg1 + ] (for field offsets) // jmp continue // -// patch_stub: jmp Runtim1::patch_code (through a runtime stub) +// patch_stub: jmp Runtime1::patch_code (through a runtime stub) // jmp patch_site // // If the class is being initialized the patch body is rewritten and @@ -1103,7 +1103,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, C1StubId stub_id )) // Now copy code back { - MutexLocker ml_patch (current, Patching_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml_code (current, CodeCache_lock, Mutex::_no_safepoint_check_flag); // // Deoptimization may have happened while we waited for the lock. // In that case we don't bother to do any patching we just return @@ -1268,12 +1268,8 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, C1StubId stub_id )) } } } - } - - // If we are patching in a non-perm oop, make sure the nmethod - // is on the right list. - { - MutexLocker ml_code (current, CodeCache_lock, Mutex::_no_safepoint_check_flag); + // If we are patching in a non-perm oop, make sure the nmethod + // is on the right list. nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); guarantee(nm != nullptr, "only nmethods can contain non-perm oops"); diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp index 6325fb6f49d73..01831cf0f3e4b 100644 --- a/src/hotspot/share/cds/archiveHeapLoader.cpp +++ b/src/hotspot/share/cds/archiveHeapLoader.cpp @@ -142,15 +142,22 @@ class PatchCompressedEmbeddedPointersQuick: public BitMapClosure { class PatchUncompressedEmbeddedPointers: public BitMapClosure { oop* _start; + intptr_t _delta; public: - PatchUncompressedEmbeddedPointers(oop* start) : _start(start) {} + PatchUncompressedEmbeddedPointers(oop* start, intx runtime_offset) : + _start(start), + _delta(runtime_offset) {} + + PatchUncompressedEmbeddedPointers(oop* start) : + _start(start), + _delta(ArchiveHeapLoader::mapped_heap_delta()) {} bool do_bit(size_t offset) { oop* p = _start + offset; intptr_t dumptime_oop = (intptr_t)((void*)*p); assert(dumptime_oop != 0, "null oops should have been filtered out at dump time"); - intptr_t runtime_oop = dumptime_oop + ArchiveHeapLoader::mapped_heap_delta(); + intptr_t runtime_oop = dumptime_oop + _delta; RawAccess::oop_store(p, cast_to_oop(runtime_oop)); return true; } @@ -221,10 +228,6 @@ void ArchiveHeapLoader::init_loaded_heap_relocation(LoadedArchiveHeapRegion* loa } bool ArchiveHeapLoader::can_load() { - if (!UseCompressedOops) { - // Pointer relocation for uncompressed oops is unimplemented. - return false; - } return Universe::heap()->can_load_archived_objects(); } @@ -312,13 +315,18 @@ bool ArchiveHeapLoader::load_heap_region_impl(FileMapInfo* mapinfo, LoadedArchiv uintptr_t oopmap = bitmap_base + r->oopmap_offset(); BitMapView bm((BitMap::bm_word_t*)oopmap, r->oopmap_size_in_bits()); - PatchLoadedRegionPointers patcher((narrowOop*)load_address + FileMapInfo::current_info()->heap_oopmap_start_pos(), loaded_region); - bm.iterate(&patcher); + if (UseCompressedOops) { + PatchLoadedRegionPointers patcher((narrowOop*)load_address + FileMapInfo::current_info()->heap_oopmap_start_pos(), loaded_region); + bm.iterate(&patcher); + } else { + PatchUncompressedEmbeddedPointers patcher((oop*)load_address + FileMapInfo::current_info()->heap_oopmap_start_pos(), loaded_region->_runtime_offset); + bm.iterate(&patcher); + } return true; } bool ArchiveHeapLoader::load_heap_region(FileMapInfo* mapinfo) { - assert(UseCompressedOops, "loaded heap for !UseCompressedOops is unimplemented"); + assert(can_load(), "loaded heap for must be supported"); init_narrow_oop_decoding(mapinfo->narrow_oop_base(), mapinfo->narrow_oop_shift()); LoadedArchiveHeapRegion loaded_region; @@ -358,8 +366,12 @@ class VerifyLoadedHeapEmbeddedPointers: public BasicOopIterateClosure { } } virtual void do_oop(oop* p) { - // Uncompressed oops are not supported by loaded heaps. - Unimplemented(); + oop v = *p; + if(v != nullptr) { + uintptr_t u = cast_from_oop(v); + ArchiveHeapLoader::assert_in_loaded_heap(u); + guarantee(_table->contains(u), "must point to beginning of object in loaded archived region"); + } } }; @@ -376,13 +388,12 @@ void ArchiveHeapLoader::finish_initialization() { intptr_t bottom = is_loaded() ? _loaded_heap_bottom : _mapped_heap_bottom; // The heap roots are stored in one or more segments that are laid out consecutively. - // The byte size of each segment (except for the last one) is max_size. + // The size of each segment (except for the last one) is max_size_in_{elems,bytes}. HeapRootSegments segments = FileMapInfo::current_info()->heap_root_segments(); - int max_size = segments.max_size_in_bytes(); - HeapShared::init_root_segment_sizes(max_size); + HeapShared::init_root_segment_sizes(segments.max_size_in_elems()); intptr_t first_segment_addr = bottom + segments.base_offset(); for (size_t c = 0; c < segments.count(); c++) { - oop segment_oop = cast_to_oop(first_segment_addr + (c * max_size)); + oop segment_oop = cast_to_oop(first_segment_addr + (c * segments.max_size_in_bytes())); assert(segment_oop->is_objArray(), "Must be"); HeapShared::add_root_segment((objArrayOop)segment_oop); } diff --git a/src/hotspot/share/cds/archiveHeapLoader.hpp b/src/hotspot/share/cds/archiveHeapLoader.hpp index 700135a38166c..8b9fab91aa3fd 100644 --- a/src/hotspot/share/cds/archiveHeapLoader.hpp +++ b/src/hotspot/share/cds/archiveHeapLoader.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,6 +146,7 @@ class ArchiveHeapLoader : AllStatic { inline static oop decode_from_archive_impl(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(nullptr); class PatchLoadedRegionPointers; + class PatchUncompressedLoadedRegionPointers; public: diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index 853d459c691dd..710e693bfdb14 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -223,6 +223,7 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeapat(root_index++)); @@ -245,6 +245,8 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeaplength(), "Post-condition: All roots are handled"); + _heap_root_segments = segments; } diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp index 2e361ab0c4650..5a78bc26ee627 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.hpp @@ -277,7 +277,6 @@ class HeapRootSegments { memset(this, 0, sizeof(*this)); } HeapRootSegments(size_t base_offset, int roots_count, int max_size_in_bytes, int max_size_in_elems) { - assert(is_power_of_2(max_size_in_bytes), "must be"); memset(this, 0, sizeof(*this)); _base_offset = base_offset; _count = (roots_count + max_size_in_elems - 1) / max_size_in_elems; diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index a0a562eca21a0..9e8a46e105e19 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -236,7 +236,9 @@ void CDSConfig::init_shared_archive_paths() { } void CDSConfig::check_internal_module_property(const char* key, const char* value) { - if (Arguments::is_internal_module_property(key)) { + if (Arguments::is_internal_module_property(key) && + !Arguments::is_module_path_property(key) && + !Arguments::is_add_modules_property(key)) { stop_using_optimized_module_handling(); log_info(cds)("optimized module handling: disabled due to incompatible property: %s=%s", key, value); } diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp index a4ffeea26dc4a..2eb47ff2788d9 100644 --- a/src/hotspot/share/cds/cdsProtectionDomain.cpp +++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp @@ -199,17 +199,9 @@ Handle CDSProtectionDomain::get_shared_jar_manifest(int shared_path_index, TRAPS Handle CDSProtectionDomain::get_shared_jar_url(int shared_path_index, TRAPS) { Handle url_h; if (shared_jar_url(shared_path_index) == nullptr) { - JavaValue result(T_OBJECT); const char* path = FileMapInfo::shared_path_name(shared_path_index); - Handle path_string = java_lang_String::create_from_str(path, CHECK_(url_h)); - Klass* classLoaders_klass = - vmClasses::jdk_internal_loader_ClassLoaders_klass(); - JavaCalls::call_static(&result, classLoaders_klass, - vmSymbols::toFileURL_name(), - vmSymbols::toFileURL_signature(), - path_string, CHECK_(url_h)); - - atomic_set_shared_jar_url(shared_path_index, result.get_oop()); + oop result_oop = to_file_URL(path, url_h, CHECK_(url_h)); + atomic_set_shared_jar_url(shared_path_index, result_oop); } url_h = Handle(THREAD, shared_jar_url(shared_path_index)); @@ -217,6 +209,17 @@ Handle CDSProtectionDomain::get_shared_jar_url(int shared_path_index, TRAPS) { return url_h; } +oop CDSProtectionDomain::to_file_URL(const char* path, Handle url_h, TRAPS) { + JavaValue result(T_OBJECT); + Handle path_string = java_lang_String::create_from_str(path, CHECK_NULL); + JavaCalls::call_static(&result, + vmClasses::jdk_internal_loader_ClassLoaders_klass(), + vmSymbols::toFileURL_name(), + vmSymbols::toFileURL_signature(), + path_string, CHECK_NULL); + return result.get_oop(); +} + // Get the ProtectionDomain associated with the CodeSource from the classloader. Handle CDSProtectionDomain::get_protection_domain_from_classloader(Handle class_loader, Handle url, TRAPS) { diff --git a/src/hotspot/share/cds/cdsProtectionDomain.hpp b/src/hotspot/share/cds/cdsProtectionDomain.hpp index 0e688fcfa00e8..baab4ab0e728a 100644 --- a/src/hotspot/share/cds/cdsProtectionDomain.hpp +++ b/src/hotspot/share/cds/cdsProtectionDomain.hpp @@ -80,6 +80,7 @@ class CDSProtectionDomain : AllStatic { static Handle create_jar_manifest(const char* man, size_t size, TRAPS); static Handle get_shared_jar_manifest(int shared_path_index, TRAPS); static Handle get_shared_jar_url(int shared_path_index, TRAPS); + static oop to_file_URL(const char* path, Handle url_h, TRAPS); static Handle get_protection_domain_from_classloader(Handle class_loader, Handle url, TRAPS); static Handle get_shared_protection_domain(Handle class_loader, diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 78613ae4b36c4..33a81a81da058 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -781,12 +781,12 @@ bool FileMapInfo::check_paths(int shared_path_start_idx, int num_paths, Growable assert(strlen(rp_array->at(i)) > (size_t)runtime_prefix_len, "sanity"); const char* runtime_path = rp_array->at(i) + runtime_prefix_len; if (!os::same_files(dumptime_path, runtime_path)) { - return true; + return false; } i++; j++; } - return false; + return true; } bool FileMapInfo::validate_boot_class_paths() { @@ -810,7 +810,7 @@ bool FileMapInfo::validate_boot_class_paths() { char* rp = skip_first_path_entry(runtime_boot_path); assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image"); int dp_len = header()->app_class_paths_start_index() - 1; // ignore the first path to the module image - bool mismatch = false; + bool match = true; bool relaxed_check = !header()->has_platform_or_app_classes(); if (dp_len == 0 && rp == nullptr) { @@ -823,7 +823,7 @@ bool FileMapInfo::validate_boot_class_paths() { if (check_paths_existence(rp)) { // If a path exists in the runtime boot paths, it is considered a mismatch // since there's no boot path specified during dump time. - mismatch = true; + match = false; } } } else if (dp_len > 0 && rp != nullptr) { @@ -840,16 +840,16 @@ bool FileMapInfo::validate_boot_class_paths() { // check the full runtime boot path, must match with dump time num = rp_len; } - mismatch = check_paths(1, num, rp_array, 0, 0); + match = check_paths(1, num, rp_array, 0, 0); } else { // create_path_array() ignores non-existing paths. Although the dump time and runtime boot classpath lengths // are the same initially, after the call to create_path_array(), the runtime boot classpath length could become // shorter. We consider boot classpath mismatch in this case. - mismatch = true; + match = false; } } - if (mismatch) { + if (!match) { // The paths are different return classpath_failure("[BOOT classpath mismatch, actual =", runtime_boot_path); } @@ -860,7 +860,7 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) { const char *appcp = Arguments::get_appclasspath(); assert(appcp != nullptr, "null app classpath"); int rp_len = num_paths(appcp); - bool mismatch = false; + bool match = false; if (rp_len < shared_app_paths_len) { return classpath_failure("Run time APP classpath is shorter than the one at dump time: ", appcp); } @@ -889,8 +889,8 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) { // run 2: -cp x.jar:NE4:b.jar -> x.jar:b.jar -> mismatched int j = header()->app_class_paths_start_index(); - mismatch = check_paths(j, shared_app_paths_len, rp_array, 0, 0); - if (mismatch) { + match = check_paths(j, shared_app_paths_len, rp_array, 0, 0); + if (!match) { // To facilitate app deployment, we allow the JAR files to be moved *together* to // a different location, as long as they are still stored under the same directory // structure. E.g., the following is OK. @@ -901,10 +901,10 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) { if (dumptime_prefix_len != 0 || runtime_prefix_len != 0) { log_info(class, path)("LCP length for app classpath (dumptime: %u, runtime: %u)", dumptime_prefix_len, runtime_prefix_len); - mismatch = check_paths(j, shared_app_paths_len, rp_array, + match = check_paths(j, shared_app_paths_len, rp_array, dumptime_prefix_len, runtime_prefix_len); } - if (mismatch) { + if (!match) { return classpath_failure("[APP classpath mismatch, actual: -Djava.class.path=", appcp); } } @@ -926,15 +926,35 @@ void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) { } } +void FileMapInfo::extract_module_paths(const char* runtime_path, GrowableArray* module_paths) { + GrowableArray* path_array = create_path_array(runtime_path); + int num_paths = path_array->length(); + for (int i = 0; i < num_paths; i++) { + const char* name = path_array->at(i); + ClassLoaderExt::extract_jar_files_from_path(name, module_paths); + } + // module paths are stored in sorted order in the CDS archive. + module_paths->sort(ClassLoaderExt::compare_module_names); +} + bool FileMapInfo::check_module_paths() { - const char* rp = Arguments::get_property("jdk.module.path"); - int num_paths = CDSConfig::num_archives(rp); - if (num_paths != header()->num_module_paths()) { + const char* runtime_path = Arguments::get_property("jdk.module.path"); + int archived_num_module_paths = header()->num_module_paths(); + if (runtime_path == nullptr && archived_num_module_paths == 0) { + return true; + } + if ((runtime_path == nullptr && archived_num_module_paths > 0) || + (runtime_path != nullptr && archived_num_module_paths == 0)) { return false; } ResourceMark rm; - GrowableArray* rp_array = create_path_array(rp); - return check_paths(header()->app_module_paths_start_index(), num_paths, rp_array, 0, 0); + GrowableArray* module_paths = new GrowableArray(3); + extract_module_paths(runtime_path, module_paths); + int num_paths = module_paths->length(); + if (num_paths != archived_num_module_paths) { + return false; + } + return check_paths(header()->app_module_paths_start_index(), num_paths, module_paths, 0, 0); } bool FileMapInfo::validate_shared_path_table() { @@ -944,6 +964,16 @@ bool FileMapInfo::validate_shared_path_table() { // Load the shared path table info from the archive header _shared_path_table = header()->shared_path_table(); + + bool matched_module_paths = true; + if (CDSConfig::is_dumping_dynamic_archive() || header()->has_full_module_graph()) { + matched_module_paths = check_module_paths(); + } + if (header()->has_full_module_graph() && !matched_module_paths) { + CDSConfig::stop_using_optimized_module_handling(); + log_info(cds)("optimized module handling: disabled because of mismatched module paths"); + } + if (CDSConfig::is_dumping_dynamic_archive()) { // Only support dynamic dumping with the usage of the default CDS archive // or a simple base archive. @@ -959,7 +989,7 @@ bool FileMapInfo::validate_shared_path_table() { "Dynamic archiving is disabled because base layer archive has appended boot classpath"); } if (header()->num_module_paths() > 0) { - if (!check_module_paths()) { + if (!matched_module_paths) { CDSConfig::disable_dumping_dynamic_archive(); log_warning(cds)( "Dynamic archiving is disabled because base layer archive has a different module path"); @@ -2024,8 +2054,7 @@ void FileMapInfo::map_or_load_heap_region() { success = ArchiveHeapLoader::load_heap_region(this); } else { if (!UseCompressedOops && !ArchiveHeapLoader::can_map()) { - // TODO - remove implicit knowledge of G1 - log_info(cds)("Cannot use CDS heap data. UseG1GC is required for -XX:-UseCompressedOops"); + log_info(cds)("Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"); } else { log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required."); } @@ -2105,7 +2134,7 @@ address FileMapInfo::heap_region_requested_address() { assert(CDSConfig::is_using_archive(), "runtime only"); FileMapRegion* r = region_at(MetaspaceShared::hp); assert(is_aligned(r->mapping_offset(), sizeof(HeapWord)), "must be"); - assert(ArchiveHeapLoader::can_map(), "cannot be used by ArchiveHeapLoader::can_load() mode"); + assert(ArchiveHeapLoader::can_use(), "GC must support mapping or loading"); if (UseCompressedOops) { // We can avoid relocation if each region's offset from the runtime CompressedOops::base() // is the same as its offset from the CompressedOops::base() during dumptime. diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 1bf2510a3351c..6650f52440881 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -271,6 +271,7 @@ class FileMapHeader: private CDSFileMapHeaderBase { bool compressed_oops() const { return _compressed_oops; } bool compressed_class_pointers() const { return _compressed_class_ptrs; } HeapRootSegments heap_root_segments() const { return _heap_root_segments; } + bool has_full_module_graph() const { return _has_full_module_graph; } size_t heap_oopmap_start_pos() const { return _heap_oopmap_start_pos; } size_t heap_ptrmap_start_pos() const { return _heap_ptrmap_start_pos; } size_t rw_ptrmap_start_pos() const { return _rw_ptrmap_start_pos; } @@ -554,6 +555,7 @@ class FileMapInfo : public CHeapObj { GrowableArray* rp_array, unsigned int dumptime_prefix_len, unsigned int runtime_prefix_len) NOT_CDS_RETURN_(false); + void extract_module_paths(const char* runtime_path, GrowableArray* module_paths); bool validate_boot_class_paths() NOT_CDS_RETURN_(false); bool validate_app_class_paths(int shared_app_paths_len) NOT_CDS_RETURN_(false); bool map_heap_region_impl() NOT_CDS_JAVA_HEAP_RETURN_(false); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 1fddcb0d81f8a..22040448770d5 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -33,6 +33,7 @@ #include "cds/heapShared.hpp" #include "cds/metaspaceShared.hpp" #include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderExt.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/modules.hpp" #include "classfile/stringTable.hpp" @@ -55,6 +56,7 @@ #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" +#include "runtime/arguments.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/init.hpp" #include "runtime/javaCalls.hpp" @@ -134,8 +136,7 @@ static ArchivableStaticFieldInfo fmg_archive_subgraph_entry_fields[] = { KlassSubGraphInfo* HeapShared::_default_subgraph_info; GrowableArrayCHeap* HeapShared::_pending_roots = nullptr; GrowableArrayCHeap* HeapShared::_root_segments; -int HeapShared::_root_segment_max_size_shift; -int HeapShared::_root_segment_max_size_mask; +int HeapShared::_root_segment_max_size_elems; OopHandle HeapShared::_scratch_basic_type_mirrors[T_VOID+1]; MetaspaceObjToOopHandleTable* HeapShared::_scratch_java_mirror_table = nullptr; MetaspaceObjToOopHandleTable* HeapShared::_scratch_references_table = nullptr; @@ -242,15 +243,29 @@ objArrayOop HeapShared::root_segment(int segment_idx) { return segment; } +void HeapShared::get_segment_indexes(int idx, int& seg_idx, int& int_idx) { + assert(_root_segment_max_size_elems > 0, "sanity"); + + // Try to avoid divisions for the common case. + if (idx < _root_segment_max_size_elems) { + seg_idx = 0; + int_idx = idx; + } else { + seg_idx = idx / _root_segment_max_size_elems; + int_idx = idx % _root_segment_max_size_elems; + } + + assert(idx == seg_idx * _root_segment_max_size_elems + int_idx, + "sanity: %d index maps to %d segment and %d internal", idx, seg_idx, int_idx); +} + // Returns an objArray that contains all the roots of the archived objects oop HeapShared::get_root(int index, bool clear) { - assert(_root_segment_max_size_shift > 0, "sanity"); - assert(_root_segment_max_size_mask > 0, "sanity"); assert(index >= 0, "sanity"); assert(!CDSConfig::is_dumping_heap() && CDSConfig::is_using_archive(), "runtime only"); assert(!_root_segments->is_empty(), "must have loaded shared heap"); - int seg_idx = index >> _root_segment_max_size_shift; - int int_idx = index & _root_segment_max_size_mask; + int seg_idx, int_idx; + get_segment_indexes(index, seg_idx, int_idx); oop result = root_segment(seg_idx)->obj_at(int_idx); if (clear) { clear_root(index); @@ -262,10 +277,8 @@ void HeapShared::clear_root(int index) { assert(index >= 0, "sanity"); assert(CDSConfig::is_using_archive(), "must be"); if (ArchiveHeapLoader::is_in_use()) { - assert(_root_segment_max_size_shift > 0, "sanity"); - assert(_root_segment_max_size_mask > 0, "sanity"); - int seg_idx = index >> _root_segment_max_size_shift; - int int_idx = index & _root_segment_max_size_mask; + int seg_idx, int_idx; + get_segment_indexes(index, seg_idx, int_idx); if (log_is_enabled(Debug, cds, heap)) { oop old = root_segment(seg_idx)->obj_at(int_idx); log_debug(cds, heap)("Clearing root %d: was " PTR_FORMAT, index, p2i(old)); @@ -373,6 +386,13 @@ void HeapShared::set_scratch_java_mirror(Klass* k, oop mirror) { } void HeapShared::remove_scratch_objects(Klass* k) { + // Klass is being deallocated. Java mirror can still be alive, and it should not + // point to dead klass. We need to break the link from mirror to the Klass. + // See how InstanceKlass::deallocate_contents does it for normal mirrors. + oop mirror = _scratch_java_mirror_table->get_oop(k); + if (mirror != nullptr) { + java_lang_Class::set_klass(mirror, nullptr); + } _scratch_java_mirror_table->remove_oop(k); if (k->is_instance_klass()) { _scratch_references_table->remove(InstanceKlass::cast(k)->constants()); @@ -785,10 +805,8 @@ void HeapShared::add_root_segment(objArrayOop segment_oop) { _root_segments->push(OopHandle(Universe::vm_global(), segment_oop)); } -void HeapShared::init_root_segment_sizes(int max_size) { - assert(is_power_of_2(max_size), "must be"); - _root_segment_max_size_shift = log2i_exact(max_size); - _root_segment_max_size_mask = max_size - 1; +void HeapShared::init_root_segment_sizes(int max_size_elems) { + _root_segment_max_size_elems = max_size_elems; } void HeapShared::serialize_tables(SerializeClosure* soc) { @@ -875,6 +893,17 @@ void HeapShared::initialize_from_archived_subgraph(JavaThread* current, Klass* k return; // nothing to do } + if (k->name()->equals("jdk/internal/module/ArchivedModuleGraph") && + !CDSConfig::is_using_optimized_module_handling() && + // archive was created with --module-path + ClassLoaderExt::num_module_paths() > 0) { + // ArchivedModuleGraph was created with a --module-path that's different than the runtime --module-path. + // Thus, it might contain references to modules that do not exist at runtime. We cannot use it. + log_info(cds, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_optimized_module_handling=%s num_module_paths=%d", + BOOL_TO_STR(CDSConfig::is_using_optimized_module_handling()), ClassLoaderExt::num_module_paths()); + return; + } + ExceptionMark em(THREAD); const ArchivedKlassSubGraphInfoRecord* record = resolve_or_init_classes_for_subgraph_of(k, /*do_init=*/true, THREAD); @@ -1123,6 +1152,13 @@ bool HeapShared::archive_reachable_objects_from(int level, // these objects that are referenced (directly or indirectly) by static fields. ResourceMark rm; log_error(cds, heap)("Cannot archive object of class %s", orig_obj->klass()->external_name()); + if (log_is_enabled(Trace, cds, heap)) { + WalkOopAndArchiveClosure* walker = WalkOopAndArchiveClosure::current(); + if (walker != nullptr) { + LogStream ls(Log(cds, heap)::trace()); + CDSHeapVerifier::trace_to_root(&ls, walker->referencing_obj()); + } + } MetaspaceShared::unrecoverable_writing_error(); } diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index 01610ebe64e15..317b791f5d3a3 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -143,13 +143,18 @@ class HeapShared: AllStatic { friend class VerifySharedOopClosure; public: - // Can this VM write a heap region into the CDS archive? Currently only {G1|Parallel|Serial}+compressed_cp + // Can this VM write a heap region into the CDS archive? static bool can_write() { CDS_JAVA_HEAP_ONLY( if (_disable_writing) { return false; } - return (UseG1GC || UseParallelGC || UseSerialGC) && UseCompressedClassPointers; + // Need compressed class pointers for heap region dump. + if (!UseCompressedClassPointers) { + return false; + } + // Almost all GCs support heap region dump, except ZGC (so far). + return !UseZGC; ) NOT_CDS_JAVA_HEAP(return false;) } @@ -291,8 +296,7 @@ class HeapShared: AllStatic { static GrowableArrayCHeap* _pending_roots; static GrowableArrayCHeap* _root_segments; - static int _root_segment_max_size_shift; - static int _root_segment_max_size_mask; + static int _root_segment_max_size_elems; static OopHandle _scratch_basic_type_mirrors[T_VOID+1]; static MetaspaceObjToOopHandleTable* _scratch_java_mirror_table; static MetaspaceObjToOopHandleTable* _scratch_references_table; @@ -407,6 +411,8 @@ class HeapShared: AllStatic { // Run-time only static void clear_root(int index); + static void get_segment_indexes(int index, int& segment_index, int& internal_index); + static void setup_test_class(const char* test_class_name) PRODUCT_RETURN; #endif // INCLUDE_CDS_JAVA_HEAP @@ -425,7 +431,7 @@ class HeapShared: AllStatic { static void init_for_dumping(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN; static void add_root_segment(objArrayOop segment_oop) NOT_CDS_JAVA_HEAP_RETURN; - static void init_root_segment_sizes(int max_size) NOT_CDS_JAVA_HEAP_RETURN; + static void init_root_segment_sizes(int max_size_elems) NOT_CDS_JAVA_HEAP_RETURN; static void serialize_tables(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; #ifndef PRODUCT diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index c66398cefac5a..2a43fd2dd4f2a 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -77,6 +77,7 @@ #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/javaCalls.hpp" #include "runtime/os.inline.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/sharedRuntime.hpp" @@ -300,6 +301,7 @@ void MetaspaceShared::post_initialize(TRAPS) { } ClassLoaderExt::init_paths_start_index(info->app_class_paths_start_index()); ClassLoaderExt::init_app_module_paths_start_index(info->app_module_paths_start_index()); + ClassLoaderExt::init_num_module_paths(info->header()->num_module_paths()); } } } @@ -401,6 +403,7 @@ void MetaspaceShared::serialize(SerializeClosure* soc) { soc->do_tag(--tag); CDS_JAVA_HEAP_ONLY(Modules::serialize(soc);) + CDS_JAVA_HEAP_ONLY(Modules::serialize_addmods_names(soc);) CDS_JAVA_HEAP_ONLY(ClassLoaderDataShared::serialize(soc);) LambdaFormInvokers::serialize(soc); @@ -500,6 +503,8 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() { LambdaFormInvokers::dump_static_archive_invokers(); // Write module name into archive CDS_JAVA_HEAP_ONLY(Modules::dump_main_module_name();) + // Write module names from --add-modules into archive + CDS_JAVA_HEAP_ONLY(Modules::dump_addmods_names();) // Write the other data to the output array. DumpRegion* ro_region = ArchiveBuilder::current()->ro_region(); char* start = ro_region->top(); @@ -749,12 +754,21 @@ void MetaspaceShared::preload_classes(TRAPS) { } } - // Exercise the manifest processing code to ensure classes used by CDS at runtime - // are always archived + // Some classes are used at CDS runtime but are not loaded, and therefore archived, at + // dumptime. We can perform dummmy calls to these classes at dumptime to ensure they + // are archived. + exercise_runtime_cds_code(CHECK); + + log_info(cds)("Loading classes to share: done."); +} + +void MetaspaceShared::exercise_runtime_cds_code(TRAPS) { + // Exercise the manifest processing code const char* dummy = "Manifest-Version: 1.0\n"; CDSProtectionDomain::create_jar_manifest(dummy, strlen(dummy), CHECK); - log_info(cds)("Loading classes to share: done."); + // Exercise FileSystem and URL code + CDSProtectionDomain::to_file_URL("dummy.jar", Handle(), CHECK); } void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) { @@ -791,6 +805,9 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS // Do this at the very end, when no Java code will be executed. Otherwise // some new strings may be added to the intern table. StringTable::allocate_shared_strings_array(CHECK); + } else { + log_info(cds)("Not dumping heap, reset CDSConfig::_is_using_optimized_module_handling"); + CDSConfig::stop_using_optimized_module_handling(); } #endif diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index f26af21676a83..ecc158cc3efcf 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -75,6 +75,7 @@ class MetaspaceShared : AllStatic { #endif private: + static void exercise_runtime_cds_code(TRAPS) NOT_CDS_RETURN; static void preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) NOT_CDS_RETURN; static void preload_classes(TRAPS) NOT_CDS_RETURN; diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 155ce032400e8..6bf8f44553d6e 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1597,6 +1597,8 @@ void ciEnv::dump_replay_data_helper(outputStream* out) { NoSafepointVerifier no_safepoint; ResourceMark rm; + assert(this->task() != nullptr, "task must not be null"); + dump_replay_data_version(out); #if INCLUDE_JVMTI out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables); @@ -1617,9 +1619,7 @@ void ciEnv::dump_replay_data_helper(outputStream* out) { objects->at(i)->dump_replay_data(out); } - if (this->task() != nullptr) { - dump_compile_data(out); - } + dump_compile_data(out); out->flush(); } diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index 94b405cdbfacd..a74a812c6a23b 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -1249,7 +1249,6 @@ bool ciMethod::has_jsrs () const { FETCH_FLAG_FROM_VM(has_jsrs); bool ciMethod::is_getter () const { FETCH_FLAG_FROM_VM(is_getter); } bool ciMethod::is_setter () const { FETCH_FLAG_FROM_VM(is_setter); } bool ciMethod::is_accessor () const { FETCH_FLAG_FROM_VM(is_accessor); } -bool ciMethod::is_initializer () const { FETCH_FLAG_FROM_VM(is_initializer); } bool ciMethod::is_empty () const { FETCH_FLAG_FROM_VM(is_empty_method); } bool ciMethod::is_boxing_method() const { diff --git a/src/hotspot/share/ci/ciMethod.hpp b/src/hotspot/share/ci/ciMethod.hpp index 5cb63204d0b72..cc524930192cd 100644 --- a/src/hotspot/share/ci/ciMethod.hpp +++ b/src/hotspot/share/ci/ciMethod.hpp @@ -352,7 +352,6 @@ class ciMethod : public ciMetadata { bool is_getter () const; bool is_setter () const; bool is_accessor () const; - bool is_initializer () const; bool is_empty () const; bool can_be_statically_bound() const { return _can_be_statically_bound; } bool has_reserved_stack_access() const { return _has_reserved_stack_access; } diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index 520eeeb10d568..2d80a18f16bc6 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -720,12 +720,18 @@ void ciTypeFlow::StateVector::do_jsr(ciBytecodeStream* str) { void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) { if (str->is_in_error()) { trap(str, nullptr, Deoptimization::make_trap_request(Deoptimization::Reason_unhandled, - Deoptimization::Action_none)); + Deoptimization::Action_none)); return; } ciConstant con = str->get_constant(); if (con.is_valid()) { int cp_index = str->get_constant_pool_index(); + if (!con.is_loaded()) { + trap(str, nullptr, Deoptimization::make_trap_request(Deoptimization::Reason_unloaded, + Deoptimization::Action_reinterpret, + cp_index)); + return; + } BasicType basic_type = str->get_basic_type_for_constant_at(cp_index); if (is_reference_type(basic_type)) { ciObject* obj = con.as_object(); @@ -2207,11 +2213,10 @@ bool ciTypeFlow::can_trap(ciBytecodeStream& str) { if (!Bytecodes::can_trap(str.cur_bc())) return false; switch (str.cur_bc()) { - // %%% FIXME: ldc of Class can generate an exception case Bytecodes::_ldc: case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: - return str.is_in_error(); + return str.is_in_error() || !str.get_constant().is_loaded(); case Bytecodes::_aload_0: // These bytecodes can trap for rewriting. We need to assume that diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index c8e95149b7c1a..93dd0af65e731 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -411,23 +411,6 @@ static inline Symbol* check_symbol_at(const ConstantPool* cp, int index) { return nullptr; } -#ifdef ASSERT -PRAGMA_DIAG_PUSH -PRAGMA_FORMAT_NONLITERAL_IGNORED -void ClassFileParser::report_assert_property_failure(const char* msg, TRAPS) const { - ResourceMark rm(THREAD); - fatal(msg, _class_name->as_C_string()); -} - -void ClassFileParser::report_assert_property_failure(const char* msg, - int index, - TRAPS) const { - ResourceMark rm(THREAD); - fatal(msg, index, _class_name->as_C_string()); -} -PRAGMA_DIAG_POP -#endif - void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, ConstantPool* const cp, const int length, @@ -462,10 +445,10 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, if (!_need_verify) break; const int klass_ref_index = cp->uncached_klass_ref_index_at(index); const int name_and_type_ref_index = cp->uncached_name_and_type_ref_index_at(index); - check_property(valid_klass_reference_at(klass_ref_index), + guarantee_property(valid_klass_reference_at(klass_ref_index), "Invalid constant pool index %u in class file %s", klass_ref_index, CHECK); - check_property(valid_cp_range(name_and_type_ref_index, length) && + guarantee_property(valid_cp_range(name_and_type_ref_index, length) && cp->tag_at(name_and_type_ref_index).is_name_and_type(), "Invalid constant pool index %u in class file %s", name_and_type_ref_index, CHECK); @@ -482,7 +465,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, case JVM_CONSTANT_Long: case JVM_CONSTANT_Double: { index++; - check_property( + guarantee_property( (index < length && cp->tag_at(index).is_invalid()), "Improper constant pool long/double index %u in class file %s", index, CHECK); @@ -492,10 +475,10 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, if (!_need_verify) break; const int name_ref_index = cp->name_ref_index_at(index); const int signature_ref_index = cp->signature_ref_index_at(index); - check_property(valid_symbol_at(name_ref_index), + guarantee_property(valid_symbol_at(name_ref_index), "Invalid constant pool index %u in class file %s", name_ref_index, CHECK); - check_property(valid_symbol_at(signature_ref_index), + guarantee_property(valid_symbol_at(signature_ref_index), "Invalid constant pool index %u in class file %s", signature_ref_index, CHECK); break; @@ -509,7 +492,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } case JVM_CONSTANT_ClassIndex: { const int class_index = cp->klass_index_at(index); - check_property(valid_symbol_at(class_index), + guarantee_property(valid_symbol_at(class_index), "Invalid constant pool index %u in class file %s", class_index, CHECK); cp->unresolved_klass_at_put(index, class_index, num_klasses++); @@ -517,7 +500,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } case JVM_CONSTANT_StringIndex: { const int string_index = cp->string_index_at(index); - check_property(valid_symbol_at(string_index), + guarantee_property(valid_symbol_at(string_index), "Invalid constant pool index %u in class file %s", string_index, CHECK); Symbol* const sym = cp->symbol_at(string_index); @@ -526,7 +509,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } case JVM_CONSTANT_MethodHandle: { const int ref_index = cp->method_handle_index_at(index); - check_property(valid_cp_range(ref_index, length), + guarantee_property(valid_cp_range(ref_index, length), "Invalid constant pool index %u in class file %s", ref_index, CHECK); const constantTag tag = cp->tag_at(ref_index); @@ -537,7 +520,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, case JVM_REF_getStatic: case JVM_REF_putField: case JVM_REF_putStatic: { - check_property( + guarantee_property( tag.is_field(), "Invalid constant pool index %u in class file %s (not a field)", ref_index, CHECK); @@ -545,7 +528,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } case JVM_REF_invokeVirtual: case JVM_REF_newInvokeSpecial: { - check_property( + guarantee_property( tag.is_method(), "Invalid constant pool index %u in class file %s (not a method)", ref_index, CHECK); @@ -553,7 +536,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } case JVM_REF_invokeStatic: case JVM_REF_invokeSpecial: { - check_property( + guarantee_property( tag.is_method() || ((_major_version >= JAVA_8_VERSION) && tag.is_interface_method()), "Invalid constant pool index %u in class file %s (not a method)", @@ -561,7 +544,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, break; } case JVM_REF_invokeInterface: { - check_property( + guarantee_property( tag.is_interface_method(), "Invalid constant pool index %u in class file %s (not an interface method)", ref_index, CHECK); @@ -579,7 +562,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } // case MethodHandle case JVM_CONSTANT_MethodType: { const int ref_index = cp->method_type_index_at(index); - check_property(valid_symbol_at(ref_index), + guarantee_property(valid_symbol_at(ref_index), "Invalid constant pool index %u in class file %s", ref_index, CHECK); break; @@ -588,7 +571,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, const int name_and_type_ref_index = cp->bootstrap_name_and_type_ref_index_at(index); - check_property(valid_cp_range(name_and_type_ref_index, length) && + guarantee_property(valid_cp_range(name_and_type_ref_index, length) && cp->tag_at(name_and_type_ref_index).is_name_and_type(), "Invalid constant pool index %u in class file %s", name_and_type_ref_index, CHECK); @@ -603,7 +586,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, const int name_and_type_ref_index = cp->bootstrap_name_and_type_ref_index_at(index); - check_property(valid_cp_range(name_and_type_ref_index, length) && + guarantee_property(valid_cp_range(name_and_type_ref_index, length) && cp->tag_at(name_and_type_ref_index).is_name_and_type(), "Invalid constant pool index %u in class file %s", name_and_type_ref_index, CHECK); @@ -821,7 +804,7 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* const stream, for (index = 0; index < itfs_len; index++) { const u2 interface_index = stream->get_u2(CHECK); Klass* interf; - check_property( + guarantee_property( valid_klass_reference_at(interface_index), "Interface name has bad constant pool index %u in class file %s", interface_index, CHECK); @@ -943,6 +926,7 @@ class AnnotationCollector : public ResourceObj{ _method_ForceInline, _method_DontInline, _method_ChangesCurrentThread, + _method_JvmtiHideEvents, _method_JvmtiMountTransition, _method_InjectedProfile, _method_LambdaForm_Compiled, @@ -1255,10 +1239,10 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs, cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length const u2 attribute_name_index = cfs->get_u2_fast(); const u4 attribute_length = cfs->get_u4_fast(); - check_property(valid_symbol_at(attribute_name_index), - "Invalid field attribute index %u in class file %s", - attribute_name_index, - CHECK); + guarantee_property(valid_symbol_at(attribute_name_index), + "Invalid field attribute index %u in class file %s", + attribute_name_index, + CHECK); const Symbol* const attribute_name = cp->symbol_at(attribute_name_index); if (is_static && attribute_name == vmSymbols::tag_constant_value()) { @@ -1267,7 +1251,7 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs, classfile_parse_error("Duplicate ConstantValue attribute in class file %s", THREAD); return; } - check_property( + guarantee_property( attribute_length == 2, "Invalid ConstantValue field attribute length %u in class file %s", attribute_length, CHECK); @@ -1413,14 +1397,14 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, FieldInfo::FieldFlags fieldFlags(0); const u2 name_index = cfs->get_u2_fast(); - check_property(valid_symbol_at(name_index), + guarantee_property(valid_symbol_at(name_index), "Invalid constant pool index %u for field name in class file %s", name_index, CHECK); const Symbol* const name = cp->symbol_at(name_index); verify_legal_field_name(name, CHECK); const u2 signature_index = cfs->get_u2_fast(); - check_property(valid_symbol_at(signature_index), + guarantee_property(valid_symbol_at(signature_index), "Invalid constant pool index %u for field signature in class file %s", signature_index, CHECK); const Symbol* const sig = cp->symbol_at(signature_index); @@ -1598,7 +1582,7 @@ void ClassFileParser::parse_linenumber_table(u4 code_attribute_length, const unsigned int length_in_bytes = num_entries * (sizeof(u2) * 2); // Verify line number attribute and table length - check_property( + guarantee_property( code_attribute_length == sizeof(u2) + length_in_bytes, "LineNumberTable attribute has wrong length in class file %s", CHECK); @@ -1788,7 +1772,7 @@ const ClassFileParser::unsafe_u2* ClassFileParser::parse_checked_exceptions(cons cfs->guarantee_more(2 * len, CHECK_NULL); for (int i = 0; i < len; i++) { checked_exception = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_klass_reference_at(checked_exception), "Exception name has bad type at constant pool %u in class file %s", checked_exception, CHECK_NULL); @@ -1847,6 +1831,11 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data, if (!privileged) break; // only allow in privileged code return _method_ChangesCurrentThread; } + case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_JvmtiHideEvents_signature): { + if (_location != _in_method) break; // only allow for methods + if (!privileged) break; // only allow in privileged code + return _method_JvmtiHideEvents; + } case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_JvmtiMountTransition_signature): { if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code @@ -1934,6 +1923,8 @@ void MethodAnnotationCollector::apply_to(const methodHandle& m) { m->set_dont_inline(); if (has_annotation(_method_ChangesCurrentThread)) m->set_changes_current_thread(); + if (has_annotation(_method_JvmtiHideEvents)) + m->set_jvmti_hide_events(); if (has_annotation(_method_JvmtiMountTransition)) m->set_jvmti_mount_transition(); if (has_annotation(_method_InjectedProfile)) @@ -2137,7 +2128,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, int flags = cfs->get_u2_fast(); const u2 name_index = cfs->get_u2_fast(); const int cp_size = cp->length(); - check_property( + guarantee_property( valid_symbol_at(name_index), "Illegal constant pool index %u for method name in class file %s", name_index, CHECK_NULL); @@ -2235,7 +2226,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, cfs->guarantee_more(6, CHECK_NULL); // method_attribute_name_index, method_attribute_length const u2 method_attribute_name_index = cfs->get_u2_fast(); const u4 method_attribute_length = cfs->get_u4_fast(); - check_property( + guarantee_property( valid_symbol_at(method_attribute_name_index), "Invalid method attribute name index %u in class file %s", method_attribute_name_index, CHECK_NULL); @@ -2310,10 +2301,10 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, calculated_attribute_length += code_attribute_length + (unsigned)sizeof(code_attribute_name_index) + (unsigned)sizeof(code_attribute_length); - check_property(valid_symbol_at(code_attribute_name_index), - "Invalid code attribute name index %u in class file %s", - code_attribute_name_index, - CHECK_NULL); + guarantee_property(valid_symbol_at(code_attribute_name_index), + "Invalid code attribute name index %u in class file %s", + code_attribute_name_index, + CHECK_NULL); if (LoadLineNumberTables && cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) { // Parse and compress line number table @@ -2798,7 +2789,7 @@ u2 ClassFileParser::parse_generic_signature_attribute(const ClassFileStream* con cfs->guarantee_more(2, CHECK_0); // generic_signature_index const u2 generic_signature_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_symbol_at(generic_signature_index), "Invalid Signature attribute at constant pool index %u in class file %s", generic_signature_index, CHECK_0); @@ -2812,7 +2803,7 @@ void ClassFileParser::parse_classfile_sourcefile_attribute(const ClassFileStream cfs->guarantee_more(2, CHECK); // sourcefile_index const u2 sourcefile_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_symbol_at(sourcefile_index), "Invalid SourceFile attribute at constant pool index %u in class file %s", sourcefile_index, CHECK); @@ -2959,13 +2950,13 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea for (int n = 0; n < length; n++) { // Inner class index const u2 inner_class_info_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_klass_reference_at(inner_class_info_index), "inner_class_info_index %u has bad constant type in class file %s", inner_class_info_index, CHECK_0); // Outer class index const u2 outer_class_info_index = cfs->get_u2_fast(); - check_property( + guarantee_property( outer_class_info_index == 0 || valid_klass_reference_at(outer_class_info_index), "outer_class_info_index %u has bad constant type in class file %s", @@ -2979,7 +2970,7 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea } // Inner class name const u2 inner_name_index = cfs->get_u2_fast(); - check_property( + guarantee_property( inner_name_index == 0 || valid_symbol_at(inner_name_index), "inner_name_index %u has bad constant type in class file %s", inner_name_index, CHECK_0); @@ -3055,7 +3046,7 @@ u2 ClassFileParser::parse_classfile_nest_members_attribute(const ClassFileStream cfs->guarantee_more(2 * length, CHECK_0); for (int n = 0; n < length; n++) { const u2 class_info_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_klass_reference_at(class_info_index), "Nest member class_info_index %u has bad constant type in class file %s", class_info_index, CHECK_0); @@ -3088,7 +3079,7 @@ u2 ClassFileParser::parse_classfile_permitted_subclasses_attribute(const ClassFi cfs->guarantee_more(2 * length, CHECK_0); for (int n = 0; n < length; n++) { const u2 class_info_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_klass_reference_at(class_info_index), "Permitted subclass class_info_index %u has bad constant type in class file %s", class_info_index, CHECK_0); @@ -3137,14 +3128,14 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons cfs->guarantee_more(6, CHECK_0); // name_index, descriptor_index, attributes_count const u2 name_index = cfs->get_u2_fast(); - check_property(valid_symbol_at(name_index), + guarantee_property(valid_symbol_at(name_index), "Invalid constant pool index %u for name in Record attribute in class file %s", name_index, CHECK_0); const Symbol* const name = cp->symbol_at(name_index); verify_legal_field_name(name, CHECK_0); const u2 descriptor_index = cfs->get_u2_fast(); - check_property(valid_symbol_at(descriptor_index), + guarantee_property(valid_symbol_at(descriptor_index), "Invalid constant pool index %u for descriptor in Record attribute in class file %s", descriptor_index, CHECK_0); const Symbol* const descr = cp->symbol_at(descriptor_index); @@ -3167,7 +3158,7 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons const u2 attribute_name_index = cfs->get_u2_fast(); const u4 attribute_length = cfs->get_u4_fast(); calculate_attr_size += 6; - check_property( + guarantee_property( valid_symbol_at(attribute_name_index), "Invalid Record attribute name index %u in class file %s", attribute_name_index, CHECK_0); @@ -3265,7 +3256,7 @@ void ClassFileParser::parse_classfile_signature_attribute(const ClassFileStream* assert(cfs != nullptr, "invariant"); const u2 signature_index = cfs->get_u2(CHECK); - check_property( + guarantee_property( valid_symbol_at(signature_index), "Invalid constant pool index %u in Signature attribute in class file %s", signature_index, CHECK); @@ -3323,7 +3314,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil cfs->guarantee_more(sizeof(u2) * 2, CHECK); // bsm, argc const u2 bootstrap_method_index = cfs->get_u2_fast(); const u2 argument_count = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_cp_range(bootstrap_method_index, cp_size) && cp->tag_at(bootstrap_method_index).is_method_handle(), "bootstrap_method_index %u has bad constant type in class file %s", @@ -3340,7 +3331,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc] for (int j = 0; j < argument_count; j++) { const u2 argument_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_cp_range(argument_index, cp_size) && cp->tag_at(argument_index).is_loadable_constant(), "argument_index %u has bad constant type in class file %s", @@ -3401,7 +3392,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length const u2 attribute_name_index = cfs->get_u2_fast(); const u4 attribute_length = cfs->get_u4_fast(); - check_property( + guarantee_property( valid_symbol_at(attribute_name_index), "Attribute name has bad constant pool index %u in class file %s", attribute_name_index, CHECK); @@ -3513,7 +3504,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf return; } // Validate the constant pool indices and types - check_property(valid_klass_reference_at(enclosing_method_class_index), + guarantee_property(valid_klass_reference_at(enclosing_method_class_index), "Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); if (enclosing_method_method_index != 0 && (!cp->is_within_bounds(enclosing_method_method_index) || @@ -3580,7 +3571,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf } cfs->guarantee_more(2, CHECK); u2 class_info_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_klass_reference_at(class_info_index), "Nest-host class_info_index %u has bad constant type in class file %s", class_info_index, CHECK); @@ -3789,15 +3780,15 @@ const InstanceKlass* ClassFileParser::parse_super_class(ConstantPool* const cp, const InstanceKlass* super_klass = nullptr; if (super_class_index == 0) { - check_property(_class_name == vmSymbols::java_lang_Object(), - "Invalid superclass index %u in class file %s", - super_class_index, - CHECK_NULL); + guarantee_property(_class_name == vmSymbols::java_lang_Object(), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); } else { - check_property(valid_klass_reference_at(super_class_index), - "Invalid superclass index %u in class file %s", - super_class_index, - CHECK_NULL); + guarantee_property(valid_klass_reference_at(super_class_index), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); // The class name should be legal because it is checked when parsing constant pool. // However, make sure it is not an array type. bool is_array = false; @@ -4076,26 +4067,6 @@ void ClassFileParser::check_super_class_access(const InstanceKlass* this_klass, return; } - // If the loader is not the boot loader then throw an exception if its - // superclass is in package jdk.internal.reflect and its loader is not a - // special reflection class loader - if (!this_klass->class_loader_data()->is_the_null_class_loader_data()) { - PackageEntry* super_package = super->package(); - if (super_package != nullptr && - super_package->name()->fast_compare(vmSymbols::jdk_internal_reflect()) == 0 && - !java_lang_ClassLoader::is_reflection_class_loader(this_klass->class_loader())) { - ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_IllegalAccessError(), - "class %s loaded by %s cannot access jdk/internal/reflect superclass %s", - this_klass->external_name(), - this_klass->class_loader_data()->loader_name_and_id(), - super->external_name()); - return; - } - } - Reflection::VerifyClassAccessResults vca_result = Reflection::verify_class_access(this_klass, InstanceKlass::cast(super), false); if (vca_result != Reflection::ACCESS_OK) { @@ -5106,7 +5077,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, // Set PackageEntry for this_klass oop cl = ik->class_loader(); - Handle clh = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(cl)); + Handle clh = Handle(THREAD, cl); ClassLoaderData* cld = ClassLoaderData::class_loader_data_or_null(clh()); ik->set_package(cld, nullptr, CHECK); @@ -5543,7 +5514,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, // This class and superclass _this_class_index = stream->get_u2_fast(); - check_property( + guarantee_property( valid_cp_range(_this_class_index, cp_size) && cp->tag_at(_this_class_index).is_unresolved_klass(), "Invalid this class index %u in constant pool in class file %s", @@ -5724,9 +5695,9 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st assert(_loader_data != nullptr, "invariant"); if (_class_name == vmSymbols::java_lang_Object()) { - check_property(_local_interfaces == Universe::the_empty_instance_klass_array(), - "java.lang.Object cannot implement an interface in class file %s", - CHECK); + guarantee_property(_local_interfaces == Universe::the_empty_instance_klass_array(), + "java.lang.Object cannot implement an interface in class file %s", + CHECK); } // We check super class after class file is parsed and format is checked if (_super_class_index > 0 && nullptr == _super_klass) { diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index d32dd6d5f78b5..a8a388f8ded9e 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -378,44 +378,6 @@ class ClassFileParser { if (!b) { classfile_parse_error(msg, THREAD); return; } } - void report_assert_property_failure(const char* msg, TRAPS) const PRODUCT_RETURN; - void report_assert_property_failure(const char* msg, int index, TRAPS) const PRODUCT_RETURN; - - inline void assert_property(bool b, const char* msg, TRAPS) const { -#ifdef ASSERT - if (!b) { - report_assert_property_failure(msg, THREAD); - } -#endif - } - - inline void assert_property(bool b, const char* msg, int index, TRAPS) const { -#ifdef ASSERT - if (!b) { - report_assert_property_failure(msg, index, THREAD); - } -#endif - } - - inline void check_property(bool property, - const char* msg, - int index, - TRAPS) const { - if (_need_verify) { - guarantee_property(property, msg, index, CHECK); - } else { - assert_property(property, msg, index, CHECK); - } - } - - inline void check_property(bool property, const char* msg, TRAPS) const { - if (_need_verify) { - guarantee_property(property, msg, CHECK); - } else { - assert_property(property, msg, CHECK); - } - } - inline void guarantee_property(bool b, const char* msg, int index, diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index 487d69a6f4fc9..9a68e2640443f 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -582,6 +582,8 @@ void ClassLoader::setup_module_search_path(JavaThread* current, const char* path new_entry = create_class_path_entry(current, path, &st, false /*is_boot_append */, false /* from_class_path_attr */); if (new_entry != nullptr) { + // ClassLoaderExt::process_module_table() filters out non-jar entries before calling this function. + assert(new_entry->is_jar_file(), "module path entry %s is not a jar file", new_entry->name()); add_to_module_path_entries(path, new_entry); } } diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index fab012456d922..de0b16a907afb 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -644,8 +644,6 @@ Dictionary* ClassLoaderData::create_dictionary() { int size; if (_the_null_class_loader_data == nullptr) { size = _boot_loader_dictionary_size; - } else if (class_loader()->is_a(vmClasses::reflect_DelegatingClassLoader_klass())) { - size = 1; // there's only one class in relection class loader and no initiated classes } else if (is_system_class_loader_data()) { size = _boot_loader_dictionary_size; } else { @@ -815,8 +813,6 @@ ClassLoaderMetaspace* ClassLoaderData::metaspace_non_null() { metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::BootMetaspaceType); } else if (has_class_mirror_holder()) { metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ClassMirrorHolderMetaspaceType); - } else if (class_loader()->is_a(vmClasses::reflect_DelegatingClassLoader_klass())) { - metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType); } else { metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::StandardMetaspaceType); } diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp index 997f9d76676fa..b9e420899c2d6 100644 --- a/src/hotspot/share/classfile/classLoaderExt.cpp +++ b/src/hotspot/share/classfile/classLoaderExt.cpp @@ -55,6 +55,7 @@ jshort ClassLoaderExt::_app_class_paths_start_index = ClassLoaderExt::max_classpath_index; jshort ClassLoaderExt::_app_module_paths_start_index = ClassLoaderExt::max_classpath_index; jshort ClassLoaderExt::_max_used_path_index = 0; +int ClassLoaderExt::_num_module_paths = 0; bool ClassLoaderExt::_has_app_classes = false; bool ClassLoaderExt::_has_platform_classes = false; bool ClassLoaderExt::_has_non_jar_in_classpath = false; @@ -89,21 +90,25 @@ void ClassLoaderExt::setup_app_search_path(JavaThread* current) { os::free(app_class_path); } +int ClassLoaderExt::compare_module_names(const char** p1, const char** p2) { + return strcmp(*p1, *p2); +} + void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable* met) { ResourceMark rm(current); - GrowableArray* module_paths = new GrowableArray(5); + GrowableArray* module_paths = new GrowableArray(5); class ModulePathsGatherer : public ModuleClosure { JavaThread* _current; - GrowableArray* _module_paths; + GrowableArray* _module_paths; public: - ModulePathsGatherer(JavaThread* current, GrowableArray* module_paths) : + ModulePathsGatherer(JavaThread* current, GrowableArray* module_paths) : _current(current), _module_paths(module_paths) {} void do_module(ModuleEntry* m) { char* uri = m->location()->as_C_string(); if (strncmp(uri, "file:", 5) == 0) { char* path = ClassLoader::uri_to_path(uri); - _module_paths->append(path); + extract_jar_files_from_path(path, _module_paths); } } }; @@ -114,6 +119,10 @@ void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable* met->modules_do(&gatherer); } + // Sort the module paths before storing into CDS archive for simpler + // checking at runtime. + module_paths->sort(compare_module_names); + for (int i = 0; i < module_paths->length(); i++) { ClassLoader::setup_module_search_path(current, module_paths->at(i)); } @@ -129,6 +138,38 @@ void ClassLoaderExt::setup_module_paths(JavaThread* current) { process_module_table(current, met); } +bool ClassLoaderExt::has_jar_suffix(const char* filename) { + // In jdk.internal.module.ModulePath.readModule(), it checks for the ".jar" suffix. + // Performing the same check here. + const char* dot = strrchr(filename, '.'); + if (dot != nullptr && strcmp(dot + 1, "jar") == 0) { + return true; + } + return false; +} + +void ClassLoaderExt::extract_jar_files_from_path(const char* path, GrowableArray* module_paths) { + DIR* dirp = os::opendir(path); + if (dirp == nullptr && errno == ENOTDIR && has_jar_suffix(path)) { + module_paths->append(path); + } else { + if (dirp != nullptr) { + struct dirent* dentry; + while ((dentry = os::readdir(dirp)) != nullptr) { + const char* file_name = dentry->d_name; + if (has_jar_suffix(file_name)) { + size_t full_name_len = strlen(path) + strlen(file_name) + strlen(os::file_separator()) + 1; + char* full_name = NEW_RESOURCE_ARRAY(char, full_name_len); + int n = os::snprintf(full_name, full_name_len, "%s%s%s", path, os::file_separator(), file_name); + assert((size_t)n == full_name_len - 1, "Unexpected number of characters in string"); + module_paths->append(full_name); + } + } + os::closedir(dirp); + } + } +} + char* ClassLoaderExt::read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size, bool clean_text) { const char* name = "META-INF/MANIFEST.MF"; diff --git a/src/hotspot/share/classfile/classLoaderExt.hpp b/src/hotspot/share/classfile/classLoaderExt.hpp index b76ce3ff33a32..1f1b38cd3121c 100644 --- a/src/hotspot/share/classfile/classLoaderExt.hpp +++ b/src/hotspot/share/classfile/classLoaderExt.hpp @@ -53,12 +53,15 @@ class ClassLoaderExt: public ClassLoader { // AllStatic static jshort _app_module_paths_start_index; // the largest path index being used during CDS dump time static jshort _max_used_path_index; + // number of module paths + static int _num_module_paths; static bool _has_app_classes; static bool _has_platform_classes; static bool _has_non_jar_in_classpath; static char* read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size, bool clean_text); + static bool has_jar_suffix(const char* filename); public: static void process_jar_manifest(JavaThread* current, ClassPathEntry* entry); @@ -68,6 +71,8 @@ class ClassLoaderExt: public ClassLoader { // AllStatic static void setup_search_paths(JavaThread* current); static void setup_module_paths(JavaThread* current); + static void extract_jar_files_from_path(const char* path, GrowableArray* module_paths); + static int compare_module_names(const char** p1, const char** p2); static char* read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size) { // Remove all the new-line continuations (which wrap long lines at 72 characters, see @@ -87,6 +92,8 @@ class ClassLoaderExt: public ClassLoader { // AllStatic static jshort max_used_path_index() { return _max_used_path_index; } + static int num_module_paths() { return _num_module_paths; } + static void set_max_used_path_index(jshort used_index) { _max_used_path_index = used_index; } @@ -99,6 +106,10 @@ class ClassLoaderExt: public ClassLoader { // AllStatic _app_module_paths_start_index = module_start; } + static void init_num_module_paths(int num_module_paths) { + _num_module_paths = num_module_paths; + } + static bool is_boot_classpath(int classpath_index) { return classpath_index < _app_class_paths_start_index; } diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp index cda64788acffa..9b0d80b2a5583 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp @@ -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 @@ -101,17 +101,13 @@ class LayoutRawBlock : public ResourceObj { // sort fields in decreasing order. // Note: with line types, the comparison should include alignment constraint if sizes are equals static int compare_size_inverted(LayoutRawBlock** x, LayoutRawBlock** y) { -#ifdef _WINDOWS - // qsort() on Windows reverse the order of fields with the same size - // the extension of the comparison function below preserves this order int diff = (*y)->size() - (*x)->size(); + // qsort() may reverse the order of fields with the same size. + // The extension is to ensure stable sort. if (diff == 0) { diff = (*x)->field_index() - (*y)->field_index(); } return diff; -#else - return (*y)->size() - (*x)->size(); -#endif // _WINDOWS } }; diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 0ad36cd21dbf3..3dce1a343d896 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -4763,9 +4763,6 @@ bool java_lang_ClassLoader::parallelCapable(oop class_loader) { } bool java_lang_ClassLoader::is_trusted_loader(oop loader) { - // Fix for 4474172; see evaluation for more details - loader = non_reflection_class_loader(loader); - oop cl = SystemDictionary::java_system_loader(); while(cl != nullptr) { if (cl == loader) return true; @@ -4774,29 +4771,6 @@ bool java_lang_ClassLoader::is_trusted_loader(oop loader) { return false; } -// Return true if this is one of the class loaders associated with -// the generated bytecodes for serialization constructor returned -// by sun.reflect.ReflectionFactory::newConstructorForSerialization -bool java_lang_ClassLoader::is_reflection_class_loader(oop loader) { - if (loader != nullptr) { - Klass* delegating_cl_class = vmClasses::reflect_DelegatingClassLoader_klass(); - // This might be null in non-1.4 JDKs - return (delegating_cl_class != nullptr && loader->is_a(delegating_cl_class)); - } - return false; -} - -oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) { - // See whether this is one of the class loaders associated with - // the generated bytecodes for reflection, and if so, "magically" - // delegate to its parent to prevent class loading from occurring - // in places where applications using reflection didn't expect it. - if (is_reflection_class_loader(loader)) { - return parent(loader); - } - return loader; -} - oop java_lang_ClassLoader::unnamedModule(oop loader) { assert(is_instance(loader), "loader must be oop"); return loader->obj_field(_unnamedModule_offset); diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 6f82a75e8ffeb..6ab73b161f4f0 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -1502,14 +1502,6 @@ class java_lang_ClassLoader : AllStatic { static bool is_trusted_loader(oop loader); - // Return true if this is one of the class loaders associated with - // the generated bytecodes for serialization constructor returned - // by sun.reflect.ReflectionFactory::newConstructorForSerialization - static bool is_reflection_class_loader(oop loader); - - // Fix for 4474172 - static oop non_reflection_class_loader(oop loader); - // Testers static bool is_subclass(Klass* klass) { return klass->is_subclass_of(vmClasses::ClassLoader_klass()); diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp index 14e730f7a3359..94e407d045fb5 100644 --- a/src/hotspot/share/classfile/modules.cpp +++ b/src/hotspot/share/classfile/modules.cpp @@ -30,6 +30,7 @@ #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/classLoaderDataShared.hpp" +#include "classfile/classLoaderExt.hpp" #include "classfile/javaAssertions.hpp" #include "classfile/javaClasses.hpp" #include "classfile/javaClasses.inline.hpp" @@ -309,11 +310,6 @@ void Modules::define_module(Handle module, jboolean is_open, jstring version, } oop loader = java_lang_Module::loader(module()); - // Make sure loader is not the jdk.internal.reflect.DelegatingClassLoader. - if (loader != java_lang_ClassLoader::non_reflection_class_loader(loader)) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Class loader is an invalid delegating class loader"); - } Handle h_loader = Handle(THREAD, loader); // define_module can be called during start-up, before the class loader's ClassLoaderData // has been created. SystemDictionary::register_loader ensures creation, if needed. @@ -565,6 +561,7 @@ void Modules::verify_archived_modules() { } char* Modules::_archived_main_module_name = nullptr; +char* Modules::_archived_addmods_names = nullptr; void Modules::dump_main_module_name() { const char* module_name = Arguments::get_property("jdk.module.main"); @@ -605,6 +602,100 @@ void Modules::serialize(SerializeClosure* soc) { } } +void Modules::dump_addmods_names() { + unsigned int count = Arguments::addmods_count(); + const char* addmods_names = get_addmods_names_as_sorted_string(); + if (addmods_names != nullptr) { + _archived_addmods_names = ArchiveBuilder::current()->ro_strdup(addmods_names); + } + ArchivePtrMarker::mark_pointer(&_archived_addmods_names); +} + +void Modules::serialize_addmods_names(SerializeClosure* soc) { + soc->do_ptr(&_archived_addmods_names); + if (soc->reading()) { + bool disable = false; + if (_archived_addmods_names[0] != '\0') { + if (Arguments::addmods_count() == 0) { + log_info(cds)("--add-modules module name(s) found in archive but not specified during runtime: %s", + _archived_addmods_names); + disable = true; + } else { + const char* addmods_names = get_addmods_names_as_sorted_string(); + if (strcmp((const char*)_archived_addmods_names, addmods_names) != 0) { + log_info(cds)("Mismatched --add-modules module name(s)."); + log_info(cds)(" dump time: %s runtime: %s", _archived_addmods_names, addmods_names); + disable = true; + } + } + } else { + if (Arguments::addmods_count() > 0) { + log_info(cds)("--add-modules module name(s) specified during runtime but not found in archive: %s", + get_addmods_names_as_sorted_string()); + disable = true; + } + } + if (disable) { + log_info(cds)("Disabling optimized module handling"); + CDSConfig::stop_using_optimized_module_handling(); + } + log_info(cds)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled"); + log_info(cds)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled"); + } +} + +const char* Modules::get_addmods_names_as_sorted_string() { + ResourceMark rm; + const int max_digits = 3; + const int extra_symbols_count = 2; // includes '.', '\0' + size_t prop_len = strlen("jdk.module.addmods") + max_digits + extra_symbols_count; + char* prop_name = resource_allocate_bytes(prop_len); + GrowableArray list; + for (unsigned int i = 0; i < Arguments::addmods_count(); i++) { + jio_snprintf(prop_name, prop_len, "jdk.module.addmods.%d", i); + const char* prop_value = Arguments::get_property(prop_name); + char* p = resource_allocate_bytes(strlen(prop_value) + 1); + strcpy(p, prop_value); + while (*p == ',') p++; // skip leading commas + while (*p) { + char* next = strchr(p, ','); + if (next == nullptr) { + // no more commas, p is the last element + list.append(p); + break; + } else { + *next = 0; + list.append(p); + p = next + 1; + } + } + } + + // Example: + // --add-modules=java.compiler --add-modules=java.base,java.base,, + // + // list[0] = "java.compiler" + // list[1] = "java.base" + // list[2] = "java.base" + // list[3] = "" + // list[4] = "" + list.sort(ClassLoaderExt::compare_module_names); + + const char* prefix = ""; + stringStream st; + const char* last_string = ""; // This also filters out all empty strings + for (int i = 0; i < list.length(); i++) { + const char* m = list.at(i); + if (strcmp(m, last_string) != 0) { // filter out duplicates + st.print("%s%s", prefix, m); + last_string = m; + prefix = "\n"; + } + } + + return (const char*)os::strdup(st.as_string()); // Example: "java.base,java.compiler" +} + void Modules::define_archived_modules(Handle h_platform_loader, Handle h_system_loader, TRAPS) { assert(CDSConfig::is_using_full_module_graph(), "must be"); diff --git a/src/hotspot/share/classfile/modules.hpp b/src/hotspot/share/classfile/modules.hpp index 3866f0d6f9b82..3ef6f57a57b4c 100644 --- a/src/hotspot/share/classfile/modules.hpp +++ b/src/hotspot/share/classfile/modules.hpp @@ -61,9 +61,13 @@ class Modules : AllStatic { static void verify_archived_modules() NOT_CDS_JAVA_HEAP_RETURN; static void dump_main_module_name() NOT_CDS_JAVA_HEAP_RETURN; static void serialize(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; + static void dump_addmods_names() NOT_CDS_JAVA_HEAP_RETURN; + static void serialize_addmods_names(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; + static const char* get_addmods_names_as_sorted_string() NOT_CDS_JAVA_HEAP_RETURN_(nullptr); #if INCLUDE_CDS_JAVA_HEAP static char* _archived_main_module_name; + static char* _archived_addmods_names; #endif // Provides the java.lang.Module for the unnamed module defined diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 7b307a0b8a37c..2338a179324b6 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -598,8 +598,6 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, HandleMark hm(THREAD); - // Fix for 4474172; see evaluation for more details - class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader())); ClassLoaderData* loader_data = register_loader(class_loader); Dictionary* dictionary = loader_data->dictionary(); @@ -765,12 +763,7 @@ InstanceKlass* SystemDictionary::find_instance_klass(Thread* current, Handle class_loader, Handle protection_domain) { - // The result of this call should be consistent with the result - // of the call to resolve_instance_class_or_null(). - // See evaluation 6790209 and 4474172 for more details. - oop class_loader_oop = java_lang_ClassLoader::non_reflection_class_loader(class_loader()); - ClassLoaderData* loader_data = ClassLoaderData::class_loader_data_or_null(class_loader_oop); - + ClassLoaderData* loader_data = ClassLoaderData::class_loader_data_or_null(class_loader()); if (loader_data == nullptr) { // If the ClassLoaderData has not been setup, // then the class loader has no entries in the dictionary. diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index ce7f862a7b6c2..05f6ace9b8a95 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -403,9 +403,6 @@ InstanceKlass* SystemDictionaryShared::find_or_load_shared_class( if (SystemDictionary::is_system_class_loader(class_loader()) || SystemDictionary::is_platform_class_loader(class_loader())) { - // Fix for 4474172; see evaluation for more details - class_loader = Handle( - THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader())); ClassLoaderData *loader_data = register_loader(class_loader); Dictionary* dictionary = loader_data->dictionary(); diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index a66fbf645f55f..b34cde4c63ab6 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -32,6 +32,7 @@ #include "classfile/stackMapTableFormat.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" +#include "classfile/systemDictionaryShared.hpp" #include "classfile/verifier.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" @@ -212,6 +213,11 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) { exception_name == vmSymbols::java_lang_ClassFormatError())) { log_info(verification)("Fail over class verification to old verifier for: %s", klass->external_name()); log_info(class, init)("Fail over class verification to old verifier for: %s", klass->external_name()); + // Exclude any classes that fail over during dynamic dumping + if (CDSConfig::is_dumping_dynamic_archive()) { + SystemDictionaryShared::warn_excluded(klass, "Failed over class verification while dynamic dumping"); + SystemDictionaryShared::set_excluded(klass); + } message_buffer = NEW_RESOURCE_ARRAY(char, message_buffer_len); exception_message = message_buffer; exception_name = inference_verify( @@ -269,10 +275,6 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) { bool Verifier::is_eligible_for_verification(InstanceKlass* klass, bool should_verify_class) { Symbol* name = klass->name(); - Klass* refl_serialization_ctor_klass = vmClasses::reflect_SerializationConstructorAccessorImpl_klass(); - - bool is_reflect_accessor = refl_serialization_ctor_klass != nullptr && - klass->is_subtype_of(refl_serialization_ctor_klass); return (should_verify_for(klass->class_loader(), should_verify_class) && // return if the class is a bootstrapping class @@ -289,12 +291,7 @@ bool Verifier::is_eligible_for_verification(InstanceKlass* klass, bool should_ve // Shared classes shouldn't have stackmaps either. // However, bytecodes for shared old classes can be verified because // they have not been rewritten. - !(klass->is_shared() && klass->is_rewritten()) && - - // As of the fix for 4486457 we disable verification for all of the - // dynamically-generated bytecodes associated with - // jdk/internal/reflect/SerializationConstructorAccessor. - (!is_reflect_accessor)); + !(klass->is_shared() && klass->is_rewritten())); } Symbol* Verifier::inference_verify( diff --git a/src/hotspot/share/classfile/vmClassMacros.hpp b/src/hotspot/share/classfile/vmClassMacros.hpp index 10fa89007957c..395e718c55d83 100644 --- a/src/hotspot/share/classfile/vmClassMacros.hpp +++ b/src/hotspot/share/classfile/vmClassMacros.hpp @@ -107,11 +107,9 @@ do_klass(StackChunk_klass, jdk_internal_vm_StackChunk ) \ \ do_klass(reflect_MethodAccessorImpl_klass, reflect_MethodAccessorImpl ) \ - do_klass(reflect_DelegatingClassLoader_klass, reflect_DelegatingClassLoader ) \ do_klass(reflect_ConstantPool_klass, reflect_ConstantPool ) \ do_klass(reflect_CallerSensitive_klass, reflect_CallerSensitive ) \ do_klass(reflect_DirectConstructorHandleAccessor_NativeAccessor_klass, reflect_DirectConstructorHandleAccessor_NativeAccessor) \ - do_klass(reflect_SerializationConstructorAccessorImpl_klass, reflect_SerializationConstructorAccessorImpl ) \ \ /* support for dynamic typing */ \ do_klass(DirectMethodHandle_klass, java_lang_invoke_DirectMethodHandle ) \ diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index b6ce21797a618..68121c56c328f 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -469,6 +469,8 @@ class methodHandle; do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \ do_intrinsic(_Reference_refersTo0, java_lang_ref_Reference, refersTo0_name, object_boolean_signature, F_RN) \ do_intrinsic(_PhantomReference_refersTo0, java_lang_ref_PhantomReference, refersTo0_name, object_boolean_signature, F_RN) \ + do_intrinsic(_Reference_clear0, java_lang_ref_Reference, clear0_name, void_method_signature, F_RN) \ + do_intrinsic(_PhantomReference_clear0, java_lang_ref_PhantomReference, clear0_name, void_method_signature, F_RN) \ \ /* support for com.sun.crypto.provider.AESCrypt and some of its callers */ \ do_class(com_sun_crypto_provider_aescrypt, "com/sun/crypto/provider/AESCrypt") \ @@ -609,7 +611,6 @@ class methodHandle; do_intrinsic(_notifyJvmtiVThreadEnd, java_lang_VirtualThread, notifyJvmtiEnd_name, void_method_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadHideFrames, java_lang_VirtualThread, notifyJvmtiHideFrames_name, bool_void_signature, F_SN) \ do_intrinsic(_notifyJvmtiVThreadDisableSuspend, java_lang_VirtualThread, notifyJvmtiDisableSuspend_name, bool_void_signature, F_SN) \ \ /* support for UnsafeConstants */ \ @@ -979,6 +980,17 @@ class methodHandle; "Ljdk/internal/vm/vector/VectorSupport$Vector;") \ do_name(vector_ternary_op_name, "ternaryOp") \ \ + do_intrinsic(_VectorSelectFromTwoVectorOp, jdk_internal_vm_vector_VectorSupport, vector_select_from_op_name, vector_select_from_op_sig, F_S) \ + do_signature(vector_select_from_op_sig, "(Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "I" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ + "Ljdk/internal/vm/vector/VectorSupport$SelectFromTwoVector;)" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;") \ + do_name(vector_select_from_op_name, "selectFromTwoVectorOp") \ + \ do_intrinsic(_VectorFromBitsCoerced, jdk_internal_vm_vector_VectorSupport, vector_frombits_coerced_name, vector_frombits_coerced_sig, F_S) \ do_signature(vector_frombits_coerced_sig, "(Ljava/lang/Class;" \ "Ljava/lang/Class;" \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index a65ab86fa0a8d..d8018cd0c8af2 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -262,12 +262,10 @@ class SerializeClosure; \ template(jdk_internal_reflect, "jdk/internal/reflect") \ template(reflect_MethodAccessorImpl, "jdk/internal/reflect/MethodAccessorImpl") \ - template(reflect_DelegatingClassLoader, "jdk/internal/reflect/DelegatingClassLoader") \ template(reflect_Reflection, "jdk/internal/reflect/Reflection") \ template(reflect_CallerSensitive, "jdk/internal/reflect/CallerSensitive") \ template(reflect_CallerSensitive_signature, "Ljdk/internal/reflect/CallerSensitive;") \ template(reflect_DirectConstructorHandleAccessor_NativeAccessor, "jdk/internal/reflect/DirectConstructorHandleAccessor$NativeAccessor") \ - template(reflect_SerializationConstructorAccessorImpl, "jdk/internal/reflect/SerializationConstructorAccessorImpl") \ template(clazz_name, "clazz") \ template(exceptionTypes_name, "exceptionTypes") \ template(modifiers_name, "modifiers") \ @@ -308,6 +306,7 @@ class SerializeClosure; template(jdk_internal_vm_annotation_Stable_signature, "Ljdk/internal/vm/annotation/Stable;") \ \ template(jdk_internal_vm_annotation_ChangesCurrentThread_signature, "Ljdk/internal/vm/annotation/ChangesCurrentThread;") \ + template(jdk_internal_vm_annotation_JvmtiHideEvents_signature, "Ljdk/internal/vm/annotation/JvmtiHideEvents;") \ template(jdk_internal_vm_annotation_JvmtiMountTransition_signature, "Ljdk/internal/vm/annotation/JvmtiMountTransition;") \ \ /* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \ @@ -399,7 +398,6 @@ class SerializeClosure; template(notifyJvmtiEnd_name, "notifyJvmtiEnd") \ template(notifyJvmtiMount_name, "notifyJvmtiMount") \ template(notifyJvmtiUnmount_name, "notifyJvmtiUnmount") \ - template(notifyJvmtiHideFrames_name, "notifyJvmtiHideFrames") \ template(notifyJvmtiDisableSuspend_name, "notifyJvmtiDisableSuspend") \ template(doYield_name, "doYield") \ template(enter_name, "enter") \ @@ -426,6 +424,7 @@ class SerializeClosure; template(cs_name, "cs") \ template(get_name, "get") \ template(refersTo0_name, "refersTo0") \ + template(clear0_name, "clear0") \ template(put_name, "put") \ template(type_name, "type") \ template(findNative_name, "findNative") \ diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 81c4d001078cb..23f621ffec832 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -41,7 +41,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaFrameAnchor.hpp" -#include "runtime/jniHandles.hpp" +#include "runtime/jniHandles.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/sharedRuntime.hpp" @@ -623,7 +623,7 @@ UpcallStub* UpcallStub::create(const char* name, CodeBuffer* cb, jobject receive // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); - trace_new_stub(blob, "UpcallStub"); + trace_new_stub(blob, "UpcallStub - ", name); return blob; } @@ -772,6 +772,10 @@ void UpcallStub::verify() { void UpcallStub::print_on(outputStream* st) const { RuntimeBlob::print_on(st); print_value_on(st); + st->print_cr("Frame data offset: %d", (int) _frame_data_offset); + oop recv = JNIHandles::resolve(_receiver); + st->print("Receiver MH="); + recv->print_on(st); Disassembler::decode((RuntimeBlob*)this, st); } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 0bab731ac565e..7fb72997749dc 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -2048,7 +2048,7 @@ bool nmethod::make_not_entrant() { } // leave critical region under NMethodState_lock #if INCLUDE_JVMCI - // Invalidate can't occur while holding the Patching lock + // Invalidate can't occur while holding the NMethodState_lock JVMCINMethodData* nmethod_data = jvmci_nmethod_data(); if (nmethod_data != nullptr) { nmethod_data->invalidate_nmethod_mirror(this); diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp index e212200a47c65..e6329f3e65579 100644 --- a/src/hotspot/share/compiler/compilerThread.cpp +++ b/src/hotspot/share/compiler/compilerThread.cpp @@ -55,8 +55,11 @@ CompilerThread::~CompilerThread() { } void CompilerThread::set_compiler(AbstractCompiler* c) { - // Only jvmci compiler threads can call Java - _can_call_java = c != nullptr && c->is_jvmci(); + /* + * Compiler threads need to make Java upcalls to the jargraal compiler. + * Java upcalls are also needed by the InterpreterRuntime when using jargraal. + */ + _can_call_java = c != nullptr && c->is_jvmci() JVMCI_ONLY(&& !UseJVMCINativeLibrary); _compiler = c; } diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp index f22d1c22ac8a7..b2b522c1435e6 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp @@ -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. * Copyright (c) 2017, 2022, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -128,7 +128,7 @@ class EpsilonHeap : public CollectedHeap { bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); } // Support for loading objects from CDS archive into the heap - bool can_load_archived_objects() const override { return UseCompressedOops; } + bool can_load_archived_objects() const override { return true; } HeapWord* allocate_loaded_archive_space(size_t size) override; void print_on(outputStream* st) const override; diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 13b993546cde4..edbf0e902392b 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -24,49 +24,32 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" +#include "code/vmreg.inline.hpp" #include "gc/g1/c2/g1BarrierSetC2.hpp" #include "gc/g1/g1BarrierSet.hpp" +#include "gc/g1/g1BarrierSetAssembler.hpp" #include "gc/g1/g1BarrierSetRuntime.hpp" #include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "opto/arraycopynode.hpp" +#include "opto/block.hpp" #include "opto/compile.hpp" #include "opto/escape.hpp" #include "opto/graphKit.hpp" #include "opto/idealKit.hpp" +#include "opto/machnode.hpp" #include "opto/macro.hpp" +#include "opto/memnode.hpp" +#include "opto/node.hpp" +#include "opto/output.hpp" +#include "opto/regalloc.hpp" #include "opto/rootnode.hpp" +#include "opto/runtime.hpp" #include "opto/type.hpp" +#include "utilities/growableArray.hpp" #include "utilities/macros.hpp" -const TypeFunc *G1BarrierSetC2::write_ref_field_pre_entry_Type() { - const Type **fields = TypeTuple::fields(2); - fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value - fields[TypeFunc::Parms+1] = TypeRawPtr::NOTNULL; // thread - const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields); - - // create result type (range) - fields = TypeTuple::fields(0); - const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields); - - return TypeFunc::make(domain, range); -} - -const TypeFunc *G1BarrierSetC2::write_ref_field_post_entry_Type() { - const Type **fields = TypeTuple::fields(2); - fields[TypeFunc::Parms+0] = TypeRawPtr::NOTNULL; // Card addr - fields[TypeFunc::Parms+1] = TypeRawPtr::NOTNULL; // thread - const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields); - - // create result type (range) - fields = TypeTuple::fields(0); - const TypeTuple *range = TypeTuple::make(TypeFunc::Parms, fields); - - return TypeFunc::make(domain, range); -} - -#define __ ideal. /* * Determine if the G1 pre-barrier can be removed. The pre-barrier is * required by SATB to make sure all objects live at the start of the @@ -84,8 +67,6 @@ const TypeFunc *G1BarrierSetC2::write_ref_field_post_entry_Type() { * The compiler needs to determine that the object in which a field is about * to be written is newly allocated, and that no prior store to the same field * has happened since the allocation. - * - * Returns true if the pre-barrier can be removed */ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, PhaseValues* phase, @@ -97,34 +78,28 @@ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, AllocateNode* alloc = AllocateNode::Ideal_allocation(base); if (offset == Type::OffsetBot) { - return false; // cannot unalias unless there are precise offsets + return false; // Cannot unalias unless there are precise offsets. } - if (alloc == nullptr) { - return false; // No allocation found + return false; // No allocation found. } intptr_t size_in_bytes = type2aelembytes(bt); - - Node* mem = kit->memory(adr_idx); // start searching here... + Node* mem = kit->memory(adr_idx); // Start searching here. for (int cnt = 0; cnt < 50; cnt++) { - if (mem->is_Store()) { - Node* st_adr = mem->in(MemNode::Address); intptr_t st_offset = 0; Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, phase, st_offset); if (st_base == nullptr) { - break; // inscrutable pointer + break; // Inscrutable pointer. } - - // Break we have found a store with same base and offset as ours so break if (st_base == base && st_offset == offset) { + // We have found a store with same base and offset as ours. break; } - if (st_offset != offset && st_offset != Type::OffsetBot) { const int MAX_STORE = BytesPerLong; if (st_offset >= offset + size_in_bytes || @@ -136,20 +111,18 @@ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, // in the same sequence of RawMem effects. We sometimes initialize // a whole 'tile' of array elements with a single jint or jlong.) mem = mem->in(MemNode::Memory); - continue; // advance through independent store memory + continue; // Advance through independent store memory. } } - if (st_base != base && MemNode::detect_ptr_independence(base, alloc, st_base, AllocateNode::Ideal_allocation(st_base), phase)) { - // Success: The bases are provably independent. + // Success: the bases are provably independent. mem = mem->in(MemNode::Memory); - continue; // advance through independent store memory + continue; // Advance through independent store memory. } } else if (mem->is_Proj() && mem->in(0)->is_Initialize()) { - InitializeNode* st_init = mem->in(0)->as_Initialize(); AllocateNode* st_alloc = st_init->allocation(); @@ -157,7 +130,7 @@ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, // The alloc variable is guaranteed to not be null here from earlier check. if (alloc == st_alloc) { // Check that the initialization is storing null so that no previous store - // has been moved up and directly write a reference + // has been moved up and directly write a reference. Node* captured_store = st_init->find_captured_store(offset, type2aelembytes(T_OBJECT), phase); @@ -166,164 +139,55 @@ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, } } } - // Unless there is an explicit 'continue', we must bail out here, // because 'mem' is an inscrutable memory state (e.g., a call). break; } - return false; } -// G1 pre/post barriers -void G1BarrierSetC2::pre_barrier(GraphKit* kit, - bool do_load, - Node* ctl, - Node* obj, - Node* adr, - uint alias_idx, - Node* val, - const TypeOopPtr* val_type, - Node* pre_val, - BasicType bt) const { - // Some sanity checks - // Note: val is unused in this routine. - - if (do_load) { - // We need to generate the load of the previous value - assert(obj != nullptr, "must have a base"); - assert(adr != nullptr, "where are loading from?"); - assert(pre_val == nullptr, "loaded already?"); - assert(val_type != nullptr, "need a type"); - - if (use_ReduceInitialCardMarks() - && g1_can_remove_pre_barrier(kit, &kit->gvn(), adr, bt, alias_idx)) { - return; - } - - } else { - // In this case both val_type and alias_idx are unused. - assert(pre_val != nullptr, "must be loaded already"); - // Nothing to be done if pre_val is null. - if (pre_val->bottom_type() == TypePtr::NULL_PTR) return; - assert(pre_val->bottom_type()->basic_type() == T_OBJECT, "or we shouldn't be here"); - } - assert(bt == T_OBJECT, "or we shouldn't be here"); - - IdealKit ideal(kit, true); - - Node* tls = __ thread(); // ThreadLocalStorage - - Node* no_base = __ top(); - Node* zero = __ ConI(0); - Node* zeroX = __ ConX(0); - - float likely = PROB_LIKELY(0.999); - float unlikely = PROB_UNLIKELY(0.999); - - BasicType active_type = in_bytes(SATBMarkQueue::byte_width_of_active()) == 4 ? T_INT : T_BYTE; - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 4 || in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "flag width"); - - // Offsets into the thread - const int marking_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - const int index_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); - const int buffer_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - - // Now the actual pointers into the thread - Node* marking_adr = __ AddP(no_base, tls, __ ConX(marking_offset)); - Node* buffer_adr = __ AddP(no_base, tls, __ ConX(buffer_offset)); - Node* index_adr = __ AddP(no_base, tls, __ ConX(index_offset)); - - // Now some of the values - Node* marking = __ load(__ ctrl(), marking_adr, TypeInt::INT, active_type, Compile::AliasIdxRaw); - - // if (!marking) - __ if_then(marking, BoolTest::ne, zero, unlikely); { - BasicType index_bt = TypeX_X->basic_type(); - assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 SATBMarkQueue::_index with wrong size."); - Node* index = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw); - - if (do_load) { - // load original value - pre_val = __ load(__ ctrl(), adr, val_type, bt, alias_idx, false, MemNode::unordered, LoadNode::Pinned); - } - - // if (pre_val != nullptr) - __ if_then(pre_val, BoolTest::ne, kit->null()); { - Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw); - - // is the queue for this thread full? - __ if_then(index, BoolTest::ne, zeroX, likely); { - - // decrement the index - Node* next_index = kit->gvn().transform(new SubXNode(index, __ ConX(sizeof(intptr_t)))); - - // Now get the buffer location we will log the previous value into and store it - Node *log_addr = __ AddP(no_base, buffer, next_index); - __ store(__ ctrl(), log_addr, pre_val, T_OBJECT, Compile::AliasIdxRaw, MemNode::unordered); - // update the index - __ store(__ ctrl(), index_adr, next_index, index_bt, Compile::AliasIdxRaw, MemNode::unordered); - - } __ else_(); { - - // logging buffer is full, call the runtime - const TypeFunc *tf = write_ref_field_pre_entry_Type(); - __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), "write_ref_field_pre_entry", pre_val, tls); - } __ end_if(); // (!index) - } __ end_if(); // (pre_val != nullptr) - } __ end_if(); // (!marking) - - // Final sync IdealKit and GraphKit. - kit->final_sync(ideal); -} - /* - * G1 similar to any GC with a Young Generation requires a way to keep track of - * references from Old Generation to Young Generation to make sure all live + * G1, similar to any GC with a Young Generation, requires a way to keep track + * of references from Old Generation to Young Generation to make sure all live * objects are found. G1 also requires to keep track of object references * between different regions to enable evacuation of old regions, which is done - * as part of mixed collections. References are tracked in remembered sets and - * is continuously updated as reference are written to with the help of the - * post-barrier. + * as part of mixed collections. References are tracked in remembered sets, + * which are continuously updated as references are written to with the help of + * the post-barrier. * - * To reduce the number of updates to the remembered set the post-barrier - * filters updates to fields in objects located in the Young Generation, - * the same region as the reference, when the null is being written or - * if the card is already marked as dirty by an earlier write. + * To reduce the number of updates to the remembered set, the post-barrier + * filters out updates to fields in objects located in the Young Generation, the + * same region as the reference, when null is being written, or if the card is + * already marked as dirty by an earlier write. * * Under certain circumstances it is possible to avoid generating the - * post-barrier completely if it is possible during compile time to prove - * the object is newly allocated and that no safepoint exists between the - * allocation and the store. - * - * In the case of slow allocation the allocation code must handle the barrier - * as part of the allocation in the case the allocated object is not located - * in the nursery; this would happen for humongous objects. + * post-barrier completely, if it is possible during compile time to prove the + * object is newly allocated and that no safepoint exists between the allocation + * and the store. This can be seen as a compile-time version of the + * above-mentioned Young Generation filter. * - * Returns true if the post barrier can be removed + * In the case of a slow allocation, the allocation code must handle the barrier + * as part of the allocation if the allocated object is not located in the + * nursery; this would happen for humongous objects. */ bool G1BarrierSetC2::g1_can_remove_post_barrier(GraphKit* kit, - PhaseValues* phase, Node* store, + PhaseValues* phase, Node* store_ctrl, Node* adr) const { intptr_t offset = 0; Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset); AllocateNode* alloc = AllocateNode::Ideal_allocation(base); if (offset == Type::OffsetBot) { - return false; // cannot unalias unless there are precise offsets + return false; // Cannot unalias unless there are precise offsets. } - if (alloc == nullptr) { - return false; // No allocation found + return false; // No allocation found. } - // Start search from Store node - Node* mem = store->in(MemNode::Control); + Node* mem = store_ctrl; // Start search from Store node. if (mem->is_Proj() && mem->in(0)->is_Initialize()) { - InitializeNode* st_init = mem->in(0)->as_Initialize(); AllocateNode* st_alloc = st_init->allocation(); - // Make sure we are looking at the same allocation if (alloc == st_alloc) { return true; @@ -333,725 +197,367 @@ bool G1BarrierSetC2::g1_can_remove_post_barrier(GraphKit* kit, return false; } -// -// Update the card table and add card address to the queue -// -void G1BarrierSetC2::g1_mark_card(GraphKit* kit, - IdealKit& ideal, - Node* card_adr, - Node* oop_store, - uint oop_alias_idx, - Node* index, - Node* index_adr, - Node* buffer, - const TypeFunc* tf) const { - Node* zero = __ ConI(0); - Node* zeroX = __ ConX(0); - Node* no_base = __ top(); - BasicType card_bt = T_BYTE; - // Smash zero into card. MUST BE ORDERED WRT TO STORE - __ storeCM(__ ctrl(), card_adr, zero, oop_store, oop_alias_idx, card_bt, Compile::AliasIdxRaw); - - // Now do the queue work - __ if_then(index, BoolTest::ne, zeroX); { - - Node* next_index = kit->gvn().transform(new SubXNode(index, __ ConX(sizeof(intptr_t)))); - Node* log_addr = __ AddP(no_base, buffer, next_index); - - // Order, see storeCM. - __ store(__ ctrl(), log_addr, card_adr, T_ADDRESS, Compile::AliasIdxRaw, MemNode::unordered); - __ store(__ ctrl(), index_adr, next_index, TypeX_X->basic_type(), Compile::AliasIdxRaw, MemNode::unordered); - - } __ else_(); { - __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), "write_ref_field_post_entry", card_adr, __ thread()); - } __ end_if(); - +Node* G1BarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const { + DecoratorSet decorators = access.decorators(); + bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; + bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; + bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0; + // If we are reading the value of the referent field of a Reference object, we + // need to record the referent in an SATB log buffer using the pre-barrier + // mechanism. Also we need to add a memory barrier to prevent commoning reads + // from this field across safepoints, since GC can change its value. + bool need_read_barrier = ((on_weak || on_phantom) && !no_keepalive); + if (access.is_oop() && need_read_barrier) { + access.set_barrier_data(G1C2BarrierPre); + } + return CardTableBarrierSetC2::load_at_resolved(access, val_type); } -void G1BarrierSetC2::post_barrier(GraphKit* kit, - Node* ctl, - Node* oop_store, - Node* obj, - Node* adr, - uint alias_idx, - Node* val, - BasicType bt, - bool use_precise) const { - // If we are writing a null then we need no post barrier +void G1BarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const { + eliminate_gc_barrier_data(node); +} - if (val != nullptr && val->is_Con() && val->bottom_type() == TypePtr::NULL_PTR) { - // Must be null - const Type* t = val->bottom_type(); - assert(t == Type::TOP || t == TypePtr::NULL_PTR, "must be null"); - // No post barrier if writing null - return; +void G1BarrierSetC2::eliminate_gc_barrier_data(Node* node) const { + if (node->is_LoadStore()) { + LoadStoreNode* loadstore = node->as_LoadStore(); + loadstore->set_barrier_data(0); + } else if (node->is_Mem()) { + MemNode* mem = node->as_Mem(); + mem->set_barrier_data(0); } +} - if (use_ReduceInitialCardMarks() && obj == kit->just_allocated_object(kit->control())) { - // We can skip marks on a freshly-allocated object in Eden. - // Keep this code in sync with CardTableBarrierSet::on_slowpath_allocation_exit. - // That routine informs GC to take appropriate compensating steps, - // upon a slow-path allocation, so as to make this card-mark - // elision safe. +static void refine_barrier_by_new_val_type(const Node* n) { + if (n->Opcode() != Op_StoreP && + n->Opcode() != Op_StoreN) { return; } - - if (use_ReduceInitialCardMarks() - && g1_can_remove_post_barrier(kit, &kit->gvn(), oop_store, adr)) { + MemNode* store = n->as_Mem(); + const Node* newval = n->in(MemNode::ValueIn); + assert(newval != nullptr, ""); + const Type* newval_bottom = newval->bottom_type(); + TypePtr::PTR newval_type = newval_bottom->make_ptr()->ptr(); + uint8_t barrier_data = store->barrier_data(); + if (!newval_bottom->isa_oopptr() && + !newval_bottom->isa_narrowoop() && + newval_type != TypePtr::Null) { + // newval is neither an OOP nor null, so there is no barrier to refine. + assert(barrier_data == 0, "non-OOP stores should have no barrier data"); return; } - - if (!use_precise) { - // All card marks for a (non-array) instance are in one place: - adr = obj; + if (barrier_data == 0) { + // No barrier to refine. + return; } - // (Else it's an array (or unknown), and we want more precise card marks.) - assert(adr != nullptr, ""); - - IdealKit ideal(kit, true); - - Node* tls = __ thread(); // ThreadLocalStorage - - Node* no_base = __ top(); - float likely = PROB_LIKELY_MAG(3); - float unlikely = PROB_UNLIKELY_MAG(3); - Node* young_card = __ ConI((jint)G1CardTable::g1_young_card_val()); - Node* dirty_card = __ ConI((jint)G1CardTable::dirty_card_val()); - Node* zeroX = __ ConX(0); - - const TypeFunc *tf = write_ref_field_post_entry_Type(); - - // Offsets into the thread - const int index_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()); - const int buffer_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()); - - // Pointers into the thread - - Node* buffer_adr = __ AddP(no_base, tls, __ ConX(buffer_offset)); - Node* index_adr = __ AddP(no_base, tls, __ ConX(index_offset)); - - // Now some values - // Use ctrl to avoid hoisting these values past a safepoint, which could - // potentially reset these fields in the JavaThread. - Node* index = __ load(__ ctrl(), index_adr, TypeX_X, TypeX_X->basic_type(), Compile::AliasIdxRaw); - Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw); - - // Convert the store obj pointer to an int prior to doing math on it - // Must use ctrl to prevent "integerized oop" existing across safepoint - Node* cast = __ CastPX(__ ctrl(), adr); - - // Divide pointer by card size - Node* card_offset = __ URShiftX( cast, __ ConI(CardTable::card_shift()) ); - - // Combine card table base and card offset - Node* card_adr = __ AddP(no_base, byte_map_base_node(kit), card_offset ); - - // If we know the value being stored does it cross regions? - - if (val != nullptr) { - // Does the store cause us to cross regions? - - // Should be able to do an unsigned compare of region_size instead of - // and extra shift. Do we have an unsigned compare?? - // Node* region_size = __ ConI(1 << G1HeapRegion::LogOfHRGrainBytes); - Node* xor_res = __ URShiftX ( __ XorX( cast, __ CastPX(__ ctrl(), val)), __ ConI(checked_cast(G1HeapRegion::LogOfHRGrainBytes))); - - // if (xor_res == 0) same region so skip - __ if_then(xor_res, BoolTest::ne, zeroX, likely); { - - // No barrier if we are storing a null. - __ if_then(val, BoolTest::ne, kit->null(), likely); { - - // Ok must mark the card if not already dirty - - // load the original value of the card - Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); - - __ if_then(card_val, BoolTest::ne, young_card, unlikely); { - kit->sync_kit(ideal); - kit->insert_mem_bar(Op_MemBarVolatile, oop_store); - __ sync_kit(kit); - - Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); - __ if_then(card_val_reload, BoolTest::ne, dirty_card); { - g1_mark_card(kit, ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); - } __ end_if(); - } __ end_if(); - } __ end_if(); - } __ end_if(); - } else { - // The Object.clone() intrinsic uses this path if !ReduceInitialCardMarks. - // We don't need a barrier here if the destination is a newly allocated object - // in Eden. Otherwise, GC verification breaks because we assume that cards in Eden - // are set to 'g1_young_gen' (see G1CardTable::verify_g1_young_region()). - assert(!use_ReduceInitialCardMarks(), "can only happen with card marking"); - Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); - __ if_then(card_val, BoolTest::ne, young_card); { - g1_mark_card(kit, ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); - } __ end_if(); + if (newval_type == TypePtr::Null) { + // Simply elide post-barrier if writing null. + barrier_data &= ~G1C2BarrierPost; + barrier_data &= ~G1C2BarrierPostNotNull; + } else if (((barrier_data & G1C2BarrierPost) != 0) && + newval_type == TypePtr::NotNull) { + // If the post-barrier has not been elided yet (e.g. due to newval being + // freshly allocated), mark it as not-null (simplifies barrier tests and + // compressed OOPs logic). + barrier_data |= G1C2BarrierPostNotNull; } - - // Final sync IdealKit and GraphKit. - kit->final_sync(ideal); + store->set_barrier_data(barrier_data); + return; } -// Helper that guards and inserts a pre-barrier. -void G1BarrierSetC2::insert_pre_barrier(GraphKit* kit, Node* base_oop, Node* offset, - Node* pre_val, bool need_mem_bar) const { - // We could be accessing the referent field of a reference object. If so, when G1 - // is enabled, we need to log the value in the referent field in an SATB buffer. - // This routine performs some compile time filters and generates suitable - // runtime filters that guard the pre-barrier code. - // Also add memory barrier for non volatile load from the referent field - // to prevent commoning of loads across safepoint. - - // Some compile time checks. - - // If offset is a constant, is it java_lang_ref_Reference::_reference_offset? - const TypeX* otype = offset->find_intptr_t_type(); - if (otype != nullptr && otype->is_con() && - otype->get_con() != java_lang_ref_Reference::referent_offset()) { - // Constant offset but not the reference_offset so just return - return; - } - - // We only need to generate the runtime guards for instances. - const TypeOopPtr* btype = base_oop->bottom_type()->isa_oopptr(); - if (btype != nullptr) { - if (btype->isa_aryptr()) { - // Array type so nothing to do - return; +// Refine (not really expand) G1 barriers by looking at the new value type +// (whether it is necessarily null or necessarily non-null). +bool G1BarrierSetC2::expand_barriers(Compile* C, PhaseIterGVN& igvn) const { + ResourceMark rm; + VectorSet visited; + Node_List worklist; + worklist.push(C->root()); + while (worklist.size() > 0) { + Node* n = worklist.pop(); + if (visited.test_set(n->_idx)) { + continue; } - - const TypeInstPtr* itype = btype->isa_instptr(); - if (itype != nullptr) { - // Can the klass of base_oop be statically determined to be - // _not_ a sub-class of Reference and _not_ Object? - ciKlass* klass = itype->instance_klass(); - if (klass->is_loaded() && - !klass->is_subtype_of(kit->env()->Reference_klass()) && - !kit->env()->Object_klass()->is_subtype_of(klass)) { - return; + refine_barrier_by_new_val_type(n); + for (uint j = 0; j < n->req(); j++) { + Node* in = n->in(j); + if (in != nullptr) { + worklist.push(in); } } } + return false; +} - // The compile time filters did not reject base_oop/offset so - // we need to generate the following runtime filters - // - // if (offset == java_lang_ref_Reference::_reference_offset) { - // if (instance_of(base, java.lang.ref.Reference)) { - // pre_barrier(_, pre_val, ...); +uint G1BarrierSetC2::estimated_barrier_size(const Node* node) const { + // These Ideal node counts are extracted from the pre-matching Ideal graph + // generated when compiling the following method with early barrier expansion: + // static void write(MyObject obj1, Object o) { + // obj1.o1 = o; // } - // } - - float likely = PROB_LIKELY( 0.999); - float unlikely = PROB_UNLIKELY(0.999); - - IdealKit ideal(kit); - - Node* referent_off = __ ConX(java_lang_ref_Reference::referent_offset()); - - __ if_then(offset, BoolTest::eq, referent_off, unlikely); { - // Update graphKit memory and control from IdealKit. - kit->sync_kit(ideal); - - Node* ref_klass_con = kit->makecon(TypeKlassPtr::make(kit->env()->Reference_klass())); - Node* is_instof = kit->gen_instanceof(base_oop, ref_klass_con); - - // Update IdealKit memory and control from graphKit. - __ sync_kit(kit); - - Node* one = __ ConI(1); - // is_instof == 0 if base_oop == nullptr - __ if_then(is_instof, BoolTest::eq, one, unlikely); { - - // Update graphKit from IdeakKit. - kit->sync_kit(ideal); - - // Use the pre-barrier to record the value in the referent field - pre_barrier(kit, false /* do_load */, - __ ctrl(), - nullptr /* obj */, nullptr /* adr */, max_juint /* alias_idx */, nullptr /* val */, nullptr /* val_type */, - pre_val /* pre_val */, - T_OBJECT); - if (need_mem_bar) { - // Add memory barrier to prevent commoning reads from this field - // across safepoint since GC can change its value. - kit->insert_mem_bar(Op_MemBarCPUOrder); - } - // Update IdealKit from graphKit. - __ sync_kit(kit); - - } __ end_if(); // _ref_type != ref_none - } __ end_if(); // offset == referent_offset + uint8_t barrier_data = MemNode::barrier_data(node); + uint nodes = 0; + if ((barrier_data & G1C2BarrierPre) != 0) { + nodes += 50; + } + if ((barrier_data & G1C2BarrierPost) != 0) { + nodes += 60; + } + return nodes; +} - // Final sync IdealKit and GraphKit. - kit->final_sync(ideal); +bool G1BarrierSetC2::can_initialize_object(const StoreNode* store) const { + assert(store->Opcode() == Op_StoreP || store->Opcode() == Op_StoreN, "OOP store expected"); + // It is OK to move the store across the object initialization boundary only + // if it does not have any barrier, or if it has barriers that can be safely + // elided (because of the compensation steps taken on the allocation slow path + // when ReduceInitialCardMarks is enabled). + return (MemNode::barrier_data(store) == 0) || use_ReduceInitialCardMarks(); } -#undef __ +void G1BarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const { + if (ac->is_clone_inst() && !use_ReduceInitialCardMarks()) { + clone_in_runtime(phase, ac, G1BarrierSetRuntime::clone_addr(), "G1BarrierSetRuntime::clone"); + return; + } + BarrierSetC2::clone_at_expansion(phase, ac); +} -Node* G1BarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const { +Node* G1BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const { DecoratorSet decorators = access.decorators(); - Node* adr = access.addr().node(); - Node* obj = access.base(); - - bool anonymous = (decorators & C2_UNSAFE_ACCESS) != 0; - bool mismatched = (decorators & C2_MISMATCHED) != 0; - bool unknown = (decorators & ON_UNKNOWN_OOP_REF) != 0; + bool anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; bool in_heap = (decorators & IN_HEAP) != 0; - bool in_native = (decorators & IN_NATIVE) != 0; - bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; - bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; - bool is_unordered = (decorators & MO_UNORDERED) != 0; + bool tightly_coupled_alloc = (decorators & C2_TIGHTLY_COUPLED_ALLOC) != 0; + bool need_store_barrier = !(tightly_coupled_alloc && use_ReduceInitialCardMarks()) && (in_heap || anonymous); bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0; - bool is_mixed = !in_heap && !in_native; - bool need_cpu_mem_bar = !is_unordered || mismatched || is_mixed; - - Node* top = Compile::current()->top(); - Node* offset = adr->is_AddP() ? adr->in(AddPNode::Offset) : top; - - // If we are reading the value of the referent field of a Reference - // object (either by using Unsafe directly or through reflection) - // then, if G1 is enabled, we need to record the referent in an - // SATB log buffer using the pre-barrier mechanism. - // Also we need to add memory barrier to prevent commoning reads - // from this field across safepoint since GC can change its value. - bool need_read_barrier = (((on_weak || on_phantom) && !no_keepalive) || - (in_heap && unknown && offset != top && obj != top)); + if (access.is_oop() && need_store_barrier) { + access.set_barrier_data(get_store_barrier(access)); + if (tightly_coupled_alloc) { + assert(!use_ReduceInitialCardMarks(), + "post-barriers are only needed for tightly-coupled initialization stores when ReduceInitialCardMarks is disabled"); + // Pre-barriers are unnecessary for tightly-coupled initialization stores. + access.set_barrier_data(access.barrier_data() & ~G1C2BarrierPre); + } + } + if (no_keepalive) { + // No keep-alive means no need for the pre-barrier. + access.set_barrier_data(access.barrier_data() & ~G1C2BarrierPre); + } + return BarrierSetC2::store_at_resolved(access, val); +} - if (!access.is_oop() || !need_read_barrier) { - return CardTableBarrierSetC2::load_at_resolved(access, val_type); +Node* G1BarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val, + Node* new_val, const Type* value_type) const { + GraphKit* kit = access.kit(); + if (!access.is_oop()) { + return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type); } + access.set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); + return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type); +} - assert(access.is_parse_access(), "entry not supported at optimization time"); +Node* G1BarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val, + Node* new_val, const Type* value_type) const { + GraphKit* kit = access.kit(); + if (!access.is_oop()) { + return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type); + } + access.set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); + return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type); +} - C2ParseAccess& parse_access = static_cast(access); - GraphKit* kit = parse_access.kit(); - Node* load; +Node* G1BarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const { + GraphKit* kit = access.kit(); + if (!access.is_oop()) { + return BarrierSetC2::atomic_xchg_at_resolved(access, new_val, value_type); + } + access.set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); + return BarrierSetC2::atomic_xchg_at_resolved(access, new_val, value_type); +} - Node* control = kit->control(); - const TypePtr* adr_type = access.addr().type(); - MemNode::MemOrd mo = access.mem_node_mo(); - bool requires_atomic_access = (decorators & MO_UNORDERED) == 0; - bool unaligned = (decorators & C2_UNALIGNED) != 0; - bool unsafe = (decorators & C2_UNSAFE_ACCESS) != 0; - // Pinned control dependency is the strictest. So it's ok to substitute it for any other. - load = kit->make_load(control, adr, val_type, access.type(), adr_type, mo, - LoadNode::Pinned, requires_atomic_access, unaligned, mismatched, unsafe, - access.barrier_data()); +class G1BarrierSetC2State : public BarrierSetC2State { +private: + GrowableArray* _stubs; +public: + G1BarrierSetC2State(Arena* arena) + : BarrierSetC2State(arena), + _stubs(new (arena) GrowableArray(arena, 8, 0, nullptr)) {} - if (on_weak || on_phantom) { - // Use the pre-barrier to record the value in the referent field - pre_barrier(kit, false /* do_load */, - kit->control(), - nullptr /* obj */, nullptr /* adr */, max_juint /* alias_idx */, nullptr /* val */, nullptr /* val_type */, - load /* pre_val */, T_OBJECT); - // Add memory barrier to prevent commoning reads from this field - // across safepoint since GC can change its value. - kit->insert_mem_bar(Op_MemBarCPUOrder); - } else if (unknown) { - // We do not require a mem bar inside pre_barrier if need_mem_bar - // is set: the barriers would be emitted by us. - insert_pre_barrier(kit, obj, offset, load, !need_cpu_mem_bar); + GrowableArray* stubs() { + return _stubs; } - return load; -} - -bool G1BarrierSetC2::is_gc_barrier_node(Node* node) const { - if (CardTableBarrierSetC2::is_gc_barrier_node(node)) { - return true; + bool needs_liveness_data(const MachNode* mach) const { + return G1PreBarrierStubC2::needs_barrier(mach) || + G1PostBarrierStubC2::needs_barrier(mach); } - if (node->Opcode() != Op_CallLeaf) { - return false; - } - CallLeafNode *call = node->as_CallLeaf(); - if (call->_name == nullptr) { + + bool needs_livein_data() const { return false; } +}; - return strcmp(call->_name, "write_ref_field_pre_entry") == 0 || strcmp(call->_name, "write_ref_field_post_entry") == 0; +static G1BarrierSetC2State* barrier_set_state() { + return reinterpret_cast(Compile::current()->barrier_set_state()); } -bool G1BarrierSetC2::is_g1_pre_val_load(Node* n) { - if (n->is_Load() && n->as_Load()->has_pinned_control_dependency()) { - // Make sure the only users of it are: CmpP, StoreP, and a call to write_ref_field_pre_entry +G1BarrierStubC2::G1BarrierStubC2(const MachNode* node) : BarrierStubC2(node) {} - // Skip possible decode - if (n->outcnt() == 1 && n->unique_out()->is_DecodeN()) { - n = n->unique_out(); - } +G1PreBarrierStubC2::G1PreBarrierStubC2(const MachNode* node) : G1BarrierStubC2(node) {} - if (n->outcnt() == 3) { - int found = 0; - for (SimpleDUIterator iter(n); iter.has_next(); iter.next()) { - Node* use = iter.get(); - if (use->is_Cmp() || use->is_Store()) { - ++found; - } else if (use->is_CallLeaf()) { - CallLeafNode* call = use->as_CallLeaf(); - if (strcmp(call->_name, "write_ref_field_pre_entry") == 0) { - ++found; - } - } - } - if (found == 3) { - return true; - } - } +bool G1PreBarrierStubC2::needs_barrier(const MachNode* node) { + return (node->barrier_data() & G1C2BarrierPre) != 0; +} + +G1PreBarrierStubC2* G1PreBarrierStubC2::create(const MachNode* node) { + G1PreBarrierStubC2* const stub = new (Compile::current()->comp_arena()) G1PreBarrierStubC2(node); + if (!Compile::current()->output()->in_scratch_emit_size()) { + barrier_set_state()->stubs()->append(stub); } - return false; + return stub; } -bool G1BarrierSetC2::is_gc_pre_barrier_node(Node *node) const { - return is_g1_pre_val_load(node); +void G1PreBarrierStubC2::initialize_registers(Register obj, Register pre_val, Register thread, Register tmp1, Register tmp2) { + _obj = obj; + _pre_val = pre_val; + _thread = thread; + _tmp1 = tmp1; + _tmp2 = tmp2; } -void G1BarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const { - if (is_g1_pre_val_load(node)) { - macro->replace_node(node, macro->zerocon(node->as_Load()->bottom_type()->basic_type())); - } else { - assert(node->Opcode() == Op_CastP2X, "ConvP2XNode required"); - assert(node->outcnt() <= 2, "expects 1 or 2 users: Xor and URShift nodes"); - // It could be only one user, URShift node, in Object.clone() intrinsic - // but the new allocation is passed to arraycopy stub and it could not - // be scalar replaced. So we don't check the case. +Register G1PreBarrierStubC2::obj() const { + return _obj; +} - // An other case of only one user (Xor) is when the value check for null - // in G1 post barrier is folded after CCP so the code which used URShift - // is removed. +Register G1PreBarrierStubC2::pre_val() const { + return _pre_val; +} - // Take Region node before eliminating post barrier since it also - // eliminates CastP2X node when it has only one user. - Node* this_region = node->in(0); - assert(this_region != nullptr, ""); +Register G1PreBarrierStubC2::thread() const { + return _thread; +} - // Remove G1 post barrier. +Register G1PreBarrierStubC2::tmp1() const { + return _tmp1; +} + +Register G1PreBarrierStubC2::tmp2() const { + return _tmp2; +} - // Search for CastP2X->Xor->URShift->Cmp path which - // checks if the store done to a different from the value's region. - // And replace Cmp with #0 (false) to collapse G1 post barrier. - Node* xorx = node->find_out_with(Op_XorX); - if (xorx != nullptr) { - Node* shift = xorx->unique_out(); - Node* cmpx = shift->unique_out(); - assert(cmpx->is_Cmp() && cmpx->unique_out()->is_Bool() && - cmpx->unique_out()->as_Bool()->_test._test == BoolTest::ne, - "missing region check in G1 post barrier"); - macro->replace_node(cmpx, macro->makecon(TypeInt::CC_EQ)); +void G1PreBarrierStubC2::emit_code(MacroAssembler& masm) { + G1BarrierSetAssembler* bs = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + bs->generate_c2_pre_barrier_stub(&masm, this); +} - // Remove G1 pre barrier. +G1PostBarrierStubC2::G1PostBarrierStubC2(const MachNode* node) : G1BarrierStubC2(node) {} - // Search "if (marking != 0)" check and set it to "false". - // There is no G1 pre barrier if previous stored value is null - // (for example, after initialization). - if (this_region->is_Region() && this_region->req() == 3) { - int ind = 1; - if (!this_region->in(ind)->is_IfFalse()) { - ind = 2; - } - if (this_region->in(ind)->is_IfFalse() && - this_region->in(ind)->in(0)->Opcode() == Op_If) { - Node* bol = this_region->in(ind)->in(0)->in(1); - assert(bol->is_Bool(), ""); - cmpx = bol->in(1); - if (bol->as_Bool()->_test._test == BoolTest::ne && - cmpx->is_Cmp() && cmpx->in(2) == macro->intcon(0) && - cmpx->in(1)->is_Load()) { - Node* adr = cmpx->in(1)->as_Load()->in(MemNode::Address); - const int marking_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - if (adr->is_AddP() && adr->in(AddPNode::Base) == macro->top() && - adr->in(AddPNode::Address)->Opcode() == Op_ThreadLocal && - adr->in(AddPNode::Offset) == macro->MakeConX(marking_offset)) { - macro->replace_node(cmpx, macro->makecon(TypeInt::CC_EQ)); - } - } - } - } - } else { - assert(!use_ReduceInitialCardMarks(), "can only happen with card marking"); - // This is a G1 post barrier emitted by the Object.clone() intrinsic. - // Search for the CastP2X->URShiftX->AddP->LoadB->Cmp path which checks if the card - // is marked as young_gen and replace the Cmp with 0 (false) to collapse the barrier. - Node* shift = node->find_out_with(Op_URShiftX); - assert(shift != nullptr, "missing G1 post barrier"); - Node* addp = shift->unique_out(); - Node* load = addp->find_out_with(Op_LoadB); - assert(load != nullptr, "missing G1 post barrier"); - Node* cmpx = load->unique_out(); - assert(cmpx->is_Cmp() && cmpx->unique_out()->is_Bool() && - cmpx->unique_out()->as_Bool()->_test._test == BoolTest::ne, - "missing card value check in G1 post barrier"); - macro->replace_node(cmpx, macro->makecon(TypeInt::CC_EQ)); - // There is no G1 pre barrier in this case - } - // Now CastP2X can be removed since it is used only on dead path - // which currently still alive until igvn optimize it. - assert(node->outcnt() == 0 || node->unique_out()->Opcode() == Op_URShiftX, ""); - macro->replace_node(node, macro->top()); - } +bool G1PostBarrierStubC2::needs_barrier(const MachNode* node) { + return (node->barrier_data() & G1C2BarrierPost) != 0; } -Node* G1BarrierSetC2::step_over_gc_barrier(Node* c) const { - if (!use_ReduceInitialCardMarks() && - c != nullptr && c->is_Region() && c->req() == 3) { - for (uint i = 1; i < c->req(); i++) { - if (c->in(i) != nullptr && c->in(i)->is_Region() && - c->in(i)->req() == 3) { - Node* r = c->in(i); - for (uint j = 1; j < r->req(); j++) { - if (r->in(j) != nullptr && r->in(j)->is_Proj() && - r->in(j)->in(0) != nullptr && - r->in(j)->in(0)->Opcode() == Op_CallLeaf && - r->in(j)->in(0)->as_Call()->entry_point() == CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)) { - Node* call = r->in(j)->in(0); - c = c->in(i == 1 ? 2 : 1); - if (c != nullptr && c->Opcode() != Op_Parm) { - c = c->in(0); - if (c != nullptr) { - c = c->in(0); - assert(call->in(0) == nullptr || - call->in(0)->in(0) == nullptr || - call->in(0)->in(0)->in(0) == nullptr || - call->in(0)->in(0)->in(0)->in(0) == nullptr || - call->in(0)->in(0)->in(0)->in(0)->in(0) == nullptr || - c == call->in(0)->in(0)->in(0)->in(0)->in(0), "bad barrier shape"); - return c; - } - } - } - } - } - } +G1PostBarrierStubC2* G1PostBarrierStubC2::create(const MachNode* node) { + G1PostBarrierStubC2* const stub = new (Compile::current()->comp_arena()) G1PostBarrierStubC2(node); + if (!Compile::current()->output()->in_scratch_emit_size()) { + barrier_set_state()->stubs()->append(stub); } - return c; + return stub; } -#ifdef ASSERT -bool G1BarrierSetC2::has_cas_in_use_chain(Node *n) const { - Unique_Node_List visited; - Node_List worklist; - worklist.push(n); - while (worklist.size() > 0) { - Node* x = worklist.pop(); - if (visited.member(x)) { - continue; - } else { - visited.push(x); - } +void G1PostBarrierStubC2::initialize_registers(Register thread, Register tmp1, Register tmp2, Register tmp3) { + _thread = thread; + _tmp1 = tmp1; + _tmp2 = tmp2; + _tmp3 = tmp3; +} - if (x->is_LoadStore()) { - int op = x->Opcode(); - if (op == Op_CompareAndExchangeP || op == Op_CompareAndExchangeN || - op == Op_CompareAndSwapP || op == Op_CompareAndSwapN || - op == Op_WeakCompareAndSwapP || op == Op_WeakCompareAndSwapN) { - return true; - } - } - if (!x->is_CFG()) { - for (SimpleDUIterator iter(x); iter.has_next(); iter.next()) { - Node* use = iter.get(); - worklist.push(use); - } - } - } - return false; +Register G1PostBarrierStubC2::thread() const { + return _thread; } -void G1BarrierSetC2::verify_pre_load(Node* marking_if, Unique_Node_List& loads /*output*/) const { - assert(loads.size() == 0, "Loads list should be empty"); - Node* pre_val_if = marking_if->find_out_with(Op_IfTrue)->find_out_with(Op_If); - if (pre_val_if != nullptr) { - Unique_Node_List visited; - Node_List worklist; - Node* pre_val = pre_val_if->in(1)->in(1)->in(1); +Register G1PostBarrierStubC2::tmp1() const { + return _tmp1; +} - worklist.push(pre_val); - while (worklist.size() > 0) { - Node* x = worklist.pop(); - if (visited.member(x)) { - continue; - } else { - visited.push(x); - } +Register G1PostBarrierStubC2::tmp2() const { + return _tmp2; +} - if (has_cas_in_use_chain(x)) { - loads.clear(); - return; - } +Register G1PostBarrierStubC2::tmp3() const { + return _tmp3; +} - if (x->is_Con()) { - continue; - } - if (x->is_EncodeP() || x->is_DecodeN()) { - worklist.push(x->in(1)); - continue; - } - if (x->is_Load() || x->is_LoadStore()) { - assert(x->in(0) != nullptr, "Pre-val load has to have a control"); - loads.push(x); - continue; - } - if (x->is_Phi()) { - for (uint i = 1; i < x->req(); i++) { - worklist.push(x->in(i)); - } - continue; - } - assert(false, "Pre-val anomaly"); - } - } +void G1PostBarrierStubC2::emit_code(MacroAssembler& masm) { + G1BarrierSetAssembler* bs = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + bs->generate_c2_post_barrier_stub(&masm, this); } -void G1BarrierSetC2::verify_no_safepoints(Compile* compile, Node* marking_check_if, const Unique_Node_List& loads) const { - if (loads.size() == 0) { - return; - } +void* G1BarrierSetC2::create_barrier_state(Arena* comp_arena) const { + return new (comp_arena) G1BarrierSetC2State(comp_arena); +} - if (loads.size() == 1) { // Handle the typical situation when there a single pre-value load - // that is dominated by the marking_check_if, that's true when the - // barrier itself does the pre-val load. - Node *pre_val = loads.at(0); - if (pre_val->in(0)->in(0) == marking_check_if) { // IfTrue->If - return; - } +int G1BarrierSetC2::get_store_barrier(C2Access& access) const { + if (!access.is_parse_access()) { + // Only support for eliding barriers at parse time for now. + return G1C2BarrierPre | G1C2BarrierPost; } - - // All other cases are when pre-value loads dominate the marking check. - Unique_Node_List controls; - for (uint i = 0; i < loads.size(); i++) { - Node *c = loads.at(i)->in(0); - controls.push(c); + GraphKit* kit = (static_cast(access)).kit(); + Node* ctl = kit->control(); + Node* adr = access.addr().node(); + uint adr_idx = kit->C->get_alias_index(access.addr().type()); + assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory"); + + bool can_remove_pre_barrier = g1_can_remove_pre_barrier(kit, &kit->gvn(), adr, access.type(), adr_idx); + + // We can skip marks on a freshly-allocated object in Eden. Keep this code in + // sync with CardTableBarrierSet::on_slowpath_allocation_exit. That routine + // informs GC to take appropriate compensating steps, upon a slow-path + // allocation, so as to make this card-mark elision safe. + // The post-barrier can also be removed if null is written. This case is + // handled by G1BarrierSetC2::expand_barriers, which runs at the end of C2's + // platform-independent optimizations to exploit stronger type information. + bool can_remove_post_barrier = use_ReduceInitialCardMarks() && + ((access.base() == kit->just_allocated_object(ctl)) || + g1_can_remove_post_barrier(kit, &kit->gvn(), ctl, adr)); + + int barriers = 0; + if (!can_remove_pre_barrier) { + barriers |= G1C2BarrierPre; + } + if (!can_remove_post_barrier) { + barriers |= G1C2BarrierPost; } - Unique_Node_List visited; - Unique_Node_List safepoints; - Node_List worklist; - uint found = 0; + return barriers; +} - worklist.push(marking_check_if); - while (worklist.size() > 0 && found < controls.size()) { - Node* x = worklist.pop(); - if (x == nullptr || x == compile->top()) continue; - if (visited.member(x)) { - continue; - } else { - visited.push(x); - } +void G1BarrierSetC2::late_barrier_analysis() const { + compute_liveness_at_stubs(); +} - if (controls.member(x)) { - found++; - } - if (x->is_Region()) { - for (uint i = 1; i < x->req(); i++) { - worklist.push(x->in(i)); - } - } else { - if (!x->is_SafePoint()) { - worklist.push(x->in(0)); - } else { - safepoints.push(x); - } +void G1BarrierSetC2::emit_stubs(CodeBuffer& cb) const { + MacroAssembler masm(&cb); + GrowableArray* const stubs = barrier_set_state()->stubs(); + for (int i = 0; i < stubs->length(); i++) { + // Make sure there is enough space in the code buffer + if (cb.insts()->maybe_expand_to_ensure_remaining(PhaseOutput::MAX_inst_size) && cb.blob() == nullptr) { + ciEnv::current()->record_failure("CodeCache is full"); + return; } + stubs->at(i)->emit_code(masm); } - assert(found == controls.size(), "Pre-barrier structure anomaly or possible safepoint"); + masm.flush(); } -void G1BarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase phase) const { - if (phase != BarrierSetC2::BeforeCodeGen) { - return; +#ifndef PRODUCT +void G1BarrierSetC2::dump_barrier_data(const MachNode* mach, outputStream* st) const { + if ((mach->barrier_data() & G1C2BarrierPre) != 0) { + st->print("pre "); } - // Verify G1 pre-barriers - const int marking_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - - Unique_Node_List visited; - Node_List worklist; - // We're going to walk control flow backwards starting from the Root - worklist.push(compile->root()); - while (worklist.size() > 0) { - Node* x = worklist.pop(); - if (x == nullptr || x == compile->top()) continue; - if (visited.member(x)) { - continue; - } else { - visited.push(x); - } - - if (x->is_Region()) { - for (uint i = 1; i < x->req(); i++) { - worklist.push(x->in(i)); - } - } else { - worklist.push(x->in(0)); - // We are looking for the pattern: - // /->ThreadLocal - // If->Bool->CmpI->LoadB->AddP->ConL(marking_offset) - // \->ConI(0) - // We want to verify that the If and the LoadB have the same control - // See GraphKit::g1_write_barrier_pre() - if (x->is_If()) { - IfNode *iff = x->as_If(); - if (iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp()) { - CmpNode *cmp = iff->in(1)->in(1)->as_Cmp(); - if (cmp->Opcode() == Op_CmpI && cmp->in(2)->is_Con() && cmp->in(2)->bottom_type()->is_int()->get_con() == 0 - && cmp->in(1)->is_Load()) { - LoadNode* load = cmp->in(1)->as_Load(); - if (load->Opcode() == Op_LoadB && load->in(2)->is_AddP() && load->in(2)->in(2)->Opcode() == Op_ThreadLocal - && load->in(2)->in(3)->is_Con() - && load->in(2)->in(3)->bottom_type()->is_intptr_t()->get_con() == marking_offset) { - - Node* if_ctrl = iff->in(0); - Node* load_ctrl = load->in(0); - - if (if_ctrl != load_ctrl) { - // Skip possible CProj->NeverBranch in infinite loops - if ((if_ctrl->is_Proj() && if_ctrl->Opcode() == Op_CProj) - && if_ctrl->in(0)->is_NeverBranch()) { - if_ctrl = if_ctrl->in(0)->in(0); - } - } - assert(load_ctrl != nullptr && if_ctrl == load_ctrl, "controls must match"); - - Unique_Node_List loads; - verify_pre_load(iff, loads); - verify_no_safepoints(compile, iff, loads); - } - } - } - } - } + if ((mach->barrier_data() & G1C2BarrierPost) != 0) { + st->print("post "); } -} -#endif - -bool G1BarrierSetC2::escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const { - if (opcode == Op_StoreP) { - Node* adr = n->in(MemNode::Address); - const Type* adr_type = gvn->type(adr); - // Pointer stores in G1 barriers looks like unsafe access. - // Ignore such stores to be able scalar replace non-escaping - // allocations. - if (adr_type->isa_rawptr() && adr->is_AddP()) { - Node* base = conn_graph->get_addp_base(adr); - if (base->Opcode() == Op_LoadP && - base->in(MemNode::Address)->is_AddP()) { - adr = base->in(MemNode::Address); - Node* tls = conn_graph->get_addp_base(adr); - if (tls->Opcode() == Op_ThreadLocal) { - int offs = (int) gvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot); - const int buf_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - if (offs == buf_offset) { - return true; // G1 pre barrier previous oop value store. - } - if (offs == in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())) { - return true; // G1 post barrier card address store. - } - } - } - } + if ((mach->barrier_data() & G1C2BarrierPostNotNull) != 0) { + st->print("notnull "); } - return false; } +#endif // !PRODUCT diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp index c445a87d2e46d..dc333d8c33174 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp @@ -31,29 +31,62 @@ class PhaseTransform; class Type; class TypeFunc; -class G1BarrierSetC2: public CardTableBarrierSetC2 { +const int G1C2BarrierPre = 1; +const int G1C2BarrierPost = 2; +const int G1C2BarrierPostNotNull = 4; + +class G1BarrierStubC2 : public BarrierStubC2 { +public: + G1BarrierStubC2(const MachNode* node); + virtual void emit_code(MacroAssembler& masm) = 0; +}; + +class G1PreBarrierStubC2 : public G1BarrierStubC2 { +private: + Register _obj; + Register _pre_val; + Register _thread; + Register _tmp1; + Register _tmp2; + +protected: + G1PreBarrierStubC2(const MachNode* node); + +public: + static bool needs_barrier(const MachNode* node); + static G1PreBarrierStubC2* create(const MachNode* node); + void initialize_registers(Register obj, Register pre_val, Register thread, Register tmp1 = noreg, Register tmp2 = noreg); + Register obj() const; + Register pre_val() const; + Register thread() const; + Register tmp1() const; + Register tmp2() const; + virtual void emit_code(MacroAssembler& masm); +}; + +class G1PostBarrierStubC2 : public G1BarrierStubC2 { +private: + Register _thread; + Register _tmp1; + Register _tmp2; + Register _tmp3; + protected: - virtual void pre_barrier(GraphKit* kit, - bool do_load, - Node* ctl, - Node* obj, - Node* adr, - uint adr_idx, - Node* val, - const TypeOopPtr* val_type, - Node* pre_val, - BasicType bt) const; - - virtual void post_barrier(GraphKit* kit, - Node* ctl, - Node* store, - Node* obj, - Node* adr, - uint adr_idx, - Node* val, - BasicType bt, - bool use_precise) const; + G1PostBarrierStubC2(const MachNode* node); +public: + static bool needs_barrier(const MachNode* node); + static G1PostBarrierStubC2* create(const MachNode* node); + void initialize_registers(Register thread, Register tmp1 = noreg, Register tmp2 = noreg, Register tmp3 = noreg); + Register thread() const; + Register tmp1() const; + Register tmp2() const; + Register tmp3() const; + virtual void emit_code(MacroAssembler& masm); +}; + +class G1BarrierSetC2: public CardTableBarrierSetC2 { +protected: bool g1_can_remove_pre_barrier(GraphKit* kit, PhaseValues* phase, Node* adr, @@ -64,44 +97,31 @@ class G1BarrierSetC2: public CardTableBarrierSetC2 { PhaseValues* phase, Node* store, Node* adr) const; - void g1_mark_card(GraphKit* kit, - IdealKit& ideal, - Node* card_adr, - Node* oop_store, - uint oop_alias_idx, - Node* index, - Node* index_adr, - Node* buffer, - const TypeFunc* tf) const; - - // Helper for unsafe accesses, that may or may not be on the referent field. - // Generates the guards that check whether the result of - // Unsafe.getReference should be recorded in an SATB log buffer. - void insert_pre_barrier(GraphKit* kit, Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar) const; - - static const TypeFunc* write_ref_field_pre_entry_Type(); - static const TypeFunc* write_ref_field_post_entry_Type(); + int get_store_barrier(C2Access& access) const; virtual Node* load_at_resolved(C2Access& access, const Type* val_type) const; + virtual Node* store_at_resolved(C2Access& access, C2AccessValue& val) const; + virtual Node* atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val, + Node* new_val, const Type* value_type) const; + virtual Node* atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val, + Node* new_val, const Type* value_type) const; + virtual Node* atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const; -#ifdef ASSERT - bool has_cas_in_use_chain(Node* x) const; - void verify_pre_load(Node* marking_check_if, Unique_Node_List& loads /*output*/) const; - void verify_no_safepoints(Compile* compile, Node* marking_load, const Unique_Node_List& loads) const; -#endif - - static bool is_g1_pre_val_load(Node* n); public: - virtual bool is_gc_pre_barrier_node(Node* node) const; - virtual bool is_gc_barrier_node(Node* node) const; virtual void eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const; - virtual Node* step_over_gc_barrier(Node* c) const; - -#ifdef ASSERT - virtual void verify_gc_barriers(Compile* compile, CompilePhase phase) const; + virtual void eliminate_gc_barrier_data(Node* node) const; + virtual bool expand_barriers(Compile* C, PhaseIterGVN& igvn) const; + virtual uint estimated_barrier_size(const Node* node) const; + virtual bool can_initialize_object(const StoreNode* store) const; + virtual void clone_at_expansion(PhaseMacroExpand* phase, + ArrayCopyNode* ac) const; + virtual void* create_barrier_state(Arena* comp_arena) const; + virtual void emit_stubs(CodeBuffer& cb) const; + virtual void late_barrier_analysis() const; + +#ifndef PRODUCT + virtual void dump_barrier_data(const MachNode* mach, outputStream* st) const; #endif - - virtual bool escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const; }; #endif // SHARE_GC_G1_C2_G1BARRIERSETC2_HPP diff --git a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp index a0fce437807f4..2e247f46c93d8 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp +++ b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp @@ -61,3 +61,11 @@ JRT_LEAF(void, G1BarrierSetRuntime::write_ref_field_post_entry(volatile G1CardTa G1DirtyCardQueue& queue = G1ThreadLocalData::dirty_card_queue(thread); G1BarrierSet::dirty_card_queue_set().enqueue(queue, card_addr); JRT_END + +JRT_LEAF(void, G1BarrierSetRuntime::clone(oopDesc* src, oopDesc* dst, size_t size)) + HeapAccess<>::clone(src, dst, size); +JRT_END + +address G1BarrierSetRuntime::clone_addr() { + return reinterpret_cast

    (clone); +} diff --git a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.hpp b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.hpp index 366679f032ba9..f98e94096e72d 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.hpp +++ b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.hpp @@ -35,6 +35,8 @@ class oopDesc; class JavaThread; class G1BarrierSetRuntime: public AllStatic { +private: + static void clone(oopDesc* src, oopDesc* dst, size_t size); public: using CardValue = G1CardTable::CardValue; @@ -46,6 +48,8 @@ class G1BarrierSetRuntime: public AllStatic { // C2 slow-path runtime calls. static void write_ref_field_pre_entry(oopDesc* orig, JavaThread *thread); static void write_ref_field_post_entry(volatile CardValue* card_addr, JavaThread* thread); + + static address clone_addr(); }; #endif // SHARE_GC_G1_G1BARRIERSETRUNTIME_HPP diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index fd73b725a1289..57236d6f6db93 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2595,8 +2595,9 @@ void G1CollectedHeap::set_young_gen_card_set_stats(const G1MonotonicArenaMemoryS } void G1CollectedHeap::record_obj_copy_mem_stats() { + size_t total_old_allocated = _old_evac_stats.allocated() + _old_evac_stats.direct_allocated(); policy()->old_gen_alloc_tracker()-> - add_allocated_bytes_since_last_gc(_old_evac_stats.allocated() * HeapWordSize); + add_allocated_bytes_since_last_gc(total_old_allocated * HeapWordSize); _gc_tracer_stw->report_evacuation_statistics(create_g1_evac_summary(&_survivor_evac_stats), create_g1_evac_summary(&_old_evac_stats)); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index d315497268f99..ec90fd377503d 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -26,7 +26,7 @@ #include "gc/g1/g1Analytics.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" -#include "gc/g1/g1CollectionSetCandidates.hpp" +#include "gc/g1/g1CollectionSetCandidates.inline.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionRemSet.inline.hpp" @@ -346,20 +346,16 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { G1CollectionCandidateRegionList pinned_retained_regions; if (collector_state()->in_mixed_phase()) { - time_remaining_ms = _policy->select_candidates_from_marking(&candidates()->marking_regions(), - time_remaining_ms, - &initial_old_regions, - &_optional_old_regions, - &pinned_marking_regions); + time_remaining_ms = select_candidates_from_marking(time_remaining_ms, + &initial_old_regions, + &pinned_marking_regions); } else { log_debug(gc, ergo, cset)("Do not add marking candidates to collection set due to pause type."); } - _policy->select_candidates_from_retained(&candidates()->retained_regions(), - time_remaining_ms, - &initial_old_regions, - &_optional_old_regions, - &pinned_retained_regions); + select_candidates_from_retained(time_remaining_ms, + &initial_old_regions, + &pinned_retained_regions); // Move initially selected old regions to collection set directly. move_candidates_to_collection_set(&initial_old_regions); @@ -394,6 +390,215 @@ void G1CollectionSet::move_candidates_to_collection_set(G1CollectionCandidateReg candidates()->remove(regions); } +static void print_finish_message(const char* reason, bool from_marking) { + log_debug(gc, ergo, cset)("Finish adding %s candidates to collection set (%s).", + from_marking ? "marking" : "retained", reason); +} + +double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions) { + uint num_expensive_regions = 0; + + uint num_initial_regions_selected = 0; + uint num_optional_regions_selected = 0; + uint num_pinned_regions = 0; + + double predicted_initial_time_ms = 0.0; + double predicted_optional_time_ms = 0.0; + + double optional_threshold_ms = time_remaining_ms * _policy->optional_prediction_fraction(); + + const uint min_old_cset_length = _policy->calc_min_old_cset_length(candidates()->last_marking_candidates_length()); + const uint max_old_cset_length = MAX2(min_old_cset_length, _policy->calc_max_old_cset_length()); + const uint max_optional_regions = max_old_cset_length - min_old_cset_length; + bool check_time_remaining = _policy->use_adaptive_young_list_length(); + + G1CollectionCandidateList* marking_list = &candidates()->marking_regions(); + assert(marking_list != nullptr, "must be"); + + log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. " + "Min %u regions, max %u regions, available %u regions" + "time remaining %1.2fms, optional threshold %1.2fms", + min_old_cset_length, max_old_cset_length, marking_list->length(), time_remaining_ms, optional_threshold_ms); + + G1CollectionCandidateListIterator iter = marking_list->begin(); + for (; iter != marking_list->end(); ++iter) { + if (num_initial_regions_selected + num_optional_regions_selected >= max_old_cset_length) { + // Added maximum number of old regions to the CSet. + print_finish_message("Maximum number of regions reached", true); + break; + } + G1HeapRegion* hr = (*iter)->_r; + // Skip evacuating pinned marking regions because we are not getting any free + // space from them (and we expect to get free space from marking candidates). + // Also prepare to move them to retained regions to be evacuated optionally later + // to not impact the mixed phase too much. + if (hr->has_pinned_objects()) { + num_pinned_regions++; + (*iter)->update_num_unreclaimed(); + log_trace(gc, ergo, cset)("Marking candidate %u can not be reclaimed currently. Skipping.", hr->hrm_index()); + pinned_old_regions->append(hr); + continue; + } + double predicted_time_ms = _policy->predict_region_total_time_ms(hr, false); + time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); + // Add regions to old set until we reach the minimum amount + if (initial_old_regions->length() < min_old_cset_length) { + initial_old_regions->append(hr); + num_initial_regions_selected++; + predicted_initial_time_ms += predicted_time_ms; + // Record the number of regions added with no time remaining + if (time_remaining_ms == 0.0) { + num_expensive_regions++; + } + } else if (!check_time_remaining) { + // In the non-auto-tuning case, we'll finish adding regions + // to the CSet if we reach the minimum. + print_finish_message("Region amount reached min", true); + break; + } else { + // Keep adding regions to old set until we reach the optional threshold + if (time_remaining_ms > optional_threshold_ms) { + predicted_initial_time_ms += predicted_time_ms; + initial_old_regions->append(hr); + num_initial_regions_selected++; + } else if (time_remaining_ms > 0) { + // Keep adding optional regions until time is up. + assert(_optional_old_regions.length() < max_optional_regions, "Should not be possible."); + predicted_optional_time_ms += predicted_time_ms; + _optional_old_regions.append(hr); + num_optional_regions_selected++; + } else { + print_finish_message("Predicted time too high", true); + break; + } + } + } + if (iter == marking_list->end()) { + log_debug(gc, ergo, cset)("Marking candidates exhausted."); + } + + if (num_expensive_regions > 0) { + log_debug(gc, ergo, cset)("Added %u marking candidates to collection set although the predicted time was too high.", + num_expensive_regions); + } + + log_debug(gc, ergo, cset)("Finish adding marking candidates to collection set. Initial: %u, optional: %u, pinned: %u, " + "predicted initial time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2fms", + num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, + predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms); + + assert(initial_old_regions->length() == num_initial_regions_selected, "must be"); + assert(_optional_old_regions.length() == num_optional_regions_selected, "must be"); + return time_remaining_ms; +} + +void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions) { + uint num_initial_regions_selected = 0; + uint num_optional_regions_selected = 0; + uint num_expensive_regions_selected = 0; + uint num_pinned_regions = 0; + + double predicted_initial_time_ms = 0.0; + double predicted_optional_time_ms = 0.0; + + uint const min_regions = _policy->min_retained_old_cset_length(); + // We want to make sure that on the one hand we process the retained regions asap, + // but on the other hand do not take too many of them as optional regions. + // So we split the time budget into budget we will unconditionally take into the + // initial old regions, and budget for taking optional regions from the retained + // list. + double optional_time_remaining_ms = _policy->max_time_for_retaining(); + time_remaining_ms = MIN2(time_remaining_ms, optional_time_remaining_ms); + + G1CollectionCandidateList* retained_list = &candidates()->retained_regions(); + + log_debug(gc, ergo, cset)("Start adding retained candidates to collection set. " + "Min %u regions, available %u, " + "time remaining %1.2fms, optional remaining %1.2fms", + min_regions, retained_list->length(), time_remaining_ms, optional_time_remaining_ms); + + for (G1CollectionSetCandidateInfo* ci : *retained_list) { + G1HeapRegion* r = ci->_r; + double predicted_time_ms = _policy->predict_region_total_time_ms(r, collector_state()->in_young_only_phase()); + bool fits_in_remaining_time = predicted_time_ms <= time_remaining_ms; + // If we can't reclaim that region ignore it for now. + if (r->has_pinned_objects()) { + num_pinned_regions++; + if (ci->update_num_unreclaimed()) { + log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Skipping.", r->hrm_index()); + } else { + log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Dropping.", r->hrm_index()); + pinned_old_regions->append(r); + } + continue; + } + + if (fits_in_remaining_time || (num_expensive_regions_selected < min_regions)) { + predicted_initial_time_ms += predicted_time_ms; + if (!fits_in_remaining_time) { + num_expensive_regions_selected++; + } + initial_old_regions->append(r); + num_initial_regions_selected++; + } else if (predicted_time_ms <= optional_time_remaining_ms) { + predicted_optional_time_ms += predicted_time_ms; + _optional_old_regions.append(r); + num_optional_regions_selected++; + } else { + // Fits neither initial nor optional time limit. Exit. + break; + } + time_remaining_ms = MAX2(0.0, time_remaining_ms - predicted_time_ms); + optional_time_remaining_ms = MAX2(0.0, optional_time_remaining_ms - predicted_time_ms); + } + + uint num_regions_selected = num_initial_regions_selected + num_optional_regions_selected; + if (num_regions_selected == retained_list->length()) { + log_debug(gc, ergo, cset)("Retained candidates exhausted."); + } + if (num_expensive_regions_selected > 0) { + log_debug(gc, ergo, cset)("Added %u retained candidates to collection set although the predicted time was too high.", + num_expensive_regions_selected); + } + + log_debug(gc, ergo, cset)("Finish adding retained candidates to collection set. Initial: %u, optional: %u, pinned: %u, " + "predicted initial time: %1.2fms, predicted optional time: %1.2fms, " + "time remaining: %1.2fms optional time remaining %1.2fms", + num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, + predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms, optional_time_remaining_ms); +} + +void G1CollectionSet::select_candidates_from_optional_regions(double time_remaining_ms, + G1CollectionCandidateRegionList* selected_regions) { + assert(optional_region_length() > 0, + "Should only be called when there are optional regions"); + + double total_prediction_ms = 0.0; + + for (G1HeapRegion* r : _optional_old_regions) { + double prediction_ms = _policy->predict_region_total_time_ms(r, false); + + if (prediction_ms > time_remaining_ms) { + log_debug(gc, ergo, cset)("Prediction %.3fms for region %u does not fit remaining time: %.3fms.", + prediction_ms, r->hrm_index(), time_remaining_ms); + break; + } + // This region will be included in the next optional evacuation. + + total_prediction_ms += prediction_ms; + time_remaining_ms -= prediction_ms; + + selected_regions->append(r); + } + + log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Total predicted time: %.3fms", + selected_regions->length(), _optional_old_regions.length(), total_prediction_ms); +} + void G1CollectionSet::prepare_optional_regions(G1CollectionCandidateRegionList* regions){ uint cur_index = 0; for (G1HeapRegion* r : *regions) { @@ -441,9 +646,8 @@ bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_ti update_incremental_marker(); G1CollectionCandidateRegionList selected_regions; - _policy->calculate_optional_collection_set_regions(&_optional_old_regions, - remaining_pause_time, - &selected_regions); + select_candidates_from_optional_regions(remaining_pause_time, + &selected_regions); move_candidates_to_collection_set(&selected_regions); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index e569d3ee966c3..5280ba7d0fd6c 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -196,6 +196,22 @@ class G1CollectionSet { // and retained collection set candidates. void finalize_old_part(double time_remaining_ms); + // Calculate and fill in the initial, optional and pinned old gen candidate regions from + // the given candidate list and the remaining time. + // Returns the remaining time. + double select_candidates_from_marking(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions); + + void select_candidates_from_retained(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions); + + // Calculate the number of optional regions from the given collection set candidates, + // the remaining time and the maximum number of these regions. + void select_candidates_from_optional_regions(double time_remaining_ms, + G1CollectionCandidateRegionList* selected); + // Iterate the part of the collection set given by the offset and length applying the given // G1HeapRegionClosure. The worker_id will determine where in the part to start the iteration // to allow for more efficient parallel iteration. diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp index 2369a0f7812ea..9fb56f7c58fb2 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp @@ -66,7 +66,7 @@ G1HeapRegionManager::G1HeapRegionManager() : _bot_mapper(nullptr), _cardtable_mapper(nullptr), _committed_map(), - _allocated_heapregions_length(0), + _next_highest_used_hrm_index(0), _regions(), _heap_mapper(nullptr), _bitmap_mapper(nullptr), _free_list("Free list", new G1MasterFreeRegionListChecker()) @@ -76,7 +76,7 @@ void G1HeapRegionManager::initialize(G1RegionToSpaceMapper* heap_storage, G1RegionToSpaceMapper* bitmap, G1RegionToSpaceMapper* bot, G1RegionToSpaceMapper* cardtable) { - _allocated_heapregions_length = 0; + _next_highest_used_hrm_index = 0; _heap_mapper = heap_storage; @@ -169,7 +169,7 @@ void G1HeapRegionManager::expand(uint start, uint num_regions, WorkerThreads* pr hr = new_heap_region(i); OrderAccess::storestore(); _regions.set_by_index(i, hr); - _allocated_heapregions_length = MAX2(_allocated_heapregions_length, i + 1); + _next_highest_used_hrm_index = MAX2(_next_highest_used_hrm_index, i + 1); } G1HeapRegionPrinter::commit(hr); } @@ -489,7 +489,7 @@ uint G1HeapRegionManager::find_contiguous_allow_expand(uint num_regions) { G1HeapRegion* G1HeapRegionManager::next_region_in_heap(const G1HeapRegion* r) const { guarantee(r != nullptr, "Start region must be a valid region"); guarantee(is_available(r->hrm_index()), "Trying to iterate starting from region %u which is not in the heap", r->hrm_index()); - for (uint i = r->hrm_index() + 1; i < _allocated_heapregions_length; i++) { + for (uint i = r->hrm_index() + 1; i < _next_highest_used_hrm_index; i++) { G1HeapRegion* hr = _regions.get_by_index(i); if (is_available(i)) { return hr; @@ -583,8 +583,8 @@ void G1HeapRegionManager::par_iterate(G1HeapRegionClosure* blk, G1HeapRegionClai uint G1HeapRegionManager::shrink_by(uint num_regions_to_remove) { assert(length() > 0, "the region sequence should not be empty"); - assert(length() <= _allocated_heapregions_length, "invariant"); - assert(_allocated_heapregions_length > 0, "we should have at least one region committed"); + assert(length() <= _next_highest_used_hrm_index, "invariant"); + assert(_next_highest_used_hrm_index > 0, "we should have at least one region committed"); assert(num_regions_to_remove < length(), "We should never remove all regions"); if (num_regions_to_remove == 0) { @@ -592,7 +592,7 @@ uint G1HeapRegionManager::shrink_by(uint num_regions_to_remove) { } uint removed = 0; - uint cur = _allocated_heapregions_length; + uint cur = _next_highest_used_hrm_index; uint idx_last_found = 0; uint num_last_found = 0; @@ -624,7 +624,7 @@ void G1HeapRegionManager::shrink_at(uint index, size_t num_regions) { } uint G1HeapRegionManager::find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const { - guarantee(start_idx <= _allocated_heapregions_length, "checking"); + guarantee(start_idx <= _next_highest_used_hrm_index, "checking"); guarantee(res_idx != nullptr, "checking"); auto is_available_and_empty = [&] (uint index) { @@ -658,12 +658,12 @@ uint G1HeapRegionManager::find_empty_from_idx_reverse(uint start_idx, uint* res_ } void G1HeapRegionManager::verify() { - guarantee(length() <= _allocated_heapregions_length, - "invariant: _length: %u _allocated_length: %u", - length(), _allocated_heapregions_length); - guarantee(_allocated_heapregions_length <= reserved_length(), - "invariant: _allocated_length: %u _max_length: %u", - _allocated_heapregions_length, reserved_length()); + guarantee(length() <= _next_highest_used_hrm_index, + "invariant: _length: %u _next_highest_used_hrm_index: %u", + length(), _next_highest_used_hrm_index); + guarantee(_next_highest_used_hrm_index <= reserved_length(), + "invariant: _next_highest_used_hrm_index: %u _max_length: %u", + _next_highest_used_hrm_index, reserved_length()); guarantee(length() <= max_length(), "invariant: committed regions: %u max_regions: %u", length(), max_length()); @@ -671,7 +671,7 @@ void G1HeapRegionManager::verify() { bool prev_committed = true; uint num_committed = 0; HeapWord* prev_end = heap_bottom(); - for (uint i = 0; i < _allocated_heapregions_length; i++) { + for (uint i = 0; i < _next_highest_used_hrm_index; i++) { if (!is_available(i)) { prev_committed = false; continue; @@ -693,7 +693,7 @@ void G1HeapRegionManager::verify() { prev_committed = true; prev_end = hr->end(); } - for (uint i = _allocated_heapregions_length; i < reserved_length(); i++) { + for (uint i = _next_highest_used_hrm_index; i < reserved_length(); i++) { guarantee(_regions.get_by_index(i) == nullptr, "invariant i: %u", i); } @@ -708,7 +708,7 @@ void G1HeapRegionManager::verify_optional() { #endif // PRODUCT G1HeapRegionClaimer::G1HeapRegionClaimer(uint n_workers) : - _n_workers(n_workers), _n_regions(G1CollectedHeap::heap()->_hrm._allocated_heapregions_length), _claims(nullptr) { + _n_workers(n_workers), _n_regions(G1CollectedHeap::heap()->_hrm._next_highest_used_hrm_index), _claims(nullptr) { uint* new_claims = NEW_C_HEAP_ARRAY(uint, _n_regions, mtGC); memset(new_claims, Unclaimed, sizeof(*_claims) * _n_regions); _claims = new_claims; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp index 81bca4ce6381c..563140acf5b8f 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp @@ -64,8 +64,8 @@ class G1HeapRegionTable : public G1BiasedMappedArray { // // * _num_committed (returned by length()) is the number of currently // committed regions. These may not be contiguous. -// * _allocated_heapregions_length (not exposed outside this class) is the -// number of regions+1 for which we have G1HeapRegions. +// * _next_highest_used_hrm_index (not exposed outside this class) is the +// highest heap region index +1 for which we have G1HeapRegions. // * max_length() returns the maximum number of regions the heap may commit. // * reserved_length() returns the maximum number of regions the heap has reserved. // @@ -81,8 +81,8 @@ class G1HeapRegionManager: public CHeapObj { // can either be active (ready for use) or inactive (ready for uncommit). G1CommittedRegionMap _committed_map; - // Internal only. The highest heap region +1 we allocated a G1HeapRegion instance for. - uint _allocated_heapregions_length; + // Internal only. The highest heap region index +1 we allocated a G1HeapRegion instance for. + uint _next_highest_used_hrm_index; HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); } HeapWord* heap_end() const {return _regions.end_address_mapped(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp index d7b1a6da92c17..577a8552091f6 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp @@ -35,8 +35,8 @@ class G1HeapRegionPrinter : public AllStatic { // Print an action event. static void print(const char* action, G1HeapRegion* hr) { - log_trace(gc, region)("G1HR %s(%s) [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]", - action, hr->get_type_str(), p2i(hr->bottom()), p2i(hr->top()), p2i(hr->end())); + log_trace(gc, region)("G1HR %4u %s(%s) [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]", + hr->hrm_index(), action, hr->get_type_str(), p2i(hr->bottom()), p2i(hr->top()), p2i(hr->end())); } public: diff --git a/src/hotspot/share/gc/g1/g1IHOPControl.cpp b/src/hotspot/share/gc/g1/g1IHOPControl.cpp index 25915cdd3566c..d1bfcf0d095f9 100644 --- a/src/hotspot/share/gc/g1/g1IHOPControl.cpp +++ b/src/hotspot/share/gc/g1/g1IHOPControl.cpp @@ -151,7 +151,7 @@ double G1AdaptiveIHOPControl::last_mutator_period_old_allocation_rate() const { assert(_last_allocation_time_s > 0, "This should not be called when the last GC is full"); return _old_gen_alloc_tracker->last_period_old_gen_growth() / _last_allocation_time_s; - } +} void G1AdaptiveIHOPControl::update_allocation_info(double allocation_time_s, size_t additional_buffer_size) { diff --git a/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp b/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp index eb86b81d2abbd..265c7029e14da 100644 --- a/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp +++ b/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp @@ -32,17 +32,17 @@ class G1AdaptiveIHOPControl; // Track allocation details in the old generation. class G1OldGenAllocationTracker : public CHeapObj { - // Total number of bytes allocated in the old generation during - // last mutator period. + // Total number of bytes allocated in the old generation at the end + // of the last gc. size_t _last_period_old_gen_bytes; - // Total growth of the old geneneration for last mutator period, - // taking eager reclaim into consideration. + // Total growth of the old geneneration since the last gc, + // taking eager-reclaim into consideration. size_t _last_period_old_gen_growth; // Total size of humongous objects for last gc. size_t _humongous_bytes_after_last_gc; - // Non-humongous old generation allocations during last mutator period. + // Non-humongous old generation allocations since the last gc. size_t _allocated_bytes_since_last_gc; // Humongous allocations during last mutator period. size_t _allocated_humongous_bytes_since_last_gc; diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index e7e57c962c734..1b71901f0fe05 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -53,7 +53,7 @@ #include "gc/shared/gcTraceTime.inline.hpp" G1Policy::G1Policy(STWGCTimer* gc_timer) : - _predictor(G1ConfidencePercent / 100.0), + _predictor((100 - G1ConfidencePercent) / 100.0), _analytics(new G1Analytics(&_predictor)), _remset_tracker(), _mmu_tracker(new G1MMUTracker(GCPauseIntervalMillis / 1000.0, MaxGCPauseMillis / 1000.0)), @@ -1467,219 +1467,6 @@ uint G1Policy::calc_max_old_cset_length() const { return (uint)ceil(result); } -static void print_finish_message(const char* reason, bool from_marking) { - log_debug(gc, ergo, cset)("Finish adding %s candidates to collection set (%s).", - from_marking ? "marking" : "retained", reason); -} - -double G1Policy::select_candidates_from_marking(G1CollectionCandidateList* marking_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions) { - assert(marking_list != nullptr, "must be"); - - uint num_expensive_regions = 0; - - uint num_initial_regions_selected = 0; - uint num_optional_regions_selected = 0; - uint num_pinned_regions = 0; - - double predicted_initial_time_ms = 0.0; - double predicted_optional_time_ms = 0.0; - - double optional_threshold_ms = time_remaining_ms * optional_prediction_fraction(); - - const uint min_old_cset_length = calc_min_old_cset_length(candidates()->last_marking_candidates_length()); - const uint max_old_cset_length = MAX2(min_old_cset_length, calc_max_old_cset_length()); - const uint max_optional_regions = max_old_cset_length - min_old_cset_length; - bool check_time_remaining = use_adaptive_young_list_length(); - - log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. " - "Min %u regions, max %u regions, available %u regions" - "time remaining %1.2fms, optional threshold %1.2fms", - min_old_cset_length, max_old_cset_length, marking_list->length(), time_remaining_ms, optional_threshold_ms); - - G1CollectionCandidateListIterator iter = marking_list->begin(); - for (; iter != marking_list->end(); ++iter) { - if (num_initial_regions_selected + num_optional_regions_selected >= max_old_cset_length) { - // Added maximum number of old regions to the CSet. - print_finish_message("Maximum number of regions reached", true); - break; - } - G1HeapRegion* hr = (*iter)->_r; - // Skip evacuating pinned marking regions because we are not getting any free - // space from them (and we expect to get free space from marking candidates). - // Also prepare to move them to retained regions to be evacuated optionally later - // to not impact the mixed phase too much. - if (hr->has_pinned_objects()) { - num_pinned_regions++; - (*iter)->update_num_unreclaimed(); - log_trace(gc, ergo, cset)("Marking candidate %u can not be reclaimed currently. Skipping.", hr->hrm_index()); - pinned_old_regions->append(hr); - continue; - } - double predicted_time_ms = predict_region_total_time_ms(hr, false); - time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); - // Add regions to old set until we reach the minimum amount - if (initial_old_regions->length() < min_old_cset_length) { - initial_old_regions->append(hr); - num_initial_regions_selected++; - predicted_initial_time_ms += predicted_time_ms; - // Record the number of regions added with no time remaining - if (time_remaining_ms == 0.0) { - num_expensive_regions++; - } - } else if (!check_time_remaining) { - // In the non-auto-tuning case, we'll finish adding regions - // to the CSet if we reach the minimum. - print_finish_message("Region amount reached min", true); - break; - } else { - // Keep adding regions to old set until we reach the optional threshold - if (time_remaining_ms > optional_threshold_ms) { - predicted_initial_time_ms += predicted_time_ms; - initial_old_regions->append(hr); - num_initial_regions_selected++; - } else if (time_remaining_ms > 0) { - // Keep adding optional regions until time is up. - assert(optional_old_regions->length() < max_optional_regions, "Should not be possible."); - predicted_optional_time_ms += predicted_time_ms; - optional_old_regions->append(hr); - num_optional_regions_selected++; - } else { - print_finish_message("Predicted time too high", true); - break; - } - } - } - if (iter == marking_list->end()) { - log_debug(gc, ergo, cset)("Marking candidates exhausted."); - } - - if (num_expensive_regions > 0) { - log_debug(gc, ergo, cset)("Added %u marking candidates to collection set although the predicted time was too high.", - num_expensive_regions); - } - - log_debug(gc, ergo, cset)("Finish adding marking candidates to collection set. Initial: %u, optional: %u, pinned: %u, " - "predicted initial time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2fms", - num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, - predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms); - - assert(initial_old_regions->length() == num_initial_regions_selected, "must be"); - assert(optional_old_regions->length() == num_optional_regions_selected, "must be"); - return time_remaining_ms; -} - -void G1Policy::select_candidates_from_retained(G1CollectionCandidateList* retained_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions) { - - uint const min_regions = min_retained_old_cset_length(); - - uint num_initial_regions_selected = 0; - uint num_optional_regions_selected = 0; - uint num_expensive_regions_selected = 0; - uint num_pinned_regions = 0; - - double predicted_initial_time_ms = 0.0; - double predicted_optional_time_ms = 0.0; - - // We want to make sure that on the one hand we process the retained regions asap, - // but on the other hand do not take too many of them as optional regions. - // So we split the time budget into budget we will unconditionally take into the - // initial old regions, and budget for taking optional regions from the retained - // list. - double optional_time_remaining_ms = max_time_for_retaining(); - time_remaining_ms = MIN2(time_remaining_ms, optional_time_remaining_ms); - - log_debug(gc, ergo, cset)("Start adding retained candidates to collection set. " - "Min %u regions, available %u, " - "time remaining %1.2fms, optional remaining %1.2fms", - min_regions, retained_list->length(), time_remaining_ms, optional_time_remaining_ms); - - for (G1CollectionSetCandidateInfo* ci : *retained_list) { - G1HeapRegion* r = ci->_r; - double predicted_time_ms = predict_region_total_time_ms(r, collector_state()->in_young_only_phase()); - bool fits_in_remaining_time = predicted_time_ms <= time_remaining_ms; - // If we can't reclaim that region ignore it for now. - if (r->has_pinned_objects()) { - num_pinned_regions++; - if (ci->update_num_unreclaimed()) { - log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Skipping.", r->hrm_index()); - } else { - log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Dropping.", r->hrm_index()); - pinned_old_regions->append(r); - } - continue; - } - - if (fits_in_remaining_time || (num_expensive_regions_selected < min_regions)) { - predicted_initial_time_ms += predicted_time_ms; - if (!fits_in_remaining_time) { - num_expensive_regions_selected++; - } - initial_old_regions->append(r); - num_initial_regions_selected++; - } else if (predicted_time_ms <= optional_time_remaining_ms) { - predicted_optional_time_ms += predicted_time_ms; - optional_old_regions->append(r); - num_optional_regions_selected++; - } else { - // Fits neither initial nor optional time limit. Exit. - break; - } - time_remaining_ms = MAX2(0.0, time_remaining_ms - predicted_time_ms); - optional_time_remaining_ms = MAX2(0.0, optional_time_remaining_ms - predicted_time_ms); - } - - uint num_regions_selected = num_initial_regions_selected + num_optional_regions_selected; - if (num_regions_selected == retained_list->length()) { - log_debug(gc, ergo, cset)("Retained candidates exhausted."); - } - if (num_expensive_regions_selected > 0) { - log_debug(gc, ergo, cset)("Added %u retained candidates to collection set although the predicted time was too high.", - num_expensive_regions_selected); - } - - log_debug(gc, ergo, cset)("Finish adding retained candidates to collection set. Initial: %u, optional: %u, pinned: %u, " - "predicted initial time: %1.2fms, predicted optional time: %1.2fms, " - "time remaining: %1.2fms optional time remaining %1.2fms", - num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, - predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms, optional_time_remaining_ms); -} - -void G1Policy::calculate_optional_collection_set_regions(G1CollectionCandidateRegionList* optional_regions, - double time_remaining_ms, - G1CollectionCandidateRegionList* selected_regions) { - assert(_collection_set->optional_region_length() > 0, - "Should only be called when there are optional regions"); - - double total_prediction_ms = 0.0; - - for (G1HeapRegion* r : *optional_regions) { - double prediction_ms = predict_region_total_time_ms(r, false); - - if (prediction_ms > time_remaining_ms) { - log_debug(gc, ergo, cset)("Prediction %.3fms for region %u does not fit remaining time: %.3fms.", - prediction_ms, r->hrm_index(), time_remaining_ms); - break; - } - // This region will be included in the next optional evacuation. - - total_prediction_ms += prediction_ms; - time_remaining_ms -= prediction_ms; - - selected_regions->append(r); - } - - log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Total predicted time: %.3fms", - selected_regions->length(), optional_regions->length(), total_prediction_ms); -} - void G1Policy::transfer_survivors_to_cset(const G1SurvivorRegions* survivors) { start_adding_survivor_regions(); diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 98d444084678c..9a6ffb570be70 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -335,27 +335,7 @@ class G1Policy: public CHeapObj { // Amount of allowed waste in bytes in the collection set. size_t allowed_waste_in_collection_set() const; - // Calculate and fill in the initial, optional and pinned old gen candidate regions from - // the given candidate list and the remaining time. - // Returns the remaining time. - double select_candidates_from_marking(G1CollectionCandidateList* marking_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions); - - void select_candidates_from_retained(G1CollectionCandidateList* retained_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions); - - // Calculate the number of optional regions from the given collection set candidates, - // the remaining time and the maximum number of these regions and return the number - // of actually selected regions in num_optional_regions. - void calculate_optional_collection_set_regions(G1CollectionCandidateRegionList* optional_old_regions, - double time_remaining_ms, - G1CollectionCandidateRegionList* selected); + private: @@ -423,12 +403,12 @@ class G1Policy: public CHeapObj { size_t desired_survivor_size(uint max_regions) const; +public: // Fraction used when predicting how many optional regions to include in // the CSet. This fraction of the available time is used for optional regions, // the rest is used to add old regions to the normal CSet. double optional_prediction_fraction() const { return 0.2; } -public: // Fraction used when evacuating the optional regions. This fraction of the // remaining time is used to choose what regions to include in the evacuation. double optional_evacuation_fraction() const { return 0.75; } diff --git a/src/hotspot/share/gc/g1/g1Predictions.hpp b/src/hotspot/share/gc/g1/g1Predictions.hpp index 510f296a9f3ac..ae2a8f418802a 100644 --- a/src/hotspot/share/gc/g1/g1Predictions.hpp +++ b/src/hotspot/share/gc/g1/g1Predictions.hpp @@ -29,8 +29,9 @@ // Utility class containing various helper methods for prediction. class G1Predictions { - private: - double _sigma; +private: + // Scale factor indicating to which degree stddev should be taking into account in predictions. + double _stddev_scale; // This function is used to estimate the stddev of sample sets. There is some // special consideration of small sample sets: the actual stddev for them is @@ -46,16 +47,14 @@ class G1Predictions { } return estimate; } - public: - G1Predictions(double sigma) : _sigma(sigma) { - assert(sigma >= 0.0, "Confidence must be larger than or equal to zero"); - } - // Confidence factor. - double sigma() const { return _sigma; } +public: + G1Predictions(double stddev_scale) : _stddev_scale(stddev_scale) { + assert(stddev_scale >= 0.0, "must be"); + } double predict(TruncatedSeq const* seq) const { - return seq->davg() + _sigma * stddev_estimate(seq); + return seq->davg() + _stddev_scale * stddev_estimate(seq); } double predict_in_unit_interval(TruncatedSeq const* seq) const { diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index f5f65cf1c48aa..bb5ac5036fe47 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -967,6 +967,10 @@ class G1MergeHeapRootsTask : public WorkerTask { _merged[G1GCPhaseTimes::MergeRSCards] += increment; } + void dec_remset_cards(size_t decrement) { + _merged[G1GCPhaseTimes::MergeRSCards] -= decrement; + } + size_t merged(uint i) const { return _merged[i]; } }; @@ -1091,6 +1095,11 @@ class G1MergeHeapRootsTask : public WorkerTask { G1MergeCardSetStats stats() { _merge_card_set_cache.flush(); + // Compensation for the dummy cards that were initially pushed into the + // card cache. + // We do not need to compensate for the other counters because the dummy + // card mark will never update another counter because it is initally "dirty". + _stats.dec_remset_cards(G1MergeCardSetCache::CacheSize); return _stats; } }; diff --git a/src/hotspot/share/gc/g1/g1_globals.hpp b/src/hotspot/share/gc/g1/g1_globals.hpp index c8016ddc0ddf5..ed02ba2dc5cad 100644 --- a/src/hotspot/share/gc/g1/g1_globals.hpp +++ b/src/hotspot/share/gc/g1/g1_globals.hpp @@ -111,7 +111,8 @@ range(1, max_intx) \ \ product(uint, G1ConfidencePercent, 50, \ - "Confidence level for MMU/pause predictions") \ + "Confidence level for MMU/pause predictions. A higher value " \ + "means that G1 will use less safety margin for its predictions.") \ range(1, 100) \ \ product(uintx, G1SummarizeRSetStatsPeriod, 0, DIAGNOSTIC, \ diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp index 76653f6c5e641..10ca66e354992 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,12 +53,10 @@ * bytes that can be moved during the adaptation phase. * Chunks may contain pages from a wrong locality group. The page-scanner has * been introduced to address the problem. Remote pages typically appear due to - * the memory shortage in the target locality group. Besides Solaris would - * allocate a large page from the remote locality group even if there are small - * local pages available. The page-scanner scans the pages right after the - * collection and frees remote pages in hope that subsequent reallocation would - * be more successful. This approach proved to be useful on systems with high - * load where multiple processes are competing for the memory. + * the memory shortage in the target locality group. The page-scanner scans the pages + * right after the collection and frees remote pages in hope that subsequent + * reallocation would be more successful. This approach proved to be useful on systems + * with high load where multiple processes are competing for the memory. */ class MutableNUMASpace : public MutableSpace { diff --git a/src/hotspot/share/gc/parallel/mutableSpace.cpp b/src/hotspot/share/gc/parallel/mutableSpace.cpp index d90121b0eaf2c..01d4e6bb04d6f 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.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 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/parallel/mutableSpace.hpp" #include "gc/shared/pretouchTask.hpp" +#include "gc/shared/spaceDecorator.hpp" #include "memory/iterator.inline.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index a6601611c9be2..22d1296507d13 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -246,7 +246,7 @@ class ParallelScavengeHeap : public CollectedHeap { } // Support for loading objects from CDS archive into the heap - bool can_load_archived_objects() const override { return UseCompressedOops; } + bool can_load_archived_objects() const override { return true; } HeapWord* allocate_loaded_archive_space(size_t size) override; void complete_loaded_archive_space(MemRegion archive_space) override; diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp index 2715ab90768e4..52ea4dc042cbb 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.cpp +++ b/src/hotspot/share/gc/parallel/psOldGen.cpp @@ -31,6 +31,7 @@ #include "gc/parallel/psOldGen.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/gcLocker.hpp" +#include "gc/shared/spaceDecorator.hpp" #include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 1ab7b2af7ed74..66ce20295f549 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -60,6 +60,7 @@ #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" +#include "gc/shared/spaceDecorator.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shared/weakProcessor.inline.hpp" diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 7df2143ccbb94..7701cea313b6a 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -51,6 +51,7 @@ #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shared/scavengableNMethods.hpp" +#include "gc/shared/spaceDecorator.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shared/weakProcessor.inline.hpp" diff --git a/src/hotspot/share/gc/parallel/psYoungGen.cpp b/src/hotspot/share/gc/parallel/psYoungGen.cpp index 7b0d3b215075e..dd9619e454656 100644 --- a/src/hotspot/share/gc/parallel/psYoungGen.cpp +++ b/src/hotspot/share/gc/parallel/psYoungGen.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 @@ -29,6 +29,7 @@ #include "gc/parallel/psYoungGen.hpp" #include "gc/shared/gcUtil.hpp" #include "gc/shared/genArguments.hpp" +#include "gc/shared/spaceDecorator.hpp" #include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 750bb322b2ac4..d787d216e37ab 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -291,7 +291,7 @@ class SerialHeap : public CollectedHeap { void safepoint_synchronize_end() override; // Support for loading objects from CDS archive into the heap - bool can_load_archived_objects() const override { return UseCompressedOops; } + bool can_load_archived_objects() const override { return true; } HeapWord* allocate_loaded_archive_space(size_t size) override; void complete_loaded_archive_space(MemRegion archive_space) override; diff --git a/src/hotspot/share/gc/shared/barrierSetConfig.hpp b/src/hotspot/share/gc/shared/barrierSetConfig.hpp index 76681aa898687..368312af06b21 100644 --- a/src/hotspot/share/gc/shared/barrierSetConfig.hpp +++ b/src/hotspot/share/gc/shared/barrierSetConfig.hpp @@ -33,7 +33,6 @@ EPSILONGC_ONLY(f(EpsilonBarrierSet)) \ G1GC_ONLY(f(G1BarrierSet)) \ SHENANDOAHGC_ONLY(f(ShenandoahBarrierSet)) \ - ZGC_ONLY(f(XBarrierSet)) \ ZGC_ONLY(f(ZBarrierSet)) #define FOR_EACH_ABSTRACT_BARRIER_SET_DO(f) \ diff --git a/src/hotspot/share/gc/shared/barrierSetConfig.inline.hpp b/src/hotspot/share/gc/shared/barrierSetConfig.inline.hpp index 9523428821b7e..001b5b00372bc 100644 --- a/src/hotspot/share/gc/shared/barrierSetConfig.inline.hpp +++ b/src/hotspot/share/gc/shared/barrierSetConfig.inline.hpp @@ -40,7 +40,6 @@ #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" #endif #if INCLUDE_ZGC -#include "gc/x/xBarrierSet.inline.hpp" #include "gc/z/zBarrierSet.inline.hpp" #endif diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp index 59e0245204441..643a7936b9b17 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp @@ -109,6 +109,10 @@ Label* BarrierStubC2::continuation() { return &_continuation; } +uint8_t BarrierStubC2::barrier_data() const { + return _node->barrier_data(); +} + void BarrierStubC2::preserve(Register r) { const VMReg vm_reg = r->as_VMReg(); assert(vm_reg->is_Register(), "r must be a general-purpose register"); diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp index c1485c069c83c..00fbf1f2c9f8b 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp @@ -254,6 +254,8 @@ class BarrierStubC2 : public ArenaObj { Label* entry(); // Return point from the stub (typically end of barrier). Label* continuation(); + // High-level, GC-specific barrier flags. + uint8_t barrier_data() const; // Preserve the value in reg across runtime calls in this barrier. void preserve(Register reg); @@ -340,6 +342,8 @@ class BarrierSetC2: public CHeapObj { // Estimated size of the node barrier in number of C2 Ideal nodes. // This is used to guide heuristics in C2, e.g. whether to unroll a loop. virtual uint estimated_barrier_size(const Node* node) const { return 0; } + // Whether the given store can be used to initialize a newly allocated object. + virtual bool can_initialize_object(const StoreNode* store) const { return true; } enum CompilePhase { BeforeOptimize, diff --git a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp index 87bb9f3cd5170..11b742156a831 100644 --- a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp @@ -125,39 +125,10 @@ void CardTableBarrierSetC2::post_barrier(GraphKit* kit, kit->final_sync(ideal); } -void CardTableBarrierSetC2::clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const { - BarrierSetC2::clone(kit, src, dst, size, is_array); - const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM; - - // If necessary, emit some card marks afterwards. (Non-arrays only.) - bool card_mark = !is_array && !use_ReduceInitialCardMarks(); - if (card_mark) { - assert(!is_array, ""); - // Put in store barrier for any and all oops we are sticking - // into this object. (We could avoid this if we could prove - // that the object type contains no oop fields at all.) - Node* no_particular_value = nullptr; - Node* no_particular_field = nullptr; - int raw_adr_idx = Compile::AliasIdxRaw; - post_barrier(kit, kit->control(), - kit->memory(raw_adr_type), - dst, - no_particular_field, - raw_adr_idx, - no_particular_value, - T_OBJECT, - false); - } -} - bool CardTableBarrierSetC2::use_ReduceInitialCardMarks() const { return ReduceInitialCardMarks; } -bool CardTableBarrierSetC2::is_gc_barrier_node(Node* node) const { - return ModRefBarrierSetC2::is_gc_barrier_node(node) || node->Opcode() == Op_StoreCM; -} - void CardTableBarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const { assert(node->Opcode() == Op_CastP2X, "ConvP2XNode required"); Node *shift = node->unique_out(); diff --git a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp index 9512f09ff8a6d..3bbf14892d3ef 100644 --- a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp @@ -42,8 +42,6 @@ class CardTableBarrierSetC2: public ModRefBarrierSetC2 { Node* byte_map_base_node(GraphKit* kit) const; public: - virtual void clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const; - virtual bool is_gc_barrier_node(Node* node) const; virtual void eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const; virtual bool array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, bool is_clone_instance, ArrayCopyPhase phase) const; diff --git a/src/hotspot/share/gc/shared/gcArguments.cpp b/src/hotspot/share/gc/shared/gcArguments.cpp index 9736c0f7fdcab..2522925746be1 100644 --- a/src/hotspot/share/gc/shared/gcArguments.cpp +++ b/src/hotspot/share/gc/shared/gcArguments.cpp @@ -30,6 +30,7 @@ #include "runtime/arguments.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" +#include "utilities/formatBuffer.hpp" #include "utilities/macros.hpp" size_t HeapAlignment = 0; @@ -166,6 +167,13 @@ void GCArguments::initialize_heap_flags_and_sizes() { FLAG_SET_ERGO(MinHeapDeltaBytes, align_up(MinHeapDeltaBytes, SpaceAlignment)); + if (checked_cast(ObjectAlignmentInBytes) > GCCardSizeInBytes) { + err_msg message("ObjectAlignmentInBytes %u is larger than GCCardSizeInBytes %u", + ObjectAlignmentInBytes, GCCardSizeInBytes); + vm_exit_during_initialization("Invalid combination of GCCardSizeInBytes and ObjectAlignmentInBytes", + message); + } + DEBUG_ONLY(assert_flags();) } diff --git a/src/hotspot/share/gc/shared/gcConfig.cpp b/src/hotspot/share/gc/shared/gcConfig.cpp index 506b368d6cf05..8eb265b54d939 100644 --- a/src/hotspot/share/gc/shared/gcConfig.cpp +++ b/src/hotspot/share/gc/shared/gcConfig.cpp @@ -44,7 +44,7 @@ #include "gc/shenandoah/shenandoahArguments.hpp" #endif #if INCLUDE_ZGC -#include "gc/z/shared/zSharedArguments.hpp" +#include "gc/z/zArguments.hpp" #endif struct IncludedGC { @@ -62,7 +62,7 @@ struct IncludedGC { PARALLELGC_ONLY(static ParallelArguments parallelArguments;) SERIALGC_ONLY(static SerialArguments serialArguments;) SHENANDOAHGC_ONLY(static ShenandoahArguments shenandoahArguments;) - ZGC_ONLY(static ZSharedArguments zArguments;) + ZGC_ONLY(static ZArguments zArguments;) // Table of included GCs, for translating between command // line flag, CollectedHeap::Name and GCArguments instance. diff --git a/src/hotspot/share/gc/shared/gcConfiguration.cpp b/src/hotspot/share/gc/shared/gcConfiguration.cpp index 2e8d3eb2a515a..824e119e69649 100644 --- a/src/hotspot/share/gc/shared/gcConfiguration.cpp +++ b/src/hotspot/share/gc/shared/gcConfiguration.cpp @@ -43,11 +43,7 @@ GCName GCConfiguration::young_collector() const { } if (UseZGC) { - if (ZGenerational) { - return ZMinor; - } else { - return NA; - } + return ZMinor; } if (UseShenandoahGC) { @@ -66,12 +62,8 @@ GCName GCConfiguration::old_collector() const { return ParallelOld; } - if (UseZGC) { - if (ZGenerational) { - return ZMajor; - } else { - return Z; - } +if (UseZGC) { + return ZMajor; } if (UseShenandoahGC) { diff --git a/src/hotspot/share/gc/shared/gcName.hpp b/src/hotspot/share/gc/shared/gcName.hpp index 3d2dd350ac10e..b9b87c231ca91 100644 --- a/src/hotspot/share/gc/shared/gcName.hpp +++ b/src/hotspot/share/gc/shared/gcName.hpp @@ -37,7 +37,6 @@ enum GCName { G1Full, ZMinor, ZMajor, - Z, // Support for the legacy, single-gen mode Shenandoah, NA, GCNameEndSentinel @@ -56,7 +55,6 @@ class GCNameHelper { case G1Full: return "G1Full"; case ZMinor: return "ZGC Minor"; case ZMajor: return "ZGC Major"; - case Z: return "Z"; case Shenandoah: return "Shenandoah"; case NA: return "N/A"; default: ShouldNotReachHere(); return nullptr; diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 34bc638c9baca..9086c25ee48fb 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -43,7 +43,7 @@ #include "gc/shenandoah/shenandoah_globals.hpp" #endif #if INCLUDE_ZGC -#include "gc/z/shared/z_shared_globals.hpp" +#include "gc/z/z_globals.hpp" #endif #define GC_FLAGS(develop, \ @@ -93,7 +93,7 @@ range, \ constraint)) \ \ - ZGC_ONLY(GC_Z_SHARED_FLAGS( \ + ZGC_ONLY(GC_Z_FLAGS( \ develop, \ develop_pd, \ product, \ @@ -118,9 +118,6 @@ product(bool, UseZGC, false, \ "Use the Z garbage collector") \ \ - product(bool, ZGenerational, true, \ - "Use the generational version of ZGC") \ - \ product(bool, UseShenandoahGC, false, \ "Use the Shenandoah garbage collector") \ \ diff --git a/src/hotspot/share/gc/shared/oopStorage.cpp b/src/hotspot/share/gc/shared/oopStorage.cpp index 568888ac7d97e..2373d6b1d93a8 100644 --- a/src/hotspot/share/gc/shared/oopStorage.cpp +++ b/src/hotspot/share/gc/shared/oopStorage.cpp @@ -300,7 +300,12 @@ void OopStorage::Block::set_active_index(size_t index) { size_t OopStorage::Block::active_index_safe(const Block* block) { STATIC_ASSERT(sizeof(intptr_t) == sizeof(block->_active_index)); - return SafeFetchN((intptr_t*)&block->_active_index, 0); + // Be careful, because block could be a false positive from block_for_ptr. + assert(block != nullptr, "precondition"); + uintptr_t block_addr = reinterpret_cast(block); + uintptr_t index_loc = block_addr + offset_of(Block, _active_index); + static_assert(sizeof(size_t) == sizeof(intptr_t), "assumption"); + return static_cast(SafeFetchN(reinterpret_cast(index_loc), 0)); } unsigned OopStorage::Block::get_index(const oop* ptr) const { @@ -366,21 +371,23 @@ void OopStorage::Block::delete_block(const Block& block) { OopStorage::Block* OopStorage::Block::block_for_ptr(const OopStorage* owner, const oop* ptr) { STATIC_ASSERT(_data_pos == 0); - // Const-ness of ptr is not related to const-ness of containing block. + assert(ptr != nullptr, "precondition"); // Blocks are allocated section-aligned, so get the containing section. - oop* section_start = align_down(const_cast(ptr), block_alignment); + uintptr_t section_start = align_down(reinterpret_cast(ptr), block_alignment); // Start with a guess that the containing section is the last section, // so the block starts section_count-1 sections earlier. - oop* section = section_start - (section_size * (section_count - 1)); + size_t section_size_in_bytes = sizeof(oop) * section_size; + uintptr_t section = section_start - (section_size_in_bytes * (section_count - 1)); // Walk up through the potential block start positions, looking for // the owner in the expected location. If we're below the actual block // start position, the value at the owner position will be some oop // (possibly null), which can never match the owner. intptr_t owner_addr = reinterpret_cast(owner); - for (unsigned i = 0; i < section_count; ++i, section += section_size) { - Block* candidate = reinterpret_cast(section); - if (SafeFetchN(&candidate->_owner_address, 0) == owner_addr) { - return candidate; + for (unsigned i = 0; i < section_count; ++i, section += section_size_in_bytes) { + uintptr_t owner_loc = section + offset_of(Block, _owner_address); + static_assert(sizeof(OopStorage*) == sizeof(intptr_t), "assumption"); + if (SafeFetchN(reinterpret_cast(owner_loc), 0) == owner_addr) { + return reinterpret_cast(section); } } return nullptr; @@ -643,8 +650,7 @@ class OopStorage::WithActiveArray : public StackObj { } }; -OopStorage::Block* OopStorage::find_block_or_null(const oop* ptr) const { - assert(ptr != nullptr, "precondition"); +OopStorage::Block* OopStorage::block_for_ptr(const oop* ptr) const { return Block::block_for_ptr(this, ptr); } @@ -771,7 +777,7 @@ static inline void check_release_entry(const oop* entry) { void OopStorage::release(const oop* ptr) { check_release_entry(ptr); - Block* block = find_block_or_null(ptr); + Block* block = block_for_ptr(ptr); assert(block != nullptr, "%s: invalid release " PTR_FORMAT, name(), p2i(ptr)); log_trace(oopstorage, ref)("%s: releasing " PTR_FORMAT, name(), p2i(ptr)); block->release_entries(block->bitmask_for_entry(ptr), this); @@ -782,7 +788,7 @@ void OopStorage::release(const oop* const* ptrs, size_t size) { size_t i = 0; while (i < size) { check_release_entry(ptrs[i]); - Block* block = find_block_or_null(ptrs[i]); + Block* block = block_for_ptr(ptrs[i]); assert(block != nullptr, "%s: invalid release " PTR_FORMAT, name(), p2i(ptrs[i])); size_t count = 0; uintx releasing = 0; @@ -989,7 +995,8 @@ bool OopStorage::delete_empty_blocks() { } OopStorage::EntryStatus OopStorage::allocation_status(const oop* ptr) const { - const Block* block = find_block_or_null(ptr); + if (ptr == nullptr) return INVALID_ENTRY; + const Block* block = block_for_ptr(ptr); if (block != nullptr) { // Prevent block deletion and _active_array modification. MutexLocker ml(_allocation_mutex, Mutex::_no_safepoint_check_flag); @@ -1137,7 +1144,7 @@ const char* OopStorage::name() const { return _name; } bool OopStorage::print_containing(const oop* addr, outputStream* st) { if (addr != nullptr) { - Block* block = find_block_or_null(addr); + Block* block = block_for_ptr(addr); if (block != nullptr && block->print_containing(addr, st)) { st->print(" in oop storage \"%s\"", name()); return true; diff --git a/src/hotspot/share/gc/shared/oopStorage.hpp b/src/hotspot/share/gc/shared/oopStorage.hpp index 96cc5a23d6a91..34c980a058659 100644 --- a/src/hotspot/share/gc/shared/oopStorage.hpp +++ b/src/hotspot/share/gc/shared/oopStorage.hpp @@ -288,7 +288,7 @@ class OopStorage : public CHeapObjBase { Block* block_for_allocation(); void log_block_transition(Block* block, const char* new_state) const; - Block* find_block_or_null(const oop* ptr) const; + Block* block_for_ptr(const oop* ptr) const; void delete_empty_block(const Block& block); bool reduce_deferred_updates(); void record_needs_cleanup(); diff --git a/src/hotspot/share/gc/shared/oopStorage.inline.hpp b/src/hotspot/share/gc/shared/oopStorage.inline.hpp index 545da0be0a76e..da0926a20b6e2 100644 --- a/src/hotspot/share/gc/shared/oopStorage.inline.hpp +++ b/src/hotspot/share/gc/shared/oopStorage.inline.hpp @@ -184,7 +184,10 @@ class OopStorage::Block /* No base class, to avoid messing up alignment. */ { void set_active_index(size_t index); static size_t active_index_safe(const Block* block); // Returns 0 if access fails. - // Returns null if ptr is not in a block or not allocated in that block. + // Return block of owner containing ptr, if ptr is a valid entry of owner. + // If ptr is not a valid entry of owner then returns either null or a "false + // positive" pointer; see allocation_status. + // precondition: ptr != nullptr static Block* block_for_ptr(const OopStorage* owner, const oop* ptr); oop* allocate(); diff --git a/src/hotspot/share/gc/shared/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp index c4acb0b1ed6ca..bba9c9e099fc9 100644 --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp @@ -46,7 +46,7 @@ #include "gc/shenandoah/vmStructs_shenandoah.hpp" #endif #if INCLUDE_ZGC -#include "gc/z/shared/vmStructs_z_shared.hpp" +#include "gc/z/vmStructs_z.hpp" #endif #define VM_STRUCTS_GC(nonstatic_field, \ @@ -69,7 +69,7 @@ SHENANDOAHGC_ONLY(VM_STRUCTS_SHENANDOAH(nonstatic_field, \ volatile_nonstatic_field, \ static_field)) \ - ZGC_ONLY(VM_STRUCTS_Z_SHARED(nonstatic_field, \ + ZGC_ONLY(VM_STRUCTS_Z(nonstatic_field, \ volatile_nonstatic_field, \ static_field)) \ \ @@ -91,6 +91,7 @@ nonstatic_field(CardTableBarrierSet, _defer_initial_card_mark, bool) \ nonstatic_field(CardTableBarrierSet, _card_table, CardTable*) \ \ + static_field(CollectedHeap, _lab_alignment_reserve, size_t) \ nonstatic_field(CollectedHeap, _reserved, MemRegion) \ nonstatic_field(CollectedHeap, _is_stw_gc_active, bool) \ nonstatic_field(CollectedHeap, _total_collections, unsigned int) \ @@ -120,7 +121,7 @@ SHENANDOAHGC_ONLY(VM_TYPES_SHENANDOAH(declare_type, \ declare_toplevel_type, \ declare_integer_type)) \ - ZGC_ONLY(VM_TYPES_Z_SHARED(declare_type, \ + ZGC_ONLY(VM_TYPES_Z(declare_type, \ declare_toplevel_type, \ declare_integer_type)) \ \ @@ -174,7 +175,7 @@ declare_constant_with_value)) \ SHENANDOAHGC_ONLY(VM_INT_CONSTANTS_SHENANDOAH(declare_constant, \ declare_constant_with_value)) \ - ZGC_ONLY(VM_INT_CONSTANTS_Z_SHARED(declare_constant, \ + ZGC_ONLY(VM_INT_CONSTANTS_Z(declare_constant, \ declare_constant_with_value)) \ \ /********************************************/ \ @@ -198,6 +199,6 @@ declare_constant(CollectedHeap::G1) \ #define VM_LONG_CONSTANTS_GC(declare_constant) \ - ZGC_ONLY(VM_LONG_CONSTANTS_Z_SHARED(declare_constant)) + ZGC_ONLY(VM_LONG_CONSTANTS_Z(declare_constant)) #endif // SHARE_GC_SHARED_VMSTRUCTS_GC_HPP diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 7ac9dcc2e8134..691c78cd02486 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -480,10 +480,17 @@ Node* ShenandoahBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& const TypePtr* adr_type = access.addr().type(); Node* adr = access.addr().node(); + bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0; + if (!access.is_oop()) { return BarrierSetC2::store_at_resolved(access, val); } + if (no_keepalive) { + // No keep-alive means no need for the pre-barrier. + return BarrierSetC2::store_at_resolved(access, val); + } + if (access.is_parse_access()) { C2ParseAccess& parse_access = static_cast(access); GraphKit* kit = parse_access.kit(); diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index efa0ced603cda..10dd650917170 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -1041,6 +1041,7 @@ void ShenandoahBarrierC2Support::fix_ctrl(Node* barrier, Node* region, const Mem Node* u = ctrl->fast_out(i); if (u->_idx < last && u != barrier && + !u->depends_only_on_test() && // preserve dependency on test !uses_to_ignore.member(u) && (u->in(0) != ctrl || (!u->is_Region() && !u->is_Phi())) && (ctrl->Opcode() != Op_CatchProj || u->Opcode() != Op_CreateEx)) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index 51903a60fb4fd..58527e808e43c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -25,18 +25,78 @@ #define SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP #include "code/nmethod.hpp" +#include "gc/shared/stringdedup/stringDedup.hpp" +#include "gc/shenandoah/shenandoahGenerationType.hpp" +#include "gc/shenandoah/shenandoahTaskqueue.hpp" #include "memory/iterator.hpp" -#include "oops/accessDecorators.hpp" -#include "runtime/handshake.hpp" +#include "runtime/javaThread.hpp" class BarrierSetNMethod; class ShenandoahBarrierSet; class ShenandoahHeap; class ShenandoahMarkingContext; -class ShenandoahHeapRegionSet; -class Thread; +class ShenandoahReferenceProcessor; -class ShenandoahForwardedIsAliveClosure: public BoolObjectClosure { +// +// ========= Super +// + +class ShenandoahSuperClosure : public MetadataVisitingOopIterateClosure { +protected: + ShenandoahHeap* const _heap; + +public: + inline ShenandoahSuperClosure(); + inline ShenandoahSuperClosure(ShenandoahReferenceProcessor* rp); + inline void do_nmethod(nmethod* nm); +}; + +// +// ========= Marking +// + +class ShenandoahMarkRefsSuperClosure : public ShenandoahSuperClosure { +private: + ShenandoahObjToScanQueue* _queue; + ShenandoahMarkingContext* const _mark_context; + bool _weak; + +protected: + template + void work(T *p); + +public: + inline ShenandoahMarkRefsSuperClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp); + + bool is_weak() const { + return _weak; + } + + void set_weak(bool weak) { + _weak = weak; + } + + virtual void do_nmethod(nmethod* nm) { + assert(!is_weak(), "Can't handle weak marking of nmethods"); + ShenandoahSuperClosure::do_nmethod(nm); + } +}; + +template +class ShenandoahMarkRefsClosure : public ShenandoahMarkRefsSuperClosure { +private: + template + inline void do_oop_work(T* p) { work(p); } + +public: + ShenandoahMarkRefsClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : + ShenandoahMarkRefsSuperClosure(q, rp) {}; + + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop(oop* p) { do_oop_work(p); } +}; + +class ShenandoahForwardedIsAliveClosure : public BoolObjectClosure { private: ShenandoahMarkingContext* const _mark_context; public: @@ -44,7 +104,7 @@ class ShenandoahForwardedIsAliveClosure: public BoolObjectClosure { inline bool do_object_b(oop obj); }; -class ShenandoahIsAliveClosure: public BoolObjectClosure { +class ShenandoahIsAliveClosure : public BoolObjectClosure { private: ShenandoahMarkingContext* const _mark_context; public: @@ -63,39 +123,29 @@ class ShenandoahIsAliveSelector : public StackObj { class ShenandoahKeepAliveClosure : public OopClosure { private: ShenandoahBarrierSet* const _bs; -public: - inline ShenandoahKeepAliveClosure(); - inline void do_oop(oop* p); - inline void do_oop(narrowOop* p); -private: template void do_oop_work(T* p); -}; -class ShenandoahOopClosureBase : public MetadataVisitingOopIterateClosure { public: - inline void do_nmethod(nmethod* nm); + inline ShenandoahKeepAliveClosure(); + inline void do_oop(oop* p) { do_oop_work(p); } + inline void do_oop(narrowOop* p) { do_oop_work(p); } }; -class ShenandoahUpdateRefsClosure: public ShenandoahOopClosureBase { -private: - ShenandoahHeap* _heap; -public: - inline ShenandoahUpdateRefsClosure(); - inline void do_oop(oop* p); - inline void do_oop(narrowOop* p); -private: - template - inline void do_oop_work(T* p); -}; -template -class ShenandoahEvacuateUpdateRootClosureBase : public ShenandoahOopClosureBase { +// +// ========= Evacuating + Roots +// + +template +class ShenandoahEvacuateUpdateRootClosureBase : public ShenandoahSuperClosure { protected: - ShenandoahHeap* const _heap; Thread* const _thread; public: - inline ShenandoahEvacuateUpdateRootClosureBase(); + inline ShenandoahEvacuateUpdateRootClosureBase() : + ShenandoahSuperClosure(), + _thread(STABLE_THREAD ? Thread::current() : nullptr) {} + inline void do_oop(oop* p); inline void do_oop(narrowOop* p); protected: @@ -103,10 +153,11 @@ class ShenandoahEvacuateUpdateRootClosureBase : public ShenandoahOopClosureBase inline void do_oop_work(T* p); }; -using ShenandoahEvacuateUpdateMetadataClosure = ShenandoahEvacuateUpdateRootClosureBase; -using ShenandoahEvacuateUpdateRootsClosure = ShenandoahEvacuateUpdateRootClosureBase; +using ShenandoahEvacuateUpdateMetadataClosure = ShenandoahEvacuateUpdateRootClosureBase; +using ShenandoahEvacuateUpdateRootsClosure = ShenandoahEvacuateUpdateRootClosureBase; using ShenandoahContextEvacuateUpdateRootsClosure = ShenandoahEvacuateUpdateRootClosureBase; + template class ShenandoahCleanUpdateWeakOopsClosure : public OopClosure { private: @@ -119,7 +170,7 @@ class ShenandoahCleanUpdateWeakOopsClosure : public OopClosure { inline void do_oop(narrowOop* p); }; -class ShenandoahNMethodAndDisarmClosure: public NMethodToOopClosure { +class ShenandoahNMethodAndDisarmClosure : public NMethodToOopClosure { private: BarrierSetNMethod* const _bs; @@ -128,6 +179,51 @@ class ShenandoahNMethodAndDisarmClosure: public NMethodToOopClosure { inline void do_nmethod(nmethod* nm); }; + +// +// ========= Update References +// + +template +class ShenandoahMarkUpdateRefsClosure : public ShenandoahMarkRefsSuperClosure { +private: + template + inline void work(T* p); + +public: + ShenandoahMarkUpdateRefsClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp); + + virtual void do_oop(narrowOop* p) { work(p); } + virtual void do_oop(oop* p) { work(p); } +}; + +class ShenandoahUpdateRefsSuperClosure : public ShenandoahSuperClosure {}; + +class ShenandoahNonConcUpdateRefsClosure : public ShenandoahUpdateRefsSuperClosure { +private: + template + inline void work(T* p); + +public: + virtual void do_oop(narrowOop* p) { work(p); } + virtual void do_oop(oop* p) { work(p); } +}; + +class ShenandoahConcUpdateRefsClosure : public ShenandoahUpdateRefsSuperClosure { +private: + template + inline void work(T* p); + +public: + virtual void do_oop(narrowOop* p) { work(p); } + virtual void do_oop(oop* p) { work(p); } +}; + + +// +// ========= Utilities +// + #ifdef ASSERT class ShenandoahAssertNotForwardedClosure : public OopClosure { private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index befc0d7c1f121..edfb62b40466a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -33,15 +33,46 @@ #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahNMethod.inline.hpp" +#include "gc/shenandoah/shenandoahMark.inline.hpp" +#include "gc/shenandoah/shenandoahReferenceProcessor.hpp" +#include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" #include "memory/iterator.inline.hpp" #include "oops/compressedOops.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" -ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() : - _mark_context(ShenandoahHeap::heap()->marking_context()) { +// +// ========= Super +// + +ShenandoahSuperClosure::ShenandoahSuperClosure() : + MetadataVisitingOopIterateClosure(), _heap(ShenandoahHeap::heap()) {} + +ShenandoahSuperClosure::ShenandoahSuperClosure(ShenandoahReferenceProcessor* rp) : + MetadataVisitingOopIterateClosure(rp), _heap(ShenandoahHeap::heap()) {} + +void ShenandoahSuperClosure::do_nmethod(nmethod* nm) { + nm->run_nmethod_entry_barrier(); } +// +// ========= Marking +// + +ShenandoahMarkRefsSuperClosure::ShenandoahMarkRefsSuperClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : + ShenandoahSuperClosure(rp), + _queue(q), + _mark_context(ShenandoahHeap::heap()->marking_context()), + _weak(false) {} + +template +inline void ShenandoahMarkRefsSuperClosure::work(T* p) { + ShenandoahMark::mark_through_ref(p, _queue, _mark_context, _weak); +} + +ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() : + _mark_context(ShenandoahHeap::heap()->marking_context()) {} + bool ShenandoahForwardedIsAliveClosure::do_object_b(oop obj) { if (CompressedOops::is_null(obj)) { return false; @@ -52,8 +83,7 @@ bool ShenandoahForwardedIsAliveClosure::do_object_b(oop obj) { } ShenandoahIsAliveClosure::ShenandoahIsAliveClosure() : - _mark_context(ShenandoahHeap::heap()->marking_context()) { -} + _mark_context(ShenandoahHeap::heap()->marking_context()) {} bool ShenandoahIsAliveClosure::do_object_b(oop obj) { if (CompressedOops::is_null(obj)) { @@ -69,21 +99,8 @@ BoolObjectClosure* ShenandoahIsAliveSelector::is_alive_closure() { reinterpret_cast(&_alive_cl); } -void ShenandoahOopClosureBase::do_nmethod(nmethod* nm) { - nm->run_nmethod_entry_barrier(); -} - ShenandoahKeepAliveClosure::ShenandoahKeepAliveClosure() : - _bs(ShenandoahBarrierSet::barrier_set()) { -} - -void ShenandoahKeepAliveClosure::do_oop(oop* p) { - do_oop_work(p); -} - -void ShenandoahKeepAliveClosure::do_oop(narrowOop* p) { - do_oop_work(p); -} + _bs(ShenandoahBarrierSet::barrier_set()) {} template void ShenandoahKeepAliveClosure::do_oop_work(T* p) { @@ -97,26 +114,14 @@ void ShenandoahKeepAliveClosure::do_oop_work(T* p) { } } -ShenandoahUpdateRefsClosure::ShenandoahUpdateRefsClosure() : - _heap(ShenandoahHeap::heap()) { -} - -template -void ShenandoahUpdateRefsClosure::do_oop_work(T* p) { - _heap->update_with_forwarded(p); -} - -void ShenandoahUpdateRefsClosure::do_oop(oop* p) { do_oop_work(p); } -void ShenandoahUpdateRefsClosure::do_oop(narrowOop* p) { do_oop_work(p); } -template -ShenandoahEvacuateUpdateRootClosureBase::ShenandoahEvacuateUpdateRootClosureBase() : - _heap(ShenandoahHeap::heap()), _thread(stable_thread ? Thread::current() : nullptr) { -} +// +// ========= Evacuating + Roots +// -template -void ShenandoahEvacuateUpdateRootClosureBase::do_oop(oop* p) { - if (concurrent) { +template +void ShenandoahEvacuateUpdateRootClosureBase::do_oop(oop* p) { + if (CONCURRENT) { ShenandoahEvacOOMScope scope; do_oop_work(p); } else { @@ -124,9 +129,9 @@ void ShenandoahEvacuateUpdateRootClosureBase::do_oop( } } -template -void ShenandoahEvacuateUpdateRootClosureBase::do_oop(narrowOop* p) { - if (concurrent) { +template +void ShenandoahEvacuateUpdateRootClosureBase::do_oop(narrowOop* p) { + if (CONCURRENT) { ShenandoahEvacOOMScope scope; do_oop_work(p); } else { @@ -134,9 +139,9 @@ void ShenandoahEvacuateUpdateRootClosureBase::do_oop( } } -template +template template -void ShenandoahEvacuateUpdateRootClosureBase::do_oop_work(T* p) { +void ShenandoahEvacuateUpdateRootClosureBase::do_oop_work(T* p) { assert(_heap->is_concurrent_weak_root_in_progress() || _heap->is_concurrent_strong_root_in_progress(), "Only do this in root processing phase"); @@ -149,12 +154,12 @@ void ShenandoahEvacuateUpdateRootClosureBase::do_oop_work shenandoah_assert_marked(p, obj); oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); if (resolved == obj) { - Thread* thr = stable_thread ? _thread : Thread::current(); + Thread* thr = STABLE_THREAD ? _thread : Thread::current(); assert(thr == Thread::current(), "Wrong thread"); resolved = _heap->evacuate_object(obj, thr); } - if (atomic) { + if (CONCURRENT) { ShenandoahHeap::atomic_update_oop(resolved, p, o); } else { RawAccess::oop_store(p, resolved); @@ -204,6 +209,42 @@ void ShenandoahNMethodAndDisarmClosure::do_nmethod(nmethod* nm) { _bs->disarm(nm); } + +// +// ========= Update References +// + +template +ShenandoahMarkUpdateRefsClosure::ShenandoahMarkUpdateRefsClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : + ShenandoahMarkRefsSuperClosure(q, rp) { + assert(_heap->is_stw_gc_in_progress(), "Can only be used for STW GC"); +} + +template +template +inline void ShenandoahMarkUpdateRefsClosure::work(T* p) { + // Update the location + _heap->non_conc_update_with_forwarded(p); + + // ...then do the usual thing + ShenandoahMarkRefsSuperClosure::work(p); +} + +template +inline void ShenandoahNonConcUpdateRefsClosure::work(T* p) { + _heap->non_conc_update_with_forwarded(p); +} + +template +inline void ShenandoahConcUpdateRefsClosure::work(T* p) { + _heap->conc_update_with_forwarded(p); +} + + +// +// ========= Utilities +// + #ifdef ASSERT template void ShenandoahAssertNotForwardedClosure::do_oop_work(T* p) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index ed40fecfc1db8..d801dda372eb4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -29,13 +29,13 @@ #include "gc/shared/collectorCounters.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shenandoah/shenandoahBreakpoint.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentGC.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" @@ -931,7 +931,10 @@ void ShenandoahConcurrentGC::op_updaterefs() { class ShenandoahUpdateThreadClosure : public HandshakeClosure { private: - ShenandoahUpdateRefsClosure _cl; + // This closure runs when thread is stopped for handshake, which means + // we can use non-concurrent closure here, as long as it only updates + // locations modified by the thread itself, i.e. stack locations. + ShenandoahNonConcUpdateRefsClosure _cl; public: ShenandoahUpdateThreadClosure(); void do_thread(Thread* thread); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 75cdb99e177d1..0e2ef4144adc9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -34,7 +34,6 @@ #include "gc/shenandoah/shenandoahMark.inline.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahStringDedup.hpp" #include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 8a4ef63b8e38b..df2d6d092e630 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -177,10 +177,13 @@ void ShenandoahControlThread::run_service() { // it is a normal completion, or the abort. heap->free_set()->log_status_under_lock(); - // Notify Universe about new heap usage. This has implications for - // global soft refs policy, and we better report it every time heap - // usage goes down. - heap->update_capacity_and_used_at_gc(); + { + // Notify Universe about new heap usage. This has implications for + // global soft refs policy, and we better report it every time heap + // usage goes down. + ShenandoahHeapLocker locker(heap->lock()); + heap->update_capacity_and_used_at_gc(); + } // Signal that we have completed a visit to all live objects. heap->record_whole_heap_examined_timestamp(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 81d07a414cd95..2249c38455f1a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -32,7 +32,6 @@ #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMetrics.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahSTWMark.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 03e19a3af5e30..310cd5b8061eb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -910,7 +910,6 @@ void ShenandoahFreeSet::try_recycle_trashed(ShenandoahHeapRegion* r) { void ShenandoahFreeSet::recycle_trash() { // lock is not reentrable, check we don't have it shenandoah_assert_not_heaplocked(); - size_t count = 0; for (size_t i = 0; i < _heap->num_regions(); i++) { ShenandoahHeapRegion* r = _heap->get_region(i); @@ -919,16 +918,45 @@ void ShenandoahFreeSet::recycle_trash() { } } - // Relinquish the lock after this much time passed. - static constexpr jlong deadline_ns = 30000; // 30 us + size_t total_batches = 0; + jlong batch_start_time = 0; + jlong recycle_trash_start_time = os::javaTimeNanos(); // This value will be treated as the initial batch_start_time + jlong batch_end_time = recycle_trash_start_time; + // Process as many batches as can be processed within 10 us. + static constexpr jlong deadline_ns = 10000; // 10 us size_t idx = 0; + jlong predicted_next_batch_end_time; + jlong batch_process_time_estimate = 0; while (idx < count) { - os::naked_yield(); // Yield to allow allocators to take the lock - ShenandoahHeapLocker locker(_heap->lock()); - const jlong deadline = os::javaTimeNanos() + deadline_ns; - while (idx < count && os::javaTimeNanos() < deadline) { - try_recycle_trashed(_trash_regions[idx++]); + if (idx > 0) { + os::naked_yield(); // Yield to allow allocators to take the lock, except on the first iteration } + // Avoid another call to javaTimeNanos() if we already know time at which last batch ended + batch_start_time = batch_end_time; + const jlong deadline = batch_start_time + deadline_ns; + + ShenandoahHeapLocker locker(_heap->lock()); + do { + // Measurements on typical 2024 hardware suggest it typically requires between 1400 and 2000 ns to process a batch of + // 32 regions, assuming low contention with other threads. Sometimes this goes higher, when mutator threads + // are contending for CPU cores and/or the heap lock. On this hardware with a 10 us deadline, we expect 3-6 batches + // to be processed between yields most of the time. + // + // Note that deadline is enforced since the end of previous batch. In the case that yield() or acquisition of heap lock + // takes a "long time", we will have less time to process regions, but we will always process at least one batch between + // yields. Yielding more frequently when there is heavy contention for the heap lock or for CPU cores is considered the + // right thing to do. + const size_t REGIONS_PER_BATCH = 32; + size_t max_idx = MIN2(count, idx + REGIONS_PER_BATCH); + while (idx < max_idx) { + try_recycle_trashed(_trash_regions[idx++]); + } + total_batches++; + batch_end_time = os::javaTimeNanos(); + // Estimate includes historic combination of yield times and heap lock acquisition times. + batch_process_time_estimate = (batch_end_time - recycle_trash_start_time) / total_batches; + predicted_next_batch_end_time = batch_end_time + batch_process_time_estimate; + } while ((idx < count) && (predicted_next_batch_end_time < deadline)); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index de7d81d0f43cd..c2d94353d54bb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -31,6 +31,7 @@ #include "gc/shared/tlab_globals.hpp" #include "gc/shared/workerThread.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentGC.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" @@ -44,7 +45,6 @@ #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahMetrics.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahSTWMark.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp index 922f54edf3c0c..719abde4b165d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp @@ -66,13 +66,13 @@ class ShenandoahUpdateRootsTask : public WorkerTask { assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint"); ShenandoahParallelWorkerSession worker_session(worker_id); - ShenandoahUpdateRefsClosure cl; + ShenandoahNonConcUpdateRefsClosure cl; if (_check_alive) { ShenandoahForwardedIsAliveClosure is_alive; - _root_updater->roots_do(worker_id, &is_alive, &cl); + _root_updater->roots_do(worker_id, &is_alive, &cl); } else { - AlwaysTrueClosure always_true;; - _root_updater->roots_do(worker_id, &always_true, &cl); + AlwaysTrueClosure always_true; + _root_updater->roots_do(worker_id, &always_true, &cl); } } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 7ae4a1cf8b3dc..07914947ead27 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -53,7 +53,6 @@ #include "gc/shenandoah/shenandoahMemoryPool.hpp" #include "gc/shenandoah/shenandoahMetrics.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahPacer.inline.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" #include "gc/shenandoah/shenandoahParallelCleaning.inline.hpp" @@ -2012,8 +2011,8 @@ void ShenandoahHeap::stw_process_weak_roots(bool full_gc) { // Cleanup weak roots if (has_forwarded_objects()) { ShenandoahForwardedIsAliveClosure is_alive; - ShenandoahUpdateRefsClosure keep_alive; - ShenandoahParallelWeakRootsCleaningTask + ShenandoahNonConcUpdateRefsClosure keep_alive; + ShenandoahParallelWeakRootsCleaningTask cleaning_task(timing_phase, &is_alive, &keep_alive, num_workers); _workers->run_task(&cleaning_task); } else { @@ -2197,7 +2196,7 @@ class ShenandoahUpdateHeapRefsTask : public WorkerTask { do_work(worker_id); } else { ShenandoahParallelWorkerSession worker_session(worker_id); - do_work(worker_id); + do_work(worker_id); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 1ee1f9dfc88be..7e616f925d035 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -543,7 +543,7 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { // ---------- CDS archive support - bool can_load_archived_objects() const override { return UseCompressedOops; } + bool can_load_archived_objects() const override { return true; } HeapWord* allocate_loaded_archive_space(size_t size) override; void complete_loaded_archive_space(MemRegion archive_space) override; @@ -660,7 +660,7 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { inline void conc_update_with_forwarded(T* p); template - inline void update_with_forwarded(T* p); + inline void non_conc_update_with_forwarded(T* p); static inline void atomic_update_oop(oop update, oop* addr, oop compare); static inline void atomic_update_oop(oop update, narrowOop* addr, oop compare); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index f2cc602d8cbc0..cd2cc2eb20930 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -108,7 +108,7 @@ inline void ShenandoahHeap::leave_evacuation(Thread* t) { } template -inline void ShenandoahHeap::update_with_forwarded(T* p) { +inline void ShenandoahHeap::non_conc_update_with_forwarded(T* p) { T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 4c45f4a7659b8..775b84a8966c1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -28,19 +28,11 @@ #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" -ShenandoahMarkRefsSuperClosure::ShenandoahMarkRefsSuperClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : - MetadataVisitingOopIterateClosure(rp), - _queue(q), - _mark_context(ShenandoahHeap::heap()->marking_context()), - _weak(false) -{ } - ShenandoahMark::ShenandoahMark() : _task_queues(ShenandoahHeap::heap()->marking_context()->task_queues()) { } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 99995c469eb64..2eca17bde275d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -30,9 +30,9 @@ #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahStringDedup.inline.hpp" #include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp index 5eb0b277b5ef8..75687302ca573 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp @@ -28,7 +28,6 @@ #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahNMethod.inline.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "memory/resourceArea.hpp" #include "runtime/continuation.hpp" #include "runtime/safepointVerifiers.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp deleted file mode 100644 index e433c2910c8d8..0000000000000 --- a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2015, 2022, 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. - * - */ - -#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHOOPCLOSURES_HPP -#define SHARE_GC_SHENANDOAH_SHENANDOAHOOPCLOSURES_HPP - -#include "gc/shared/stringdedup/stringDedup.hpp" -#include "gc/shenandoah/shenandoahClosures.inline.hpp" -#include "gc/shenandoah/shenandoahGenerationType.hpp" -#include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahTaskqueue.hpp" -#include "gc/shenandoah/shenandoahUtils.hpp" -#include "memory/iterator.hpp" -#include "runtime/javaThread.hpp" - -class ShenandoahMarkRefsSuperClosure : public MetadataVisitingOopIterateClosure { -private: - ShenandoahObjToScanQueue* _queue; - ShenandoahMarkingContext* const _mark_context; - bool _weak; - -protected: - template - void work(T *p); - -public: - ShenandoahMarkRefsSuperClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp); - - bool is_weak() const { - return _weak; - } - - void set_weak(bool weak) { - _weak = weak; - } - - virtual void do_nmethod(nmethod* nm) { - assert(!is_weak(), "Can't handle weak marking of nmethods"); - nm->run_nmethod_entry_barrier(); - } -}; - -class ShenandoahMarkUpdateRefsSuperClosure : public ShenandoahMarkRefsSuperClosure { -protected: - ShenandoahHeap* const _heap; - - template - inline void work(T* p); - -public: - ShenandoahMarkUpdateRefsSuperClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : - ShenandoahMarkRefsSuperClosure(q, rp), - _heap(ShenandoahHeap::heap()) { - assert(_heap->is_stw_gc_in_progress(), "Can only be used for STW GC"); - }; -}; - -template -class ShenandoahMarkUpdateRefsClosure : public ShenandoahMarkUpdateRefsSuperClosure { -private: - template - inline void do_oop_work(T* p) { work(p); } - -public: - ShenandoahMarkUpdateRefsClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : - ShenandoahMarkUpdateRefsSuperClosure(q, rp) {} - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop(oop* p) { do_oop_work(p); } -}; - -template -class ShenandoahMarkRefsClosure : public ShenandoahMarkRefsSuperClosure { -private: - template - inline void do_oop_work(T* p) { work(p); } - -public: - ShenandoahMarkRefsClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : - ShenandoahMarkRefsSuperClosure(q, rp) {}; - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop(oop* p) { do_oop_work(p); } -}; - - -class ShenandoahUpdateRefsSuperClosure : public ShenandoahOopClosureBase { -protected: - ShenandoahHeap* _heap; - -public: - ShenandoahUpdateRefsSuperClosure() : _heap(ShenandoahHeap::heap()) {} -}; - -class ShenandoahSTWUpdateRefsClosure : public ShenandoahUpdateRefsSuperClosure { -private: - template - inline void work(T* p); - -public: - ShenandoahSTWUpdateRefsClosure() : ShenandoahUpdateRefsSuperClosure() { - assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must only be used at safepoints"); - } - - virtual void do_oop(narrowOop* p) { work(p); } - virtual void do_oop(oop* p) { work(p); } -}; - -class ShenandoahConcUpdateRefsClosure : public ShenandoahUpdateRefsSuperClosure { -private: - template - inline void work(T* p); - -public: - ShenandoahConcUpdateRefsClosure() : ShenandoahUpdateRefsSuperClosure() {} - - virtual void do_oop(narrowOop* p) { work(p); } - virtual void do_oop(oop* p) { work(p); } -}; - -#endif // SHARE_GC_SHENANDOAH_SHENANDOAHOOPCLOSURES_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp deleted file mode 100644 index 70d7e94fb503f..0000000000000 --- a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2015, 2021, 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. - * - */ - -#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHOOPCLOSURES_INLINE_HPP -#define SHARE_GC_SHENANDOAH_SHENANDOAHOOPCLOSURES_INLINE_HPP - -#include "gc/shenandoah/shenandoahOopClosures.hpp" - -#include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahMark.inline.hpp" - -template -inline void ShenandoahMarkRefsSuperClosure::work(T* p) { - ShenandoahMark::mark_through_ref(p, _queue, _mark_context, _weak); -} - -template -inline void ShenandoahMarkUpdateRefsSuperClosure::work(T* p) { - // Update the location - _heap->update_with_forwarded(p); - - // ...then do the usual thing - ShenandoahMarkRefsSuperClosure::work(p); -} - -template -inline void ShenandoahSTWUpdateRefsClosure::work(T* p) { - _heap->update_with_forwarded(p); -} - -template -inline void ShenandoahConcUpdateRefsClosure::work(T* p) { - _heap->conc_update_with_forwarded(p); -} - -#endif // SHARE_GC_SHENANDOAH_SHENANDOAHOOPCLOSURES_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp index e67d3d197d42d..8d10b7cbfcfaf 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp @@ -65,6 +65,7 @@ void ShenandoahPacer::setup_for_mark() { size_t non_taxable = free * ShenandoahPacingCycleSlack / 100; size_t taxable = free - non_taxable; + taxable = MAX2(1, taxable); double tax = 1.0 * live / taxable; // base tax for available free space tax *= 1; // mark can succeed with immediate garbage, claim all available space @@ -88,6 +89,7 @@ void ShenandoahPacer::setup_for_evac() { size_t non_taxable = free * ShenandoahPacingCycleSlack / 100; size_t taxable = free - non_taxable; + taxable = MAX2(1, taxable); double tax = 1.0 * used / taxable; // base tax for available free space tax *= 2; // evac is followed by update-refs, claim 1/2 of remaining free @@ -112,6 +114,7 @@ void ShenandoahPacer::setup_for_updaterefs() { size_t non_taxable = free * ShenandoahPacingCycleSlack / 100; size_t taxable = free - non_taxable; + taxable = MAX2(1, taxable); double tax = 1.0 * used / taxable; // base tax for available free space tax *= 1; // update-refs is the last phase, claim the remaining free diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index 42c8d0ad27112..fe1d6d69bd8ba 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -26,7 +26,7 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" #include "gc/shared/workerThread.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 9a30b1fed8724..2e581d918d4a4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -31,39 +31,11 @@ #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahGenerationType.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahSTWMark.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" -template -class ShenandoahInitMarkRootsClosure : public OopClosure { -private: - ShenandoahObjToScanQueue* const _queue; - ShenandoahMarkingContext* const _mark_context; - - template - inline void do_oop_work(T* p); -public: - ShenandoahInitMarkRootsClosure(ShenandoahObjToScanQueue* q); - - void do_oop(narrowOop* p) { do_oop_work(p); } - void do_oop(oop* p) { do_oop_work(p); } -}; - -template -ShenandoahInitMarkRootsClosure::ShenandoahInitMarkRootsClosure(ShenandoahObjToScanQueue* q) : - _queue(q), - _mark_context(ShenandoahHeap::heap()->marking_context()) { -} - -template -template -void ShenandoahInitMarkRootsClosure::do_oop_work(T* p) { - ShenandoahMark::mark_through_ref(p, _queue, _mark_context, false); -} - class ShenandoahSTWMarkTask : public WorkerTask { private: ShenandoahSTWMark* const _mark; @@ -137,8 +109,9 @@ void ShenandoahSTWMark::mark() { } void ShenandoahSTWMark::mark_roots(uint worker_id) { - ShenandoahInitMarkRootsClosure init_mark(task_queues()->queue(worker_id)); - _root_scanner.roots_do(&init_mark, worker_id); + ShenandoahReferenceProcessor* rp = ShenandoahHeap::heap()->ref_processor(); + ShenandoahMarkRefsClosure cl(task_queues()->queue(worker_id), rp); + _root_scanner.roots_do(&cl, worker_id); } void ShenandoahSTWMark::finish_mark(uint worker_id) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp index c3e8108752fed..127e6324fb01e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "gc/shenandoah/shenandoahSimpleBitMap.hpp" +#include "gc/shenandoah/shenandoahSimpleBitMap.inline.hpp" ShenandoahSimpleBitMap::ShenandoahSimpleBitMap(size_t num_bits) : _num_bits(num_bits), @@ -43,8 +43,8 @@ size_t ShenandoahSimpleBitMap::count_leading_ones(idx_t start_idx) const { assert((start_idx >= 0) && (start_idx < _num_bits), "precondition"); size_t array_idx = start_idx >> LogBitsPerWord; uintx element_bits = _bitmap[array_idx]; - uintx bit_number = start_idx & right_n_bits(LogBitsPerWord); - uintx mask = ~right_n_bits(bit_number); + uintx bit_number = start_idx & (BitsPerWord - 1); + uintx mask = ~tail_mask(bit_number); size_t counted_ones = 0; while ((element_bits & mask) == mask) { // All bits numbered >= bit_number are set @@ -54,7 +54,7 @@ size_t ShenandoahSimpleBitMap::count_leading_ones(idx_t start_idx) const { // Strength reduction: array_idx = (start_idx >> LogBitsPerWord) array_idx++; element_bits = _bitmap[array_idx]; - // Constant folding: bit_number = start_idx & right_n_bits(LogBitsPerWord); + // Constant folding: bit_number = start_idx & (BitsPerWord - 1); bit_number = 0; // Constant folding: mask = ~right_n_bits(bit_number); mask = ~0; @@ -70,9 +70,9 @@ size_t ShenandoahSimpleBitMap::count_trailing_ones(idx_t last_idx) const { assert((last_idx >= 0) && (last_idx < _num_bits), "precondition"); size_t array_idx = last_idx >> LogBitsPerWord; uintx element_bits = _bitmap[array_idx]; - uintx bit_number = last_idx & right_n_bits(LogBitsPerWord); + uintx bit_number = last_idx & (BitsPerWord - 1); // All ones from bit 0 to the_bit - uintx mask = right_n_bits(bit_number + 1); + uintx mask = tail_mask(bit_number + 1); size_t counted_ones = 0; while ((element_bits & mask) == mask) { // All bits numbered <= bit_number are set @@ -81,7 +81,7 @@ size_t ShenandoahSimpleBitMap::count_trailing_ones(idx_t last_idx) const { // Dead code: do not need to compute: last_idx -= found_ones; array_idx--; element_bits = _bitmap[array_idx]; - // Constant folding: bit_number = last_idx & right_n_bits(LogBitsPerWord); + // Constant folding: bit_number = last_idx & (BitsPerWord - 1); bit_number = BitsPerWord - 1; // Constant folding: mask = right_n_bits(bit_number + 1); mask = ~0; @@ -99,7 +99,7 @@ bool ShenandoahSimpleBitMap::is_forward_consecutive_ones(idx_t start_idx, idx_t start_idx, count); assert(start_idx + count <= (idx_t) _num_bits, "precondition"); size_t array_idx = start_idx >> LogBitsPerWord; - uintx bit_number = start_idx & right_n_bits(LogBitsPerWord); + uintx bit_number = start_idx & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; uintx bits_to_examine = BitsPerWord - bit_number; element_bits >>= bit_number; @@ -128,7 +128,7 @@ bool ShenandoahSimpleBitMap::is_backward_consecutive_ones(idx_t last_idx, idx_t assert((last_idx >= 0) && (last_idx < _num_bits), "precondition"); assert(last_idx - count >= -1, "precondition"); size_t array_idx = last_idx >> LogBitsPerWord; - uintx bit_number = last_idx & right_n_bits(LogBitsPerWord); + uintx bit_number = last_idx & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; uintx bits_to_examine = bit_number + 1; element_bits <<= (BitsPerWord - bits_to_examine); @@ -161,10 +161,10 @@ idx_t ShenandoahSimpleBitMap::find_first_consecutive_set_bits(idx_t beg, idx_t e return end; } uintx array_idx = beg >> LogBitsPerWord; - uintx bit_number = beg & right_n_bits(LogBitsPerWord); + uintx bit_number = beg & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; if (bit_number > 0) { - uintx mask_out = right_n_bits(bit_number); + uintx mask_out = tail_mask(bit_number); element_bits &= ~mask_out; } @@ -222,9 +222,9 @@ idx_t ShenandoahSimpleBitMap::find_first_consecutive_set_bits(idx_t beg, idx_t e } array_idx = beg >> LogBitsPerWord; element_bits = _bitmap[array_idx]; - bit_number = beg & right_n_bits(LogBitsPerWord); + bit_number = beg & (BitsPerWord - 1); if (bit_number > 0) { - size_t mask_out = right_n_bits(bit_number); + size_t mask_out = tail_mask(bit_number); element_bits &= ~mask_out; } } @@ -242,10 +242,10 @@ idx_t ShenandoahSimpleBitMap::find_last_consecutive_set_bits(const idx_t beg, id } size_t array_idx = end >> LogBitsPerWord; - uintx bit_number = end & right_n_bits(LogBitsPerWord); + uintx bit_number = end & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; if (bit_number < BitsPerWord - 1) { - uintx mask_in = right_n_bits(bit_number + 1); + uintx mask_in = tail_mask(bit_number + 1); element_bits &= mask_in; } @@ -280,10 +280,10 @@ idx_t ShenandoahSimpleBitMap::find_last_consecutive_set_bits(const idx_t beg, id return beg; } array_idx = end >> LogBitsPerWord; - bit_number = end & right_n_bits(LogBitsPerWord); + bit_number = end & (BitsPerWord - 1); element_bits = _bitmap[array_idx]; if (bit_number < BitsPerWord - 1){ - size_t mask_in = right_n_bits(bit_number + 1); + size_t mask_in = tail_mask(bit_number + 1); element_bits &= mask_in; } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp index c22e952700204..55d21b06e4bbd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp @@ -50,7 +50,7 @@ typedef ssize_t idx_t; // ShenandoahSimpleBitMap resembles CHeapBitMap but adds missing support for find_first_consecutive_set_bits() and // find_last_consecutive_set_bits. An alternative refactoring of code would subclass CHeapBitMap, but this might // break abstraction rules, because efficient implementation requires assumptions about superclass internals that -// might be violatee through future software maintenance. +// might be violated through future software maintenance. class ShenandoahSimpleBitMap { const idx_t _num_bits; const size_t _num_words; @@ -80,11 +80,13 @@ class ShenandoahSimpleBitMap { bool is_forward_consecutive_ones(idx_t start_idx, idx_t count) const; bool is_backward_consecutive_ones(idx_t last_idx, idx_t count) const; + static inline uintx tail_mask(uintx bit_number); + public: inline idx_t aligned_index(idx_t idx) const { assert((idx >= 0) && (idx < _num_bits), "precondition"); - idx_t array_idx = idx & ~right_n_bits(LogBitsPerWord); + idx_t array_idx = idx & ~(BitsPerWord - 1); return array_idx; } @@ -107,7 +109,7 @@ class ShenandoahSimpleBitMap { inline void set_bit(idx_t idx) { assert((idx >= 0) && (idx < _num_bits), "precondition"); size_t array_idx = idx >> LogBitsPerWord; - uintx bit_number = idx & right_n_bits(LogBitsPerWord); + uintx bit_number = idx & (BitsPerWord - 1); uintx the_bit = nth_bit(bit_number); _bitmap[array_idx] |= the_bit; } @@ -116,7 +118,7 @@ class ShenandoahSimpleBitMap { assert((idx >= 0) && (idx < _num_bits), "precondition"); assert(idx >= 0, "precondition"); size_t array_idx = idx >> LogBitsPerWord; - uintx bit_number = idx & right_n_bits(LogBitsPerWord); + uintx bit_number = idx & (BitsPerWord - 1); uintx the_bit = nth_bit(bit_number); _bitmap[array_idx] &= ~the_bit; } @@ -125,9 +127,9 @@ class ShenandoahSimpleBitMap { assert((idx >= 0) && (idx < _num_bits), "precondition"); assert(idx >= 0, "precondition"); size_t array_idx = idx >> LogBitsPerWord; - uintx bit_number = idx & right_n_bits(LogBitsPerWord); + uintx bit_number = idx & (BitsPerWord - 1); uintx the_bit = nth_bit(bit_number); - return (_bitmap[array_idx] & the_bit)? true: false; + return (_bitmap[array_idx] & the_bit) != 0; } // Return the index of the first set bit in the range [beg, size()), or size() if none found. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp index 3e602ed11e0c0..4582ab9a781dd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp @@ -27,15 +27,22 @@ #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" +inline uintx ShenandoahSimpleBitMap::tail_mask(uintx bit_number) { + if (bit_number >= BitsPerWord) { + return -1; + } + return (uintx(1) << bit_number) - 1; +} + inline idx_t ShenandoahSimpleBitMap::find_first_set_bit(idx_t beg, idx_t end) const { assert((beg >= 0) && (beg < _num_bits), "precondition"); assert((end > beg) && (end <= _num_bits), "precondition"); do { size_t array_idx = beg >> LogBitsPerWord; - uintx bit_number = beg & right_n_bits(LogBitsPerWord); + uintx bit_number = beg & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; if (bit_number > 0) { - uintx mask_out = right_n_bits(bit_number); + uintx mask_out = tail_mask(bit_number); element_bits &= ~mask_out; } if (element_bits) { @@ -62,10 +69,10 @@ inline idx_t ShenandoahSimpleBitMap::find_last_set_bit(idx_t beg, idx_t end) con assert((beg >= -1) && (beg < end), "precondition"); do { idx_t array_idx = end >> LogBitsPerWord; - uintx bit_number = end & right_n_bits(LogBitsPerWord); + uint8_t bit_number = end & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; if (bit_number < BitsPerWord - 1){ - uintx mask_in = right_n_bits(bit_number + 1); + uintx mask_in = tail_mask(bit_number + 1); element_bits &= mask_in; } if (element_bits) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp index 9d2782502fefc..2dd6018ecd47a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp @@ -28,8 +28,6 @@ #include "gc/shenandoah/shenandoahDegeneratedGC.hpp" #include "gc/shenandoah/shenandoahFullGC.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahMark.inline.hpp" -#include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahVMOperations.hpp" #include "interpreter/oopMapCache.hpp" diff --git a/src/hotspot/share/gc/x/c1/xBarrierSetC1.cpp b/src/hotspot/share/gc/x/c1/xBarrierSetC1.cpp deleted file mode 100644 index 6f64392cefced..0000000000000 --- a/src/hotspot/share/gc/x/c1/xBarrierSetC1.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "c1/c1_LIR.hpp" -#include "c1/c1_LIRGenerator.hpp" -#include "c1/c1_CodeStubs.hpp" -#include "gc/x/c1/xBarrierSetC1.hpp" -#include "gc/x/xBarrierSet.hpp" -#include "gc/x/xBarrierSetAssembler.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "utilities/macros.hpp" - -XLoadBarrierStubC1::XLoadBarrierStubC1(LIRAccess& access, LIR_Opr ref, address runtime_stub) : - _decorators(access.decorators()), - _ref_addr(access.resolved_addr()), - _ref(ref), - _tmp(LIR_OprFact::illegalOpr), - _runtime_stub(runtime_stub) { - - assert(_ref_addr->is_address(), "Must be an address"); - assert(_ref->is_register(), "Must be a register"); - - // Allocate tmp register if needed - if (_ref_addr->as_address_ptr()->index()->is_valid() || - _ref_addr->as_address_ptr()->disp() != 0) { - // Has index or displacement, need tmp register to load address into - _tmp = access.gen()->new_pointer_register(); - } - - FrameMap* f = Compilation::current()->frame_map(); - f->update_reserved_argument_area_size(2 * BytesPerWord); -} - -DecoratorSet XLoadBarrierStubC1::decorators() const { - return _decorators; -} - -LIR_Opr XLoadBarrierStubC1::ref() const { - return _ref; -} - -LIR_Opr XLoadBarrierStubC1::ref_addr() const { - return _ref_addr; -} - -LIR_Opr XLoadBarrierStubC1::tmp() const { - return _tmp; -} - -address XLoadBarrierStubC1::runtime_stub() const { - return _runtime_stub; -} - -void XLoadBarrierStubC1::visit(LIR_OpVisitState* visitor) { - visitor->do_slow_case(); - visitor->do_input(_ref_addr); - visitor->do_output(_ref); - if (_tmp->is_valid()) { - visitor->do_temp(_tmp); - } -} - -void XLoadBarrierStubC1::emit_code(LIR_Assembler* ce) { - XBarrierSet::assembler()->generate_c1_load_barrier_stub(ce, this); -} - -#ifndef PRODUCT -void XLoadBarrierStubC1::print_name(outputStream* out) const { - out->print("XLoadBarrierStubC1"); -} -#endif // PRODUCT - -class LIR_OpXLoadBarrierTest : public LIR_Op { -private: - LIR_Opr _opr; - -public: - LIR_OpXLoadBarrierTest(LIR_Opr opr) : - LIR_Op(lir_xloadbarrier_test, LIR_OprFact::illegalOpr, nullptr), - _opr(opr) {} - - virtual void visit(LIR_OpVisitState* state) { - state->do_input(_opr); - } - - virtual void emit_code(LIR_Assembler* ce) { - XBarrierSet::assembler()->generate_c1_load_barrier_test(ce, _opr); - } - - virtual void print_instr(outputStream* out) const { - _opr->print(out); - out->print(" "); - } - -#ifndef PRODUCT - virtual const char* name() const { - return "lir_z_load_barrier_test"; - } -#endif // PRODUCT -}; - -static bool barrier_needed(LIRAccess& access) { - return XBarrierSet::barrier_needed(access.decorators(), access.type()); -} - -XBarrierSetC1::XBarrierSetC1() : - _load_barrier_on_oop_field_preloaded_runtime_stub(nullptr), - _load_barrier_on_weak_oop_field_preloaded_runtime_stub(nullptr) {} - -address XBarrierSetC1::load_barrier_on_oop_field_preloaded_runtime_stub(DecoratorSet decorators) const { - assert((decorators & ON_PHANTOM_OOP_REF) == 0, "Unsupported decorator"); - //assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Unsupported decorator"); - - if ((decorators & ON_WEAK_OOP_REF) != 0) { - return _load_barrier_on_weak_oop_field_preloaded_runtime_stub; - } else { - return _load_barrier_on_oop_field_preloaded_runtime_stub; - } -} - -#ifdef ASSERT -#define __ access.gen()->lir(__FILE__, __LINE__)-> -#else -#define __ access.gen()->lir()-> -#endif - -void XBarrierSetC1::load_barrier(LIRAccess& access, LIR_Opr result) const { - // Fast path - __ append(new LIR_OpXLoadBarrierTest(result)); - - // Slow path - const address runtime_stub = load_barrier_on_oop_field_preloaded_runtime_stub(access.decorators()); - CodeStub* const stub = new XLoadBarrierStubC1(access, result, runtime_stub); - __ branch(lir_cond_notEqual, stub); - __ branch_destination(stub->continuation()); -} - -LIR_Opr XBarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) { - // We must resolve in register when patching. This is to avoid - // having a patch area in the load barrier stub, since the call - // into the runtime to patch will not have the proper oop map. - const bool patch_before_barrier = barrier_needed(access) && (access.decorators() & C1_NEEDS_PATCHING) != 0; - return BarrierSetC1::resolve_address(access, resolve_in_register || patch_before_barrier); -} - -#undef __ - -void XBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { - BarrierSetC1::load_at_resolved(access, result); - - if (barrier_needed(access)) { - load_barrier(access, result); - } -} - -static void pre_load_barrier(LIRAccess& access) { - DecoratorSet decorators = access.decorators(); - - // Downgrade access to MO_UNORDERED - decorators = (decorators & ~MO_DECORATOR_MASK) | MO_UNORDERED; - - // Remove ACCESS_WRITE - decorators = (decorators & ~ACCESS_WRITE); - - // Generate synthetic load at - access.gen()->access_load_at(decorators, - access.type(), - access.base().item(), - access.offset().opr(), - access.gen()->new_register(access.type()), - nullptr /* patch_emit_info */, - nullptr /* load_emit_info */); -} - -LIR_Opr XBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value) { - if (barrier_needed(access)) { - pre_load_barrier(access); - } - - return BarrierSetC1::atomic_xchg_at_resolved(access, value); -} - -LIR_Opr XBarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) { - if (barrier_needed(access)) { - pre_load_barrier(access); - } - - return BarrierSetC1::atomic_cmpxchg_at_resolved(access, cmp_value, new_value); -} - -class XLoadBarrierRuntimeStubCodeGenClosure : public StubAssemblerCodeGenClosure { -private: - const DecoratorSet _decorators; - -public: - XLoadBarrierRuntimeStubCodeGenClosure(DecoratorSet decorators) : - _decorators(decorators) {} - - virtual OopMapSet* generate_code(StubAssembler* sasm) { - XBarrierSet::assembler()->generate_c1_load_barrier_runtime_stub(sasm, _decorators); - return nullptr; - } -}; - -static address generate_c1_runtime_stub(BufferBlob* blob, DecoratorSet decorators, const char* name) { - XLoadBarrierRuntimeStubCodeGenClosure cl(decorators); - CodeBlob* const code_blob = Runtime1::generate_blob(blob, C1StubId::NO_STUBID /* stub_id */, name, false /* expect_oop_map*/, &cl); - return code_blob->code_begin(); -} - -void XBarrierSetC1::generate_c1_runtime_stubs(BufferBlob* blob) { - _load_barrier_on_oop_field_preloaded_runtime_stub = - generate_c1_runtime_stub(blob, ON_STRONG_OOP_REF, "load_barrier_on_oop_field_preloaded_runtime_stub"); - _load_barrier_on_weak_oop_field_preloaded_runtime_stub = - generate_c1_runtime_stub(blob, ON_WEAK_OOP_REF, "load_barrier_on_weak_oop_field_preloaded_runtime_stub"); -} diff --git a/src/hotspot/share/gc/x/c1/xBarrierSetC1.hpp b/src/hotspot/share/gc/x/c1/xBarrierSetC1.hpp deleted file mode 100644 index 26c2e142cdf80..0000000000000 --- a/src/hotspot/share/gc/x/c1/xBarrierSetC1.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * 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_GC_X_C1_XBARRIERSETC1_HPP -#define SHARE_GC_X_C1_XBARRIERSETC1_HPP - -#include "c1/c1_CodeStubs.hpp" -#include "c1/c1_IR.hpp" -#include "c1/c1_LIR.hpp" -#include "gc/shared/c1/barrierSetC1.hpp" -#include "oops/accessDecorators.hpp" - -class XLoadBarrierStubC1 : public CodeStub { -private: - DecoratorSet _decorators; - LIR_Opr _ref_addr; - LIR_Opr _ref; - LIR_Opr _tmp; - address _runtime_stub; - -public: - XLoadBarrierStubC1(LIRAccess& access, LIR_Opr ref, address runtime_stub); - - DecoratorSet decorators() const; - LIR_Opr ref() const; - LIR_Opr ref_addr() const; - LIR_Opr tmp() const; - address runtime_stub() const; - - virtual void emit_code(LIR_Assembler* ce); - virtual void visit(LIR_OpVisitState* visitor); - -#ifndef PRODUCT - virtual void print_name(outputStream* out) const; -#endif // PRODUCT -}; - -class XBarrierSetC1 : public BarrierSetC1 { -private: - address _load_barrier_on_oop_field_preloaded_runtime_stub; - address _load_barrier_on_weak_oop_field_preloaded_runtime_stub; - - address load_barrier_on_oop_field_preloaded_runtime_stub(DecoratorSet decorators) const; - void load_barrier(LIRAccess& access, LIR_Opr result) const; - -protected: - virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register); - virtual void load_at_resolved(LIRAccess& access, LIR_Opr result); - virtual LIR_Opr atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value); - virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value); - -public: - XBarrierSetC1(); - - virtual void generate_c1_runtime_stubs(BufferBlob* blob); -}; - -#endif // SHARE_GC_X_C1_XBARRIERSETC1_HPP diff --git a/src/hotspot/share/gc/x/c2/xBarrierSetC2.cpp b/src/hotspot/share/gc/x/c2/xBarrierSetC2.cpp deleted file mode 100644 index d006b37e7d208..0000000000000 --- a/src/hotspot/share/gc/x/c2/xBarrierSetC2.cpp +++ /dev/null @@ -1,583 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "classfile/javaClasses.hpp" -#include "gc/x/c2/xBarrierSetC2.hpp" -#include "gc/x/xBarrierSet.hpp" -#include "gc/x/xBarrierSetAssembler.hpp" -#include "gc/x/xBarrierSetRuntime.hpp" -#include "opto/arraycopynode.hpp" -#include "opto/addnode.hpp" -#include "opto/block.hpp" -#include "opto/compile.hpp" -#include "opto/graphKit.hpp" -#include "opto/machnode.hpp" -#include "opto/macro.hpp" -#include "opto/memnode.hpp" -#include "opto/node.hpp" -#include "opto/output.hpp" -#include "opto/regalloc.hpp" -#include "opto/rootnode.hpp" -#include "opto/runtime.hpp" -#include "opto/type.hpp" -#include "utilities/growableArray.hpp" -#include "utilities/macros.hpp" - -class XBarrierSetC2State : public ArenaObj { -private: - GrowableArray* _stubs; - Node_Array _live; - -public: - XBarrierSetC2State(Arena* arena) : - _stubs(new (arena) GrowableArray(arena, 8, 0, nullptr)), - _live(arena) {} - - GrowableArray* stubs() { - return _stubs; - } - - RegMask* live(const Node* node) { - if (!node->is_Mach()) { - // Don't need liveness for non-MachNodes - return nullptr; - } - - const MachNode* const mach = node->as_Mach(); - if (mach->barrier_data() == XLoadBarrierElided) { - // Don't need liveness data for nodes without barriers - return nullptr; - } - - RegMask* live = (RegMask*)_live[node->_idx]; - if (live == nullptr) { - live = new (Compile::current()->comp_arena()->AmallocWords(sizeof(RegMask))) RegMask(); - _live.map(node->_idx, (Node*)live); - } - - return live; - } -}; - -static XBarrierSetC2State* barrier_set_state() { - return reinterpret_cast(Compile::current()->barrier_set_state()); -} - -XLoadBarrierStubC2* XLoadBarrierStubC2::create(const MachNode* node, Address ref_addr, Register ref, Register tmp, uint8_t barrier_data) { - XLoadBarrierStubC2* const stub = new (Compile::current()->comp_arena()) XLoadBarrierStubC2(node, ref_addr, ref, tmp, barrier_data); - if (!Compile::current()->output()->in_scratch_emit_size()) { - barrier_set_state()->stubs()->append(stub); - } - - return stub; -} - -XLoadBarrierStubC2::XLoadBarrierStubC2(const MachNode* node, Address ref_addr, Register ref, Register tmp, uint8_t barrier_data) : - _node(node), - _ref_addr(ref_addr), - _ref(ref), - _tmp(tmp), - _barrier_data(barrier_data), - _entry(), - _continuation() { - assert_different_registers(ref, ref_addr.base()); - assert_different_registers(ref, ref_addr.index()); -} - -Address XLoadBarrierStubC2::ref_addr() const { - return _ref_addr; -} - -Register XLoadBarrierStubC2::ref() const { - return _ref; -} - -Register XLoadBarrierStubC2::tmp() const { - return _tmp; -} - -address XLoadBarrierStubC2::slow_path() const { - DecoratorSet decorators = DECORATORS_NONE; - if (_barrier_data & XLoadBarrierStrong) { - decorators |= ON_STRONG_OOP_REF; - } - if (_barrier_data & XLoadBarrierWeak) { - decorators |= ON_WEAK_OOP_REF; - } - if (_barrier_data & XLoadBarrierPhantom) { - decorators |= ON_PHANTOM_OOP_REF; - } - if (_barrier_data & XLoadBarrierNoKeepalive) { - decorators |= AS_NO_KEEPALIVE; - } - return XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators); -} - -RegMask& XLoadBarrierStubC2::live() const { - RegMask* mask = barrier_set_state()->live(_node); - assert(mask != nullptr, "must be mach-node with barrier"); - return *mask; -} - -Label* XLoadBarrierStubC2::entry() { - // The _entry will never be bound when in_scratch_emit_size() is true. - // However, we still need to return a label that is not bound now, but - // will eventually be bound. Any label will do, as it will only act as - // a placeholder, so we return the _continuation label. - return Compile::current()->output()->in_scratch_emit_size() ? &_continuation : &_entry; -} - -Label* XLoadBarrierStubC2::continuation() { - return &_continuation; -} - -void* XBarrierSetC2::create_barrier_state(Arena* comp_arena) const { - return new (comp_arena) XBarrierSetC2State(comp_arena); -} - -void XBarrierSetC2::late_barrier_analysis() const { - analyze_dominating_barriers(); - compute_liveness_at_stubs(); -} - -void XBarrierSetC2::emit_stubs(CodeBuffer& cb) const { - MacroAssembler masm(&cb); - GrowableArray* const stubs = barrier_set_state()->stubs(); - - for (int i = 0; i < stubs->length(); i++) { - // Make sure there is enough space in the code buffer - if (cb.insts()->maybe_expand_to_ensure_remaining(PhaseOutput::MAX_inst_size) && cb.blob() == nullptr) { - ciEnv::current()->record_failure("CodeCache is full"); - return; - } - - XBarrierSet::assembler()->generate_c2_load_barrier_stub(&masm, stubs->at(i)); - } - - masm.flush(); -} - -int XBarrierSetC2::estimate_stub_size() const { - Compile* const C = Compile::current(); - BufferBlob* const blob = C->output()->scratch_buffer_blob(); - GrowableArray* const stubs = barrier_set_state()->stubs(); - int size = 0; - - for (int i = 0; i < stubs->length(); i++) { - CodeBuffer cb(blob->content_begin(), (address)C->output()->scratch_locs_memory() - blob->content_begin()); - MacroAssembler masm(&cb); - XBarrierSet::assembler()->generate_c2_load_barrier_stub(&masm, stubs->at(i)); - size += cb.insts_size(); - } - - return size; -} - -static void set_barrier_data(C2Access& access) { - if (XBarrierSet::barrier_needed(access.decorators(), access.type())) { - uint8_t barrier_data = 0; - - if (access.decorators() & ON_PHANTOM_OOP_REF) { - barrier_data |= XLoadBarrierPhantom; - } else if (access.decorators() & ON_WEAK_OOP_REF) { - barrier_data |= XLoadBarrierWeak; - } else { - barrier_data |= XLoadBarrierStrong; - } - - if (access.decorators() & AS_NO_KEEPALIVE) { - barrier_data |= XLoadBarrierNoKeepalive; - } - - access.set_barrier_data(barrier_data); - } -} - -Node* XBarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const { - set_barrier_data(access); - return BarrierSetC2::load_at_resolved(access, val_type); -} - -Node* XBarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val, - Node* new_val, const Type* val_type) const { - set_barrier_data(access); - return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, val_type); -} - -Node* XBarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val, - Node* new_val, const Type* value_type) const { - set_barrier_data(access); - return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type); -} - -Node* XBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* val_type) const { - set_barrier_data(access); - return BarrierSetC2::atomic_xchg_at_resolved(access, new_val, val_type); -} - -bool XBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, - bool is_clone, bool is_clone_instance, - ArrayCopyPhase phase) const { - if (phase == ArrayCopyPhase::Parsing) { - return false; - } - if (phase == ArrayCopyPhase::Optimization) { - return is_clone_instance; - } - // else ArrayCopyPhase::Expansion - return type == T_OBJECT || type == T_ARRAY; -} - -// This TypeFunc assumes a 64bit system -static const TypeFunc* clone_type() { - // Create input type (domain) - const Type** domain_fields = TypeTuple::fields(4); - domain_fields[TypeFunc::Parms + 0] = TypeInstPtr::NOTNULL; // src - domain_fields[TypeFunc::Parms + 1] = TypeInstPtr::NOTNULL; // dst - domain_fields[TypeFunc::Parms + 2] = TypeLong::LONG; // size lower - domain_fields[TypeFunc::Parms + 3] = Type::HALF; // size upper - const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + 4, domain_fields); - - // Create result type (range) - const Type** range_fields = TypeTuple::fields(0); - const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 0, range_fields); - - return TypeFunc::make(domain, range); -} - -#define XTOP LP64_ONLY(COMMA phase->top()) - -void XBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const { - Node* const src = ac->in(ArrayCopyNode::Src); - const TypeAryPtr* ary_ptr = src->get_ptr_type()->isa_aryptr(); - - if (ac->is_clone_array() && ary_ptr != nullptr) { - BasicType bt = ary_ptr->elem()->array_element_basic_type(); - if (is_reference_type(bt)) { - // Clone object array - bt = T_OBJECT; - } else { - // Clone primitive array - bt = T_LONG; - } - - Node* ctrl = ac->in(TypeFunc::Control); - Node* mem = ac->in(TypeFunc::Memory); - Node* src = ac->in(ArrayCopyNode::Src); - Node* src_offset = ac->in(ArrayCopyNode::SrcPos); - Node* dest = ac->in(ArrayCopyNode::Dest); - Node* dest_offset = ac->in(ArrayCopyNode::DestPos); - Node* length = ac->in(ArrayCopyNode::Length); - - if (bt == T_OBJECT) { - // BarrierSetC2::clone sets the offsets via BarrierSetC2::arraycopy_payload_base_offset - // which 8-byte aligns them to allow for word size copies. Make sure the offsets point - // to the first element in the array when cloning object arrays. Otherwise, load - // barriers are applied to parts of the header. Also adjust the length accordingly. - assert(src_offset == dest_offset, "should be equal"); - jlong offset = src_offset->get_long(); - if (offset != arrayOopDesc::base_offset_in_bytes(T_OBJECT)) { - assert(!UseCompressedClassPointers, "should only happen without compressed class pointers"); - assert((arrayOopDesc::base_offset_in_bytes(T_OBJECT) - offset) == BytesPerLong, "unexpected offset"); - length = phase->transform_later(new SubLNode(length, phase->longcon(1))); // Size is in longs - src_offset = phase->longcon(arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - dest_offset = src_offset; - } - } - Node* payload_src = phase->basic_plus_adr(src, src_offset); - Node* payload_dst = phase->basic_plus_adr(dest, dest_offset); - - const char* copyfunc_name = "arraycopy"; - address copyfunc_addr = phase->basictype2arraycopy(bt, nullptr, nullptr, true, copyfunc_name, true); - - const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM; - const TypeFunc* call_type = OptoRuntime::fast_arraycopy_Type(); - - Node* call = phase->make_leaf_call(ctrl, mem, call_type, copyfunc_addr, copyfunc_name, raw_adr_type, payload_src, payload_dst, length XTOP); - phase->transform_later(call); - - phase->igvn().replace_node(ac, call); - return; - } - - // Clone instance - Node* const ctrl = ac->in(TypeFunc::Control); - Node* const mem = ac->in(TypeFunc::Memory); - Node* const dst = ac->in(ArrayCopyNode::Dest); - Node* const size = ac->in(ArrayCopyNode::Length); - - assert(size->bottom_type()->is_long(), "Should be long"); - - // The native clone we are calling here expects the instance size in words - // Add header/offset size to payload size to get instance size. - Node* const base_offset = phase->longcon(arraycopy_payload_base_offset(ac->is_clone_array()) >> LogBytesPerLong); - Node* const full_size = phase->transform_later(new AddLNode(size, base_offset)); - - Node* const call = phase->make_leaf_call(ctrl, - mem, - clone_type(), - XBarrierSetRuntime::clone_addr(), - "XBarrierSetRuntime::clone", - TypeRawPtr::BOTTOM, - src, - dst, - full_size, - phase->top()); - phase->transform_later(call); - phase->igvn().replace_node(ac, call); -} - -#undef XTOP - -// == Dominating barrier elision == - -static bool block_has_safepoint(const Block* block, uint from, uint to) { - for (uint i = from; i < to; i++) { - if (block->get_node(i)->is_MachSafePoint()) { - // Safepoint found - return true; - } - } - - // Safepoint not found - return false; -} - -static bool block_has_safepoint(const Block* block) { - return block_has_safepoint(block, 0, block->number_of_nodes()); -} - -static uint block_index(const Block* block, const Node* node) { - for (uint j = 0; j < block->number_of_nodes(); ++j) { - if (block->get_node(j) == node) { - return j; - } - } - ShouldNotReachHere(); - return 0; -} - -void XBarrierSetC2::analyze_dominating_barriers() const { - ResourceMark rm; - Compile* const C = Compile::current(); - PhaseCFG* const cfg = C->cfg(); - Block_List worklist; - Node_List mem_ops; - Node_List barrier_loads; - - // Step 1 - Find accesses, and track them in lists - for (uint i = 0; i < cfg->number_of_blocks(); ++i) { - const Block* const block = cfg->get_block(i); - for (uint j = 0; j < block->number_of_nodes(); ++j) { - const Node* const node = block->get_node(j); - if (!node->is_Mach()) { - continue; - } - - MachNode* const mach = node->as_Mach(); - switch (mach->ideal_Opcode()) { - case Op_LoadP: - if ((mach->barrier_data() & XLoadBarrierStrong) != 0) { - barrier_loads.push(mach); - } - if ((mach->barrier_data() & (XLoadBarrierStrong | XLoadBarrierNoKeepalive)) == - XLoadBarrierStrong) { - mem_ops.push(mach); - } - break; - case Op_CompareAndExchangeP: - case Op_CompareAndSwapP: - case Op_GetAndSetP: - if ((mach->barrier_data() & XLoadBarrierStrong) != 0) { - barrier_loads.push(mach); - } - case Op_StoreP: - mem_ops.push(mach); - break; - - default: - break; - } - } - } - - // Step 2 - Find dominating accesses for each load - for (uint i = 0; i < barrier_loads.size(); i++) { - MachNode* const load = barrier_loads.at(i)->as_Mach(); - const TypePtr* load_adr_type = nullptr; - intptr_t load_offset = 0; - const Node* const load_obj = load->get_base_and_disp(load_offset, load_adr_type); - Block* const load_block = cfg->get_block_for_node(load); - const uint load_index = block_index(load_block, load); - - for (uint j = 0; j < mem_ops.size(); j++) { - MachNode* mem = mem_ops.at(j)->as_Mach(); - const TypePtr* mem_adr_type = nullptr; - intptr_t mem_offset = 0; - const Node* mem_obj = mem->get_base_and_disp(mem_offset, mem_adr_type); - Block* mem_block = cfg->get_block_for_node(mem); - uint mem_index = block_index(mem_block, mem); - - if (load_obj == NodeSentinel || mem_obj == NodeSentinel || - load_obj == nullptr || mem_obj == nullptr || - load_offset < 0 || mem_offset < 0) { - continue; - } - - if (mem_obj != load_obj || mem_offset != load_offset) { - // Not the same addresses, not a candidate - continue; - } - - if (load_block == mem_block) { - // Earlier accesses in the same block - if (mem_index < load_index && !block_has_safepoint(mem_block, mem_index + 1, load_index)) { - load->set_barrier_data(XLoadBarrierElided); - } - } else if (mem_block->dominates(load_block)) { - // Dominating block? Look around for safepoints - ResourceMark rm; - Block_List stack; - VectorSet visited; - stack.push(load_block); - bool safepoint_found = block_has_safepoint(load_block); - while (!safepoint_found && stack.size() > 0) { - Block* block = stack.pop(); - if (visited.test_set(block->_pre_order)) { - continue; - } - if (block_has_safepoint(block)) { - safepoint_found = true; - break; - } - if (block == mem_block) { - continue; - } - - // Push predecessor blocks - for (uint p = 1; p < block->num_preds(); ++p) { - Block* pred = cfg->get_block_for_node(block->pred(p)); - stack.push(pred); - } - } - - if (!safepoint_found) { - load->set_barrier_data(XLoadBarrierElided); - } - } - } - } -} - -// == Reduced spilling optimization == - -void XBarrierSetC2::compute_liveness_at_stubs() const { - ResourceMark rm; - Compile* const C = Compile::current(); - Arena* const A = Thread::current()->resource_area(); - PhaseCFG* const cfg = C->cfg(); - PhaseRegAlloc* const regalloc = C->regalloc(); - RegMask* const live = NEW_ARENA_ARRAY(A, RegMask, cfg->number_of_blocks() * sizeof(RegMask)); - XBarrierSetAssembler* const bs = XBarrierSet::assembler(); - Block_List worklist; - - for (uint i = 0; i < cfg->number_of_blocks(); ++i) { - new ((void*)(live + i)) RegMask(); - worklist.push(cfg->get_block(i)); - } - - while (worklist.size() > 0) { - const Block* const block = worklist.pop(); - RegMask& old_live = live[block->_pre_order]; - RegMask new_live; - - // Initialize to union of successors - for (uint i = 0; i < block->_num_succs; i++) { - const uint succ_id = block->_succs[i]->_pre_order; - new_live.OR(live[succ_id]); - } - - // Walk block backwards, computing liveness - for (int i = block->number_of_nodes() - 1; i >= 0; --i) { - const Node* const node = block->get_node(i); - - // Remove def bits - const OptoReg::Name first = bs->refine_register(node, regalloc->get_reg_first(node)); - const OptoReg::Name second = bs->refine_register(node, regalloc->get_reg_second(node)); - if (first != OptoReg::Bad) { - new_live.Remove(first); - } - if (second != OptoReg::Bad) { - new_live.Remove(second); - } - - // Add use bits - for (uint j = 1; j < node->req(); ++j) { - const Node* const use = node->in(j); - const OptoReg::Name first = bs->refine_register(use, regalloc->get_reg_first(use)); - const OptoReg::Name second = bs->refine_register(use, regalloc->get_reg_second(use)); - if (first != OptoReg::Bad) { - new_live.Insert(first); - } - if (second != OptoReg::Bad) { - new_live.Insert(second); - } - } - - // If this node tracks liveness, update it - RegMask* const regs = barrier_set_state()->live(node); - if (regs != nullptr) { - regs->OR(new_live); - } - } - - // Now at block top, see if we have any changes - new_live.SUBTRACT(old_live); - if (new_live.is_NotEmpty()) { - // Liveness has refined, update and propagate to prior blocks - old_live.OR(new_live); - for (uint i = 1; i < block->num_preds(); ++i) { - Block* const pred = cfg->get_block_for_node(block->pred(i)); - worklist.push(pred); - } - } - } -} - -#ifndef PRODUCT -void XBarrierSetC2::dump_barrier_data(const MachNode* mach, outputStream* st) const { - if ((mach->barrier_data() & XLoadBarrierStrong) != 0) { - st->print("strong "); - } - if ((mach->barrier_data() & XLoadBarrierWeak) != 0) { - st->print("weak "); - } - if ((mach->barrier_data() & XLoadBarrierPhantom) != 0) { - st->print("phantom "); - } - if ((mach->barrier_data() & XLoadBarrierNoKeepalive) != 0) { - st->print("nokeepalive "); - } -} -#endif // !PRODUCT diff --git a/src/hotspot/share/gc/x/c2/xBarrierSetC2.hpp b/src/hotspot/share/gc/x/c2/xBarrierSetC2.hpp deleted file mode 100644 index 91835338fd73c..0000000000000 --- a/src/hotspot/share/gc/x/c2/xBarrierSetC2.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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 - * 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_GC_X_C2_XBARRIERSETC2_HPP -#define SHARE_GC_X_C2_XBARRIERSETC2_HPP - -#include "gc/shared/c2/barrierSetC2.hpp" -#include "memory/allocation.hpp" -#include "opto/node.hpp" -#include "utilities/growableArray.hpp" - -const uint8_t XLoadBarrierElided = 0; -const uint8_t XLoadBarrierStrong = 1; -const uint8_t XLoadBarrierWeak = 2; -const uint8_t XLoadBarrierPhantom = 4; -const uint8_t XLoadBarrierNoKeepalive = 8; - -class XLoadBarrierStubC2 : public ArenaObj { -private: - const MachNode* _node; - const Address _ref_addr; - const Register _ref; - const Register _tmp; - const uint8_t _barrier_data; - Label _entry; - Label _continuation; - - XLoadBarrierStubC2(const MachNode* node, Address ref_addr, Register ref, Register tmp, uint8_t barrier_data); - -public: - static XLoadBarrierStubC2* create(const MachNode* node, Address ref_addr, Register ref, Register tmp, uint8_t barrier_data); - - Address ref_addr() const; - Register ref() const; - Register tmp() const; - address slow_path() const; - RegMask& live() const; - Label* entry(); - Label* continuation(); -}; - -class XBarrierSetC2 : public BarrierSetC2 { -private: - void compute_liveness_at_stubs() const; - void analyze_dominating_barriers() const; - -protected: - virtual Node* load_at_resolved(C2Access& access, const Type* val_type) const; - virtual Node* atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, - Node* expected_val, - Node* new_val, - const Type* val_type) const; - virtual Node* atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, - Node* expected_val, - Node* new_val, - const Type* value_type) const; - virtual Node* atomic_xchg_at_resolved(C2AtomicParseAccess& access, - Node* new_val, - const Type* val_type) const; - -public: - virtual void* create_barrier_state(Arena* comp_arena) const; - virtual bool array_copy_requires_gc_barriers(bool tightly_coupled_alloc, - BasicType type, - bool is_clone, - bool is_clone_instance, - ArrayCopyPhase phase) const; - virtual void clone_at_expansion(PhaseMacroExpand* phase, - ArrayCopyNode* ac) const; - - virtual void late_barrier_analysis() const; - virtual int estimate_stub_size() const; - virtual void emit_stubs(CodeBuffer& cb) const; - -#ifndef PRODUCT - virtual void dump_barrier_data(const MachNode* mach, outputStream* st) const; -#endif -}; - -#endif // SHARE_GC_X_C2_XBARRIERSETC2_HPP diff --git a/src/hotspot/share/gc/x/vmStructs_x.cpp b/src/hotspot/share/gc/x/vmStructs_x.cpp deleted file mode 100644 index 4c7d63f41b403..0000000000000 --- a/src/hotspot/share/gc/x/vmStructs_x.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/vmStructs_x.hpp" - -XGlobalsForVMStructs::XGlobalsForVMStructs() : - _XGlobalPhase(&XGlobalPhase), - _XGlobalSeqNum(&XGlobalSeqNum), - _XAddressOffsetMask(&XAddressOffsetMask), - _XAddressMetadataMask(&XAddressMetadataMask), - _XAddressMetadataFinalizable(&XAddressMetadataFinalizable), - _XAddressGoodMask(&XAddressGoodMask), - _XAddressBadMask(&XAddressBadMask), - _XAddressWeakBadMask(&XAddressWeakBadMask), - _XObjectAlignmentSmallShift(&XObjectAlignmentSmallShift), - _XObjectAlignmentSmall(&XObjectAlignmentSmall) { -} - -XGlobalsForVMStructs XGlobalsForVMStructs::_instance; -XGlobalsForVMStructs* XGlobalsForVMStructs::_instance_p = &XGlobalsForVMStructs::_instance; diff --git a/src/hotspot/share/gc/x/vmStructs_x.hpp b/src/hotspot/share/gc/x/vmStructs_x.hpp deleted file mode 100644 index b911c21be2343..0000000000000 --- a/src/hotspot/share/gc/x/vmStructs_x.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_VMSTRUCTS_X_HPP -#define SHARE_GC_X_VMSTRUCTS_X_HPP - -#include "gc/x/xAttachedArray.hpp" -#include "gc/x/xCollectedHeap.hpp" -#include "gc/x/xForwarding.hpp" -#include "gc/x/xGranuleMap.hpp" -#include "gc/x/xHeap.hpp" -#include "gc/x/xPageAllocator.hpp" -#include "utilities/macros.hpp" - -// Expose some ZGC globals to the SA agent. -class XGlobalsForVMStructs { - static XGlobalsForVMStructs _instance; - -public: - static XGlobalsForVMStructs* _instance_p; - - XGlobalsForVMStructs(); - - uint32_t* _XGlobalPhase; - - uint32_t* _XGlobalSeqNum; - - uintptr_t* _XAddressOffsetMask; - uintptr_t* _XAddressMetadataMask; - uintptr_t* _XAddressMetadataFinalizable; - uintptr_t* _XAddressGoodMask; - uintptr_t* _XAddressBadMask; - uintptr_t* _XAddressWeakBadMask; - - const int* _XObjectAlignmentSmallShift; - const int* _XObjectAlignmentSmall; -}; - -typedef XGranuleMap XGranuleMapForPageTable; -typedef XGranuleMap XGranuleMapForForwarding; -typedef XAttachedArray XAttachedArrayForForwarding; - -#define VM_STRUCTS_X(nonstatic_field, volatile_nonstatic_field, static_field) \ - static_field(XGlobalsForVMStructs, _instance_p, XGlobalsForVMStructs*) \ - nonstatic_field(XGlobalsForVMStructs, _XGlobalPhase, uint32_t*) \ - nonstatic_field(XGlobalsForVMStructs, _XGlobalSeqNum, uint32_t*) \ - nonstatic_field(XGlobalsForVMStructs, _XAddressOffsetMask, uintptr_t*) \ - nonstatic_field(XGlobalsForVMStructs, _XAddressMetadataMask, uintptr_t*) \ - nonstatic_field(XGlobalsForVMStructs, _XAddressMetadataFinalizable, uintptr_t*) \ - nonstatic_field(XGlobalsForVMStructs, _XAddressGoodMask, uintptr_t*) \ - nonstatic_field(XGlobalsForVMStructs, _XAddressBadMask, uintptr_t*) \ - nonstatic_field(XGlobalsForVMStructs, _XAddressWeakBadMask, uintptr_t*) \ - nonstatic_field(XGlobalsForVMStructs, _XObjectAlignmentSmallShift, const int*) \ - nonstatic_field(XGlobalsForVMStructs, _XObjectAlignmentSmall, const int*) \ - \ - nonstatic_field(XCollectedHeap, _heap, XHeap) \ - \ - nonstatic_field(XHeap, _page_allocator, XPageAllocator) \ - nonstatic_field(XHeap, _page_table, XPageTable) \ - nonstatic_field(XHeap, _forwarding_table, XForwardingTable) \ - nonstatic_field(XHeap, _relocate, XRelocate) \ - \ - nonstatic_field(XPage, _type, const uint8_t) \ - nonstatic_field(XPage, _seqnum, uint32_t) \ - nonstatic_field(XPage, _virtual, const XVirtualMemory) \ - volatile_nonstatic_field(XPage, _top, uintptr_t) \ - \ - nonstatic_field(XPageAllocator, _max_capacity, const size_t) \ - volatile_nonstatic_field(XPageAllocator, _capacity, size_t) \ - volatile_nonstatic_field(XPageAllocator, _used, size_t) \ - \ - nonstatic_field(XPageTable, _map, XGranuleMapForPageTable) \ - \ - nonstatic_field(XGranuleMapForPageTable, _map, XPage** const) \ - nonstatic_field(XGranuleMapForForwarding, _map, XForwarding** const) \ - \ - nonstatic_field(XForwardingTable, _map, XGranuleMapForForwarding) \ - \ - nonstatic_field(XVirtualMemory, _start, const uintptr_t) \ - nonstatic_field(XVirtualMemory, _end, const uintptr_t) \ - \ - nonstatic_field(XForwarding, _virtual, const XVirtualMemory) \ - nonstatic_field(XForwarding, _object_alignment_shift, const size_t) \ - volatile_nonstatic_field(XForwarding, _ref_count, int) \ - nonstatic_field(XForwarding, _entries, const XAttachedArrayForForwarding) \ - nonstatic_field(XForwardingEntry, _entry, uint64_t) \ - nonstatic_field(XAttachedArrayForForwarding, _length, const size_t) - -#define VM_INT_CONSTANTS_X(declare_constant, declare_constant_with_value) \ - declare_constant(XPhaseRelocate) \ - declare_constant(XPageTypeSmall) \ - declare_constant(XPageTypeMedium) \ - declare_constant(XPageTypeLarge) \ - declare_constant(XObjectAlignmentMediumShift) \ - declare_constant(XObjectAlignmentLargeShift) - -#define VM_LONG_CONSTANTS_X(declare_constant) \ - declare_constant(XGranuleSizeShift) \ - declare_constant(XPageSizeSmallShift) \ - declare_constant(XPageSizeMediumShift) \ - declare_constant(XAddressOffsetShift) \ - declare_constant(XAddressOffsetBits) \ - declare_constant(XAddressOffsetMask) \ - declare_constant(XAddressOffsetMax) - -#define VM_TYPES_X(declare_type, declare_toplevel_type, declare_integer_type) \ - declare_toplevel_type(XGlobalsForVMStructs) \ - declare_type(XCollectedHeap, CollectedHeap) \ - declare_toplevel_type(XHeap) \ - declare_toplevel_type(XRelocate) \ - declare_toplevel_type(XPage) \ - declare_toplevel_type(XPageAllocator) \ - declare_toplevel_type(XPageTable) \ - declare_toplevel_type(XAttachedArrayForForwarding) \ - declare_toplevel_type(XGranuleMapForPageTable) \ - declare_toplevel_type(XGranuleMapForForwarding) \ - declare_toplevel_type(XVirtualMemory) \ - declare_toplevel_type(XForwardingTable) \ - declare_toplevel_type(XForwarding) \ - declare_toplevel_type(XForwardingEntry) \ - declare_toplevel_type(XPhysicalMemoryManager) - -#endif // SHARE_GC_X_VMSTRUCTS_X_HPP diff --git a/src/hotspot/share/gc/x/xAbort.cpp b/src/hotspot/share/gc/x/xAbort.cpp deleted file mode 100644 index 11b8d840d22f5..0000000000000 --- a/src/hotspot/share/gc/x/xAbort.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xAbort.hpp" -#include "runtime/atomic.hpp" - -volatile bool XAbort::_should_abort = false; - -void XAbort::abort() { - Atomic::release_store_fence(&_should_abort, true); -} diff --git a/src/hotspot/share/gc/x/xAbort.hpp b/src/hotspot/share/gc/x/xAbort.hpp deleted file mode 100644 index 808a350584bc5..0000000000000 --- a/src/hotspot/share/gc/x/xAbort.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XABORT_HPP -#define SHARE_GC_X_XABORT_HPP - -#include "memory/allStatic.hpp" - -class XAbort : public AllStatic { -private: - static volatile bool _should_abort; - -public: - static bool should_abort(); - static void abort(); -}; - -#endif // SHARE_GC_X_XABORT_HPP diff --git a/src/hotspot/share/gc/x/xAbort.inline.hpp b/src/hotspot/share/gc/x/xAbort.inline.hpp deleted file mode 100644 index 8ef1219330a93..0000000000000 --- a/src/hotspot/share/gc/x/xAbort.inline.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XABORT_INLINE_HPP -#define SHARE_GC_X_XABORT_INLINE_HPP - -#include "gc/x/xAbort.hpp" - -#include "runtime/atomic.hpp" - -inline bool XAbort::should_abort() { - return Atomic::load_acquire(&_should_abort); -} - -#endif // SHARE_GC_X_XABORT_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xAddress.cpp b/src/hotspot/share/gc/x/xAddress.cpp deleted file mode 100644 index 33dffc662f161..0000000000000 --- a/src/hotspot/share/gc/x/xAddress.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xAddress.hpp" -#include "gc/x/xGlobals.hpp" - -void XAddress::set_good_mask(uintptr_t mask) { - XAddressGoodMask = mask; - XAddressBadMask = XAddressGoodMask ^ XAddressMetadataMask; - XAddressWeakBadMask = (XAddressGoodMask | XAddressMetadataRemapped | XAddressMetadataFinalizable) ^ XAddressMetadataMask; -} - -void XAddress::initialize() { - XAddressOffsetBits = XPlatformAddressOffsetBits(); - XAddressOffsetMask = (((uintptr_t)1 << XAddressOffsetBits) - 1) << XAddressOffsetShift; - XAddressOffsetMax = (uintptr_t)1 << XAddressOffsetBits; - - XAddressMetadataShift = XPlatformAddressMetadataShift(); - XAddressMetadataMask = (((uintptr_t)1 << XAddressMetadataBits) - 1) << XAddressMetadataShift; - - XAddressMetadataMarked0 = (uintptr_t)1 << (XAddressMetadataShift + 0); - XAddressMetadataMarked1 = (uintptr_t)1 << (XAddressMetadataShift + 1); - XAddressMetadataRemapped = (uintptr_t)1 << (XAddressMetadataShift + 2); - XAddressMetadataFinalizable = (uintptr_t)1 << (XAddressMetadataShift + 3); - - XAddressMetadataMarked = XAddressMetadataMarked0; - set_good_mask(XAddressMetadataRemapped); -} - -void XAddress::flip_to_marked() { - XAddressMetadataMarked ^= (XAddressMetadataMarked0 | XAddressMetadataMarked1); - set_good_mask(XAddressMetadataMarked); -} - -void XAddress::flip_to_remapped() { - set_good_mask(XAddressMetadataRemapped); -} diff --git a/src/hotspot/share/gc/x/xAddress.hpp b/src/hotspot/share/gc/x/xAddress.hpp deleted file mode 100644 index ff9d548f1af0c..0000000000000 --- a/src/hotspot/share/gc/x/xAddress.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XADDRESS_HPP -#define SHARE_GC_X_XADDRESS_HPP - -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" - -class XAddress : public AllStatic { - friend class XAddressTest; - -private: - static void set_good_mask(uintptr_t mask); - -public: - static void initialize(); - - static void flip_to_marked(); - static void flip_to_remapped(); - - static bool is_null(uintptr_t value); - static bool is_bad(uintptr_t value); - static bool is_good(uintptr_t value); - static bool is_good_or_null(uintptr_t value); - static bool is_weak_bad(uintptr_t value); - static bool is_weak_good(uintptr_t value); - static bool is_weak_good_or_null(uintptr_t value); - static bool is_marked(uintptr_t value); - static bool is_marked_or_null(uintptr_t value); - static bool is_finalizable(uintptr_t value); - static bool is_finalizable_good(uintptr_t value); - static bool is_remapped(uintptr_t value); - static bool is_in(uintptr_t value); - - static uintptr_t offset(uintptr_t value); - static uintptr_t good(uintptr_t value); - static uintptr_t good_or_null(uintptr_t value); - static uintptr_t finalizable_good(uintptr_t value); - static uintptr_t marked(uintptr_t value); - static uintptr_t marked0(uintptr_t value); - static uintptr_t marked1(uintptr_t value); - static uintptr_t remapped(uintptr_t value); - static uintptr_t remapped_or_null(uintptr_t value); -}; - -#endif // SHARE_GC_X_XADDRESS_HPP diff --git a/src/hotspot/share/gc/x/xAddress.inline.hpp b/src/hotspot/share/gc/x/xAddress.inline.hpp deleted file mode 100644 index 046ee10af00af..0000000000000 --- a/src/hotspot/share/gc/x/xAddress.inline.hpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * 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_GC_X_XADDRESS_INLINE_HPP -#define SHARE_GC_X_XADDRESS_INLINE_HPP - -#include "gc/x/xAddress.hpp" - -#include "gc/x/xGlobals.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" -#include "utilities/powerOfTwo.hpp" - -inline bool XAddress::is_null(uintptr_t value) { - return value == 0; -} - -inline bool XAddress::is_bad(uintptr_t value) { - return value & XAddressBadMask; -} - -inline bool XAddress::is_good(uintptr_t value) { - return !is_bad(value) && !is_null(value); -} - -inline bool XAddress::is_good_or_null(uintptr_t value) { - // Checking if an address is "not bad" is an optimized version of - // checking if it's "good or null", which eliminates an explicit - // null check. However, the implicit null check only checks that - // the mask bits are zero, not that the entire address is zero. - // This means that an address without mask bits would pass through - // the barrier as if it was null. This should be harmless as such - // addresses should ever be passed through the barrier. - const bool result = !is_bad(value); - assert((is_good(value) || is_null(value)) == result, "Bad address"); - return result; -} - -inline bool XAddress::is_weak_bad(uintptr_t value) { - return value & XAddressWeakBadMask; -} - -inline bool XAddress::is_weak_good(uintptr_t value) { - return !is_weak_bad(value) && !is_null(value); -} - -inline bool XAddress::is_weak_good_or_null(uintptr_t value) { - return !is_weak_bad(value); -} - -inline bool XAddress::is_marked(uintptr_t value) { - return value & XAddressMetadataMarked; -} - -inline bool XAddress::is_marked_or_null(uintptr_t value) { - return is_marked(value) || is_null(value); -} - -inline bool XAddress::is_finalizable(uintptr_t value) { - return value & XAddressMetadataFinalizable; -} - -inline bool XAddress::is_finalizable_good(uintptr_t value) { - return is_finalizable(value) && is_good(value ^ XAddressMetadataFinalizable); -} - -inline bool XAddress::is_remapped(uintptr_t value) { - return value & XAddressMetadataRemapped; -} - -inline bool XAddress::is_in(uintptr_t value) { - // Check that exactly one non-offset bit is set - if (!is_power_of_2(value & ~XAddressOffsetMask)) { - return false; - } - - // Check that one of the non-finalizable metadata is set - return value & (XAddressMetadataMask & ~XAddressMetadataFinalizable); -} - -inline uintptr_t XAddress::offset(uintptr_t value) { - return value & XAddressOffsetMask; -} - -inline uintptr_t XAddress::good(uintptr_t value) { - return offset(value) | XAddressGoodMask; -} - -inline uintptr_t XAddress::good_or_null(uintptr_t value) { - return is_null(value) ? 0 : good(value); -} - -inline uintptr_t XAddress::finalizable_good(uintptr_t value) { - return offset(value) | XAddressMetadataFinalizable | XAddressGoodMask; -} - -inline uintptr_t XAddress::marked(uintptr_t value) { - return offset(value) | XAddressMetadataMarked; -} - -inline uintptr_t XAddress::marked0(uintptr_t value) { - return offset(value) | XAddressMetadataMarked0; -} - -inline uintptr_t XAddress::marked1(uintptr_t value) { - return offset(value) | XAddressMetadataMarked1; -} - -inline uintptr_t XAddress::remapped(uintptr_t value) { - return offset(value) | XAddressMetadataRemapped; -} - -inline uintptr_t XAddress::remapped_or_null(uintptr_t value) { - return is_null(value) ? 0 : remapped(value); -} - -#endif // SHARE_GC_X_XADDRESS_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xAddressSpaceLimit.cpp b/src/hotspot/share/gc/x/xAddressSpaceLimit.cpp deleted file mode 100644 index 6d3c7a295dfe0..0000000000000 --- a/src/hotspot/share/gc/x/xAddressSpaceLimit.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xAddressSpaceLimit.hpp" -#include "gc/x/xGlobals.hpp" -#include "runtime/globals.hpp" -#include "runtime/os.hpp" -#include "utilities/align.hpp" - -static size_t address_space_limit() { - size_t limit = 0; - - if (os::has_allocatable_memory_limit(&limit)) { - return limit; - } - - // No limit - return SIZE_MAX; -} - -size_t XAddressSpaceLimit::mark_stack() { - // Allow mark stacks to occupy 10% of the address space - const size_t limit = address_space_limit() / 10; - return align_up(limit, XMarkStackSpaceExpandSize); -} - -size_t XAddressSpaceLimit::heap_view() { - // Allow all heap views to occupy 50% of the address space - const size_t limit = address_space_limit() / MaxVirtMemFraction / XHeapViews; - return align_up(limit, XGranuleSize); -} diff --git a/src/hotspot/share/gc/x/xAddressSpaceLimit.hpp b/src/hotspot/share/gc/x/xAddressSpaceLimit.hpp deleted file mode 100644 index 9a3fcc27a293d..0000000000000 --- a/src/hotspot/share/gc/x/xAddressSpaceLimit.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XADDRESSSPACELIMIT_HPP -#define SHARE_GC_X_XADDRESSSPACELIMIT_HPP - -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" - -class XAddressSpaceLimit : public AllStatic { -public: - static size_t mark_stack(); - static size_t heap_view(); -}; - -#endif // SHARE_GC_X_XADDRESSSPACELIMIT_HPP diff --git a/src/hotspot/share/gc/x/xAllocationFlags.hpp b/src/hotspot/share/gc/x/xAllocationFlags.hpp deleted file mode 100644 index 307d68c65ac78..0000000000000 --- a/src/hotspot/share/gc/x/xAllocationFlags.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XALLOCATIONFLAGS_HPP -#define SHARE_GC_X_XALLOCATIONFLAGS_HPP - -#include "gc/x/xBitField.hpp" -#include "memory/allocation.hpp" - -// -// Allocation flags layout -// ----------------------- -// -// 7 2 1 0 -// +-----+-+-+-+ -// |00000|1|1|1| -// +-----+-+-+-+ -// | | | | -// | | | * 0-0 Non-Blocking Flag (1-bit) -// | | | -// | | * 1-1 Worker Relocation Flag (1-bit) -// | | -// | * 2-2 Low Address Flag (1-bit) -// | -// * 7-3 Unused (5-bits) -// - -class XAllocationFlags { -private: - typedef XBitField field_non_blocking; - typedef XBitField field_worker_relocation; - typedef XBitField field_low_address; - - uint8_t _flags; - -public: - XAllocationFlags() : - _flags(0) {} - - void set_non_blocking() { - _flags |= field_non_blocking::encode(true); - } - - void set_worker_relocation() { - _flags |= field_worker_relocation::encode(true); - } - - void set_low_address() { - _flags |= field_low_address::encode(true); - } - - bool non_blocking() const { - return field_non_blocking::decode(_flags); - } - - bool worker_relocation() const { - return field_worker_relocation::decode(_flags); - } - - bool low_address() const { - return field_low_address::decode(_flags); - } -}; - -#endif // SHARE_GC_X_XALLOCATIONFLAGS_HPP diff --git a/src/hotspot/share/gc/x/xArguments.cpp b/src/hotspot/share/gc/x/xArguments.cpp deleted file mode 100644 index 13cb302d14aa9..0000000000000 --- a/src/hotspot/share/gc/x/xArguments.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xAddressSpaceLimit.hpp" -#include "gc/x/xArguments.hpp" -#include "gc/x/xCollectedHeap.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xHeuristics.hpp" -#include "gc/shared/gcArguments.hpp" -#include "runtime/globals.hpp" -#include "runtime/globals_extension.hpp" -#include "runtime/java.hpp" - -void XArguments::initialize_alignments() { - SpaceAlignment = XGranuleSize; - HeapAlignment = SpaceAlignment; -} - -void XArguments::initialize_heap_flags_and_sizes() { - // Nothing extra to do -} - -void XArguments::initialize() { - warning("Non-generational ZGC is deprecated."); - - // Check mark stack size - const size_t mark_stack_space_limit = XAddressSpaceLimit::mark_stack(); - if (ZMarkStackSpaceLimit > mark_stack_space_limit) { - if (!FLAG_IS_DEFAULT(ZMarkStackSpaceLimit)) { - vm_exit_during_initialization("ZMarkStackSpaceLimit too large for limited address space"); - } - FLAG_SET_DEFAULT(ZMarkStackSpaceLimit, mark_stack_space_limit); - } - - // Enable NUMA by default - if (FLAG_IS_DEFAULT(UseNUMA)) { - FLAG_SET_DEFAULT(UseNUMA, true); - } - - if (FLAG_IS_DEFAULT(ZFragmentationLimit)) { - FLAG_SET_DEFAULT(ZFragmentationLimit, 25.0); - } - - // Select number of parallel threads - if (FLAG_IS_DEFAULT(ParallelGCThreads)) { - FLAG_SET_DEFAULT(ParallelGCThreads, XHeuristics::nparallel_workers()); - } - - if (ParallelGCThreads == 0) { - vm_exit_during_initialization("The flag -XX:+UseZGC can not be combined with -XX:ParallelGCThreads=0"); - } - - // Select number of concurrent threads - if (FLAG_IS_DEFAULT(ConcGCThreads)) { - FLAG_SET_DEFAULT(ConcGCThreads, XHeuristics::nconcurrent_workers()); - } - - if (ConcGCThreads == 0) { - vm_exit_during_initialization("The flag -XX:+UseZGC can not be combined with -XX:ConcGCThreads=0"); - } - - // Large page size must match granule size - if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != XGranuleSize) { - vm_exit_during_initialization(err_msg("Incompatible -XX:LargePageSizeInBytes, only " - SIZE_FORMAT "M large pages are supported by ZGC", - XGranuleSize / M)); - } - - // The heuristics used when UseDynamicNumberOfGCThreads is - // enabled defaults to using a ZAllocationSpikeTolerance of 1. - if (UseDynamicNumberOfGCThreads && FLAG_IS_DEFAULT(ZAllocationSpikeTolerance)) { - FLAG_SET_DEFAULT(ZAllocationSpikeTolerance, 1); - } - -#ifdef COMPILER2 - // Enable loop strip mining by default - if (FLAG_IS_DEFAULT(UseCountedLoopSafepoints)) { - FLAG_SET_DEFAULT(UseCountedLoopSafepoints, true); - if (FLAG_IS_DEFAULT(LoopStripMiningIter)) { - FLAG_SET_DEFAULT(LoopStripMiningIter, 1000); - } - } -#endif - - // CompressedOops not supported - FLAG_SET_DEFAULT(UseCompressedOops, false); - - // Verification before startup and after exit not (yet) supported - FLAG_SET_DEFAULT(VerifyDuringStartup, false); - FLAG_SET_DEFAULT(VerifyBeforeExit, false); - - if (VerifyBeforeGC || VerifyDuringGC || VerifyAfterGC) { - FLAG_SET_DEFAULT(ZVerifyRoots, true); - FLAG_SET_DEFAULT(ZVerifyObjects, true); - } -} - -size_t XArguments::heap_virtual_to_physical_ratio() { - return XHeapViews * XVirtualToPhysicalRatio; -} - -CollectedHeap* XArguments::create_heap() { - return new XCollectedHeap(); -} - -bool XArguments::is_supported() { - return is_os_supported(); -} diff --git a/src/hotspot/share/gc/x/xArguments.hpp b/src/hotspot/share/gc/x/xArguments.hpp deleted file mode 100644 index 196dd994cad9b..0000000000000 --- a/src/hotspot/share/gc/x/xArguments.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XARGUMENTS_HPP -#define SHARE_GC_X_XARGUMENTS_HPP - -#include "gc/shared/gcArguments.hpp" - -class CollectedHeap; - -class XArguments : AllStatic { -public: - static void initialize_alignments(); - static void initialize_heap_flags_and_sizes(); - static void initialize(); - static size_t heap_virtual_to_physical_ratio(); - static CollectedHeap* create_heap(); - - static bool is_supported(); - - static bool is_os_supported(); -}; - -#endif // SHARE_GC_X_XARGUMENTS_HPP diff --git a/src/hotspot/share/gc/x/xArray.hpp b/src/hotspot/share/gc/x/xArray.hpp deleted file mode 100644 index b0b4b5bd81ea6..0000000000000 --- a/src/hotspot/share/gc/x/xArray.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XARRAY_HPP -#define SHARE_GC_X_XARRAY_HPP - -#include "memory/allocation.hpp" -#include "utilities/growableArray.hpp" - -template using XArray = GrowableArrayCHeap; - -template -class XArrayIteratorImpl : public StackObj { -private: - const T* _next; - const T* const _end; - - bool next_serial(T* elem); - bool next_parallel(T* elem); - -public: - XArrayIteratorImpl(const T* array, size_t length); - XArrayIteratorImpl(const XArray* array); - - bool next(T* elem); -}; - -template using XArrayIterator = XArrayIteratorImpl; -template using XArrayParallelIterator = XArrayIteratorImpl; - -#endif // SHARE_GC_X_XARRAY_HPP diff --git a/src/hotspot/share/gc/x/xArray.inline.hpp b/src/hotspot/share/gc/x/xArray.inline.hpp deleted file mode 100644 index 721e3130095cd..0000000000000 --- a/src/hotspot/share/gc/x/xArray.inline.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XARRAY_INLINE_HPP -#define SHARE_GC_X_XARRAY_INLINE_HPP - -#include "gc/x/xArray.hpp" - -#include "runtime/atomic.hpp" - -template -inline bool XArrayIteratorImpl::next_serial(T* elem) { - if (_next == _end) { - return false; - } - - *elem = *_next; - _next++; - - return true; -} - -template -inline bool XArrayIteratorImpl::next_parallel(T* elem) { - const T* old_next = Atomic::load(&_next); - - for (;;) { - if (old_next == _end) { - return false; - } - - const T* const new_next = old_next + 1; - const T* const prev_next = Atomic::cmpxchg(&_next, old_next, new_next); - if (prev_next == old_next) { - *elem = *old_next; - return true; - } - - old_next = prev_next; - } -} - -template -inline XArrayIteratorImpl::XArrayIteratorImpl(const T* array, size_t length) : - _next(array), - _end(array + length) {} - -template -inline XArrayIteratorImpl::XArrayIteratorImpl(const XArray* array) : - XArrayIteratorImpl(array->is_empty() ? nullptr : array->adr_at(0), array->length()) {} - -template -inline bool XArrayIteratorImpl::next(T* elem) { - if (Parallel) { - return next_parallel(elem); - } else { - return next_serial(elem); - } -} - -#endif // SHARE_GC_X_XARRAY_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xAttachedArray.hpp b/src/hotspot/share/gc/x/xAttachedArray.hpp deleted file mode 100644 index f039f602aab38..0000000000000 --- a/src/hotspot/share/gc/x/xAttachedArray.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XATTACHEDARRAY_HPP -#define SHARE_GC_X_XATTACHEDARRAY_HPP - -#include "utilities/globalDefinitions.hpp" - -class VMStructs; - -template -class XAttachedArray { - friend class ::VMStructs; - -private: - const size_t _length; - - static size_t object_size(); - static size_t array_size(size_t length); - -public: - template - static void* alloc(Allocator* allocator, size_t length); - - static void* alloc(size_t length); - static void free(ObjectT* obj); - - XAttachedArray(size_t length); - - size_t length() const; - ArrayT* operator()(const ObjectT* obj) const; -}; - -#endif // SHARE_GC_X_XATTACHEDARRAY_HPP diff --git a/src/hotspot/share/gc/x/xAttachedArray.inline.hpp b/src/hotspot/share/gc/x/xAttachedArray.inline.hpp deleted file mode 100644 index ba10de9967384..0000000000000 --- a/src/hotspot/share/gc/x/xAttachedArray.inline.hpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XATTACHEDARRAY_INLINE_HPP -#define SHARE_GC_X_XATTACHEDARRAY_INLINE_HPP - -#include "gc/x/xAttachedArray.hpp" - -#include "memory/allocation.hpp" -#include "utilities/align.hpp" - -template -inline size_t XAttachedArray::object_size() { - return align_up(sizeof(ObjectT), sizeof(ArrayT)); -} - -template -inline size_t XAttachedArray::array_size(size_t length) { - return sizeof(ArrayT) * length; -} - -template -template -inline void* XAttachedArray::alloc(Allocator* allocator, size_t length) { - // Allocate memory for object and array - const size_t size = object_size() + array_size(length); - void* const addr = allocator->alloc(size); - - // Placement new array - void* const array_addr = reinterpret_cast(addr) + object_size(); - ::new (array_addr) ArrayT[length]; - - // Return pointer to object - return addr; -} - -template -inline void* XAttachedArray::alloc(size_t length) { - struct Allocator { - void* alloc(size_t size) const { - return AllocateHeap(size, mtGC); - } - } allocator; - return alloc(&allocator, length); -} - -template -inline void XAttachedArray::free(ObjectT* obj) { - FreeHeap(obj); -} - -template -inline XAttachedArray::XAttachedArray(size_t length) : - _length(length) {} - -template -inline size_t XAttachedArray::length() const { - return _length; -} - -template -inline ArrayT* XAttachedArray::operator()(const ObjectT* obj) const { - return reinterpret_cast(reinterpret_cast(obj) + object_size()); -} - -#endif // SHARE_GC_X_XATTACHEDARRAY_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xBarrier.cpp b/src/hotspot/share/gc/x/xBarrier.cpp deleted file mode 100644 index 726950092b246..0000000000000 --- a/src/hotspot/share/gc/x/xBarrier.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "classfile/javaClasses.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xOop.inline.hpp" -#include "gc/x/xThread.inline.hpp" -#include "memory/iterator.inline.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/safepoint.hpp" -#include "utilities/debug.hpp" - -template -bool XBarrier::should_mark_through(uintptr_t addr) { - // Finalizable marked oops can still exists on the heap after marking - // has completed, in which case we just want to convert this into a - // good oop and not push it on the mark stack. - if (!during_mark()) { - assert(XAddress::is_marked(addr), "Should be marked"); - assert(XAddress::is_finalizable(addr), "Should be finalizable"); - return false; - } - - // During marking, we mark through already marked oops to avoid having - // some large part of the object graph hidden behind a pushed, but not - // yet flushed, entry on a mutator mark stack. Always marking through - // allows the GC workers to proceed through the object graph even if a - // mutator touched an oop first, which in turn will reduce the risk of - // having to flush mark stacks multiple times to terminate marking. - // - // However, when doing finalizable marking we don't always want to mark - // through. First, marking through an already strongly marked oop would - // be wasteful, since we will then proceed to do finalizable marking on - // an object which is, or will be, marked strongly. Second, marking - // through an already finalizable marked oop would also be wasteful, - // since such oops can never end up on a mutator mark stack and can - // therefore not hide some part of the object graph from GC workers. - if (finalizable) { - return !XAddress::is_marked(addr); - } - - // Mark through - return true; -} - -template -uintptr_t XBarrier::mark(uintptr_t addr) { - uintptr_t good_addr; - - if (XAddress::is_marked(addr)) { - // Already marked, but try to mark though anyway - good_addr = XAddress::good(addr); - } else if (XAddress::is_remapped(addr)) { - // Already remapped, but also needs to be marked - good_addr = XAddress::good(addr); - } else { - // Needs to be both remapped and marked - good_addr = remap(addr); - } - - // Mark - if (should_mark_through(addr)) { - XHeap::heap()->mark_object(good_addr); - } - - if (finalizable) { - // Make the oop finalizable marked/good, instead of normal marked/good. - // This is needed because an object might first becomes finalizable - // marked by the GC, and then loaded by a mutator thread. In this case, - // the mutator thread must be able to tell that the object needs to be - // strongly marked. The finalizable bit in the oop exists to make sure - // that a load of a finalizable marked oop will fall into the barrier - // slow path so that we can mark the object as strongly reachable. - return XAddress::finalizable_good(good_addr); - } - - return good_addr; -} - -uintptr_t XBarrier::remap(uintptr_t addr) { - assert(!XAddress::is_good(addr), "Should not be good"); - assert(!XAddress::is_weak_good(addr), "Should not be weak good"); - return XHeap::heap()->remap_object(addr); -} - -uintptr_t XBarrier::relocate(uintptr_t addr) { - assert(!XAddress::is_good(addr), "Should not be good"); - assert(!XAddress::is_weak_good(addr), "Should not be weak good"); - return XHeap::heap()->relocate_object(addr); -} - -uintptr_t XBarrier::relocate_or_mark(uintptr_t addr) { - return during_relocate() ? relocate(addr) : mark(addr); -} - -uintptr_t XBarrier::relocate_or_mark_no_follow(uintptr_t addr) { - return during_relocate() ? relocate(addr) : mark(addr); -} - -uintptr_t XBarrier::relocate_or_remap(uintptr_t addr) { - return during_relocate() ? relocate(addr) : remap(addr); -} - -// -// Load barrier -// -uintptr_t XBarrier::load_barrier_on_oop_slow_path(uintptr_t addr) { - return relocate_or_mark(addr); -} - -uintptr_t XBarrier::load_barrier_on_invisible_root_oop_slow_path(uintptr_t addr) { - return relocate_or_mark_no_follow(addr); -} - -void XBarrier::load_barrier_on_oop_fields(oop o) { - assert(XAddress::is_good(XOop::to_address(o)), "Should be good"); - XLoadBarrierOopClosure cl; - o->oop_iterate(&cl); -} - -// -// Weak load barrier -// -uintptr_t XBarrier::weak_load_barrier_on_oop_slow_path(uintptr_t addr) { - return XAddress::is_weak_good(addr) ? XAddress::good(addr) : relocate_or_remap(addr); -} - -uintptr_t XBarrier::weak_load_barrier_on_weak_oop_slow_path(uintptr_t addr) { - const uintptr_t good_addr = weak_load_barrier_on_oop_slow_path(addr); - if (XHeap::heap()->is_object_strongly_live(good_addr)) { - return good_addr; - } - - // Not strongly live - return 0; -} - -uintptr_t XBarrier::weak_load_barrier_on_phantom_oop_slow_path(uintptr_t addr) { - const uintptr_t good_addr = weak_load_barrier_on_oop_slow_path(addr); - if (XHeap::heap()->is_object_live(good_addr)) { - return good_addr; - } - - // Not live - return 0; -} - -// -// Keep alive barrier -// -uintptr_t XBarrier::keep_alive_barrier_on_oop_slow_path(uintptr_t addr) { - assert(during_mark(), "Invalid phase"); - - // Mark - return mark(addr); -} - -uintptr_t XBarrier::keep_alive_barrier_on_weak_oop_slow_path(uintptr_t addr) { - assert(XResurrection::is_blocked(), "This operation is only valid when resurrection is blocked"); - const uintptr_t good_addr = weak_load_barrier_on_oop_slow_path(addr); - assert(XHeap::heap()->is_object_strongly_live(good_addr), "Should be live"); - return good_addr; -} - -uintptr_t XBarrier::keep_alive_barrier_on_phantom_oop_slow_path(uintptr_t addr) { - assert(XResurrection::is_blocked(), "This operation is only valid when resurrection is blocked"); - const uintptr_t good_addr = weak_load_barrier_on_oop_slow_path(addr); - assert(XHeap::heap()->is_object_live(good_addr), "Should be live"); - return good_addr; -} - -// -// Mark barrier -// -uintptr_t XBarrier::mark_barrier_on_oop_slow_path(uintptr_t addr) { - assert(during_mark(), "Invalid phase"); - assert(XThread::is_worker(), "Invalid thread"); - - // Mark - return mark(addr); -} - -uintptr_t XBarrier::mark_barrier_on_finalizable_oop_slow_path(uintptr_t addr) { - assert(during_mark(), "Invalid phase"); - assert(XThread::is_worker(), "Invalid thread"); - - // Mark - return mark(addr); -} - -// -// Narrow oop variants, never used. -// -oop XBarrier::load_barrier_on_oop_field(volatile narrowOop* p) { - ShouldNotReachHere(); - return nullptr; -} - -oop XBarrier::load_barrier_on_oop_field_preloaded(volatile narrowOop* p, oop o) { - ShouldNotReachHere(); - return nullptr; -} - -void XBarrier::load_barrier_on_oop_array(volatile narrowOop* p, size_t length) { - ShouldNotReachHere(); -} - -oop XBarrier::load_barrier_on_weak_oop_field_preloaded(volatile narrowOop* p, oop o) { - ShouldNotReachHere(); - return nullptr; -} - -oop XBarrier::load_barrier_on_phantom_oop_field_preloaded(volatile narrowOop* p, oop o) { - ShouldNotReachHere(); - return nullptr; -} - -oop XBarrier::weak_load_barrier_on_oop_field_preloaded(volatile narrowOop* p, oop o) { - ShouldNotReachHere(); - return nullptr; -} - -oop XBarrier::weak_load_barrier_on_weak_oop_field_preloaded(volatile narrowOop* p, oop o) { - ShouldNotReachHere(); - return nullptr; -} - -oop XBarrier::weak_load_barrier_on_phantom_oop_field_preloaded(volatile narrowOop* p, oop o) { - ShouldNotReachHere(); - return nullptr; -} - -#ifdef ASSERT - -// ON_WEAK barriers should only ever be applied to j.l.r.Reference.referents. -void XBarrier::verify_on_weak(volatile oop* referent_addr) { - if (referent_addr != nullptr) { - uintptr_t base = (uintptr_t)referent_addr - java_lang_ref_Reference::referent_offset(); - oop obj = cast_to_oop(base); - assert(oopDesc::is_oop(obj), "Verification failed for: ref " PTR_FORMAT " obj: " PTR_FORMAT, (uintptr_t)referent_addr, base); - assert(java_lang_ref_Reference::is_referent_field(obj, java_lang_ref_Reference::referent_offset()), "Sanity"); - } -} - -#endif - -void XLoadBarrierOopClosure::do_oop(oop* p) { - XBarrier::load_barrier_on_oop_field(p); -} - -void XLoadBarrierOopClosure::do_oop(narrowOop* p) { - ShouldNotReachHere(); -} diff --git a/src/hotspot/share/gc/x/xBarrier.hpp b/src/hotspot/share/gc/x/xBarrier.hpp deleted file mode 100644 index e2ef210d7d25b..0000000000000 --- a/src/hotspot/share/gc/x/xBarrier.hpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XBARRIER_HPP -#define SHARE_GC_X_XBARRIER_HPP - -#include "memory/allStatic.hpp" -#include "memory/iterator.hpp" -#include "oops/oop.hpp" - -typedef bool (*XBarrierFastPath)(uintptr_t); -typedef uintptr_t (*XBarrierSlowPath)(uintptr_t); - -class XBarrier : public AllStatic { -private: - static const bool GCThread = true; - static const bool AnyThread = false; - - static const bool Follow = true; - static const bool DontFollow = false; - - static const bool Strong = false; - static const bool Finalizable = true; - - static const bool Publish = true; - static const bool Overflow = false; - - template static void self_heal(volatile oop* p, uintptr_t addr, uintptr_t heal_addr); - - template static oop barrier(volatile oop* p, oop o); - template static oop weak_barrier(volatile oop* p, oop o); - template static void root_barrier(oop* p, oop o); - - static bool is_good_or_null_fast_path(uintptr_t addr); - static bool is_weak_good_or_null_fast_path(uintptr_t addr); - static bool is_marked_or_null_fast_path(uintptr_t addr); - - static bool during_mark(); - static bool during_relocate(); - template static bool should_mark_through(uintptr_t addr); - template static uintptr_t mark(uintptr_t addr); - static uintptr_t remap(uintptr_t addr); - static uintptr_t relocate(uintptr_t addr); - static uintptr_t relocate_or_mark(uintptr_t addr); - static uintptr_t relocate_or_mark_no_follow(uintptr_t addr); - static uintptr_t relocate_or_remap(uintptr_t addr); - - static uintptr_t load_barrier_on_oop_slow_path(uintptr_t addr); - static uintptr_t load_barrier_on_invisible_root_oop_slow_path(uintptr_t addr); - - static uintptr_t weak_load_barrier_on_oop_slow_path(uintptr_t addr); - static uintptr_t weak_load_barrier_on_weak_oop_slow_path(uintptr_t addr); - static uintptr_t weak_load_barrier_on_phantom_oop_slow_path(uintptr_t addr); - - static uintptr_t keep_alive_barrier_on_oop_slow_path(uintptr_t addr); - static uintptr_t keep_alive_barrier_on_weak_oop_slow_path(uintptr_t addr); - static uintptr_t keep_alive_barrier_on_phantom_oop_slow_path(uintptr_t addr); - - static uintptr_t mark_barrier_on_oop_slow_path(uintptr_t addr); - static uintptr_t mark_barrier_on_finalizable_oop_slow_path(uintptr_t addr); - - static void verify_on_weak(volatile oop* referent_addr) NOT_DEBUG_RETURN; - -public: - // Load barrier - static oop load_barrier_on_oop(oop o); - static oop load_barrier_on_oop_field(volatile oop* p); - static oop load_barrier_on_oop_field_preloaded(volatile oop* p, oop o); - static void load_barrier_on_oop_array(volatile oop* p, size_t length); - static void load_barrier_on_oop_fields(oop o); - static oop load_barrier_on_weak_oop_field_preloaded(volatile oop* p, oop o); - static oop load_barrier_on_phantom_oop_field_preloaded(volatile oop* p, oop o); - static void load_barrier_on_root_oop_field(oop* p); - static void load_barrier_on_invisible_root_oop_field(oop* p); - - // Weak load barrier - static oop weak_load_barrier_on_oop_field(volatile oop* p); - static oop weak_load_barrier_on_oop_field_preloaded(volatile oop* p, oop o); - static oop weak_load_barrier_on_weak_oop(oop o); - static oop weak_load_barrier_on_weak_oop_field_preloaded(volatile oop* p, oop o); - static oop weak_load_barrier_on_phantom_oop(oop o); - static oop weak_load_barrier_on_phantom_oop_field_preloaded(volatile oop* p, oop o); - - // Is alive barrier - static bool is_alive_barrier_on_weak_oop(oop o); - static bool is_alive_barrier_on_phantom_oop(oop o); - - // Keep alive barrier - static void keep_alive_barrier_on_oop(oop o); - static void keep_alive_barrier_on_weak_oop_field(volatile oop* p); - static void keep_alive_barrier_on_phantom_oop_field(volatile oop* p); - static void keep_alive_barrier_on_phantom_root_oop_field(oop* p); - - // Mark barrier - static void mark_barrier_on_oop_field(volatile oop* p, bool finalizable); - static void mark_barrier_on_oop_array(volatile oop* p, size_t length, bool finalizable); - - // Narrow oop variants, never used. - static oop load_barrier_on_oop_field(volatile narrowOop* p); - static oop load_barrier_on_oop_field_preloaded(volatile narrowOop* p, oop o); - static void load_barrier_on_oop_array(volatile narrowOop* p, size_t length); - static oop load_barrier_on_weak_oop_field_preloaded(volatile narrowOop* p, oop o); - static oop load_barrier_on_phantom_oop_field_preloaded(volatile narrowOop* p, oop o); - static oop weak_load_barrier_on_oop_field_preloaded(volatile narrowOop* p, oop o); - static oop weak_load_barrier_on_weak_oop_field_preloaded(volatile narrowOop* p, oop o); - static oop weak_load_barrier_on_phantom_oop_field_preloaded(volatile narrowOop* p, oop o); -}; - -class XLoadBarrierOopClosure : public BasicOopIterateClosure { -public: - virtual void do_oop(oop* p); - virtual void do_oop(narrowOop* p); -}; - -#endif // SHARE_GC_X_XBARRIER_HPP diff --git a/src/hotspot/share/gc/x/xBarrier.inline.hpp b/src/hotspot/share/gc/x/xBarrier.inline.hpp deleted file mode 100644 index 2319bda4d74b1..0000000000000 --- a/src/hotspot/share/gc/x/xBarrier.inline.hpp +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XBARRIER_INLINE_HPP -#define SHARE_GC_X_XBARRIER_INLINE_HPP - -#include "gc/x/xBarrier.hpp" - -#include "code/codeCache.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xOop.inline.hpp" -#include "gc/x/xResurrection.inline.hpp" -#include "oops/oop.hpp" -#include "runtime/atomic.hpp" -#include "runtime/continuation.hpp" - -// A self heal must always "upgrade" the address metadata bits in -// accordance with the metadata bits state machine, which has the -// valid state transitions as described below (where N is the GC -// cycle). -// -// Note the subtleness of overlapping GC cycles. Specifically that -// oops are colored Remapped(N) starting at relocation N and ending -// at marking N + 1. -// -// +--- Mark Start -// | +--- Mark End -// | | +--- Relocate Start -// | | | +--- Relocate End -// | | | | -// Marked |---N---|--N+1--|--N+2--|---- -// Finalizable |---N---|--N+1--|--N+2--|---- -// Remapped ----|---N---|--N+1--|--N+2--| -// -// VALID STATE TRANSITIONS -// -// Marked(N) -> Remapped(N) -// -> Marked(N + 1) -// -> Finalizable(N + 1) -// -// Finalizable(N) -> Marked(N) -// -> Remapped(N) -// -> Marked(N + 1) -// -> Finalizable(N + 1) -// -// Remapped(N) -> Marked(N + 1) -// -> Finalizable(N + 1) -// -// PHASE VIEW -// -// XPhaseMark -// Load & Mark -// Marked(N) <- Marked(N - 1) -// <- Finalizable(N - 1) -// <- Remapped(N - 1) -// <- Finalizable(N) -// -// Mark(Finalizable) -// Finalizable(N) <- Marked(N - 1) -// <- Finalizable(N - 1) -// <- Remapped(N - 1) -// -// Load(AS_NO_KEEPALIVE) -// Remapped(N - 1) <- Marked(N - 1) -// <- Finalizable(N - 1) -// -// XPhaseMarkCompleted (Resurrection blocked) -// Load & Load(ON_WEAK/PHANTOM_OOP_REF | AS_NO_KEEPALIVE) & KeepAlive -// Marked(N) <- Marked(N - 1) -// <- Finalizable(N - 1) -// <- Remapped(N - 1) -// <- Finalizable(N) -// -// Load(ON_STRONG_OOP_REF | AS_NO_KEEPALIVE) -// Remapped(N - 1) <- Marked(N - 1) -// <- Finalizable(N - 1) -// -// XPhaseMarkCompleted (Resurrection unblocked) -// Load -// Marked(N) <- Finalizable(N) -// -// XPhaseRelocate -// Load & Load(AS_NO_KEEPALIVE) -// Remapped(N) <- Marked(N) -// <- Finalizable(N) - -template -inline void XBarrier::self_heal(volatile oop* p, uintptr_t addr, uintptr_t heal_addr) { - if (heal_addr == 0) { - // Never heal with null since it interacts badly with reference processing. - // A mutator clearing an oop would be similar to calling Reference.clear(), - // which would make the reference non-discoverable or silently dropped - // by the reference processor. - return; - } - - assert(!fast_path(addr), "Invalid self heal"); - assert(fast_path(heal_addr), "Invalid self heal"); - - for (;;) { - // Heal - const uintptr_t prev_addr = Atomic::cmpxchg((volatile uintptr_t*)p, addr, heal_addr, memory_order_relaxed); - if (prev_addr == addr) { - // Success - return; - } - - if (fast_path(prev_addr)) { - // Must not self heal - return; - } - - // The oop location was healed by another barrier, but still needs upgrading. - // Re-apply healing to make sure the oop is not left with weaker (remapped or - // finalizable) metadata bits than what this barrier tried to apply. - assert(XAddress::offset(prev_addr) == XAddress::offset(heal_addr), "Invalid offset"); - addr = prev_addr; - } -} - -template -inline oop XBarrier::barrier(volatile oop* p, oop o) { - const uintptr_t addr = XOop::to_address(o); - - // Fast path - if (fast_path(addr)) { - return XOop::from_address(addr); - } - - // Slow path - const uintptr_t good_addr = slow_path(addr); - - if (p != nullptr) { - self_heal(p, addr, good_addr); - } - - return XOop::from_address(good_addr); -} - -template -inline oop XBarrier::weak_barrier(volatile oop* p, oop o) { - const uintptr_t addr = XOop::to_address(o); - - // Fast path - if (fast_path(addr)) { - // Return the good address instead of the weak good address - // to ensure that the currently active heap view is used. - return XOop::from_address(XAddress::good_or_null(addr)); - } - - // Slow path - const uintptr_t good_addr = slow_path(addr); - - if (p != nullptr) { - // The slow path returns a good/marked address or null, but we never mark - // oops in a weak load barrier so we always heal with the remapped address. - self_heal(p, addr, XAddress::remapped_or_null(good_addr)); - } - - return XOop::from_address(good_addr); -} - -template -inline void XBarrier::root_barrier(oop* p, oop o) { - const uintptr_t addr = XOop::to_address(o); - - // Fast path - if (fast_path(addr)) { - return; - } - - // Slow path - const uintptr_t good_addr = slow_path(addr); - - // Non-atomic healing helps speed up root scanning. This is safe to do - // since we are always healing roots in a safepoint, or under a lock, - // which ensures we are never racing with mutators modifying roots while - // we are healing them. It's also safe in case multiple GC threads try - // to heal the same root if it is aligned, since they would always heal - // the root in the same way and it does not matter in which order it - // happens. For misaligned oops, there needs to be mutual exclusion. - *p = XOop::from_address(good_addr); -} - -inline bool XBarrier::is_good_or_null_fast_path(uintptr_t addr) { - return XAddress::is_good_or_null(addr); -} - -inline bool XBarrier::is_weak_good_or_null_fast_path(uintptr_t addr) { - return XAddress::is_weak_good_or_null(addr); -} - -inline bool XBarrier::is_marked_or_null_fast_path(uintptr_t addr) { - return XAddress::is_marked_or_null(addr); -} - -inline bool XBarrier::during_mark() { - return XGlobalPhase == XPhaseMark; -} - -inline bool XBarrier::during_relocate() { - return XGlobalPhase == XPhaseRelocate; -} - -// -// Load barrier -// -inline oop XBarrier::load_barrier_on_oop(oop o) { - return load_barrier_on_oop_field_preloaded((oop*)nullptr, o); -} - -inline oop XBarrier::load_barrier_on_oop_field(volatile oop* p) { - const oop o = Atomic::load(p); - return load_barrier_on_oop_field_preloaded(p, o); -} - -inline oop XBarrier::load_barrier_on_oop_field_preloaded(volatile oop* p, oop o) { - return barrier(p, o); -} - -inline void XBarrier::load_barrier_on_oop_array(volatile oop* p, size_t length) { - for (volatile const oop* const end = p + length; p < end; p++) { - load_barrier_on_oop_field(p); - } -} - -inline oop XBarrier::load_barrier_on_weak_oop_field_preloaded(volatile oop* p, oop o) { - verify_on_weak(p); - - if (XResurrection::is_blocked()) { - return barrier(p, o); - } - - return load_barrier_on_oop_field_preloaded(p, o); -} - -inline oop XBarrier::load_barrier_on_phantom_oop_field_preloaded(volatile oop* p, oop o) { - if (XResurrection::is_blocked()) { - return barrier(p, o); - } - - return load_barrier_on_oop_field_preloaded(p, o); -} - -inline void XBarrier::load_barrier_on_root_oop_field(oop* p) { - const oop o = *p; - root_barrier(p, o); -} - -inline void XBarrier::load_barrier_on_invisible_root_oop_field(oop* p) { - const oop o = *p; - root_barrier(p, o); -} - -// -// Weak load barrier -// -inline oop XBarrier::weak_load_barrier_on_oop_field(volatile oop* p) { - assert(!XResurrection::is_blocked(), "Should not be called during resurrection blocked phase"); - const oop o = Atomic::load(p); - return weak_load_barrier_on_oop_field_preloaded(p, o); -} - -inline oop XBarrier::weak_load_barrier_on_oop_field_preloaded(volatile oop* p, oop o) { - return weak_barrier(p, o); -} - -inline oop XBarrier::weak_load_barrier_on_weak_oop(oop o) { - return weak_load_barrier_on_weak_oop_field_preloaded((oop*)nullptr, o); -} - -inline oop XBarrier::weak_load_barrier_on_weak_oop_field_preloaded(volatile oop* p, oop o) { - verify_on_weak(p); - - if (XResurrection::is_blocked()) { - return barrier(p, o); - } - - return weak_load_barrier_on_oop_field_preloaded(p, o); -} - -inline oop XBarrier::weak_load_barrier_on_phantom_oop(oop o) { - return weak_load_barrier_on_phantom_oop_field_preloaded((oop*)nullptr, o); -} - -inline oop XBarrier::weak_load_barrier_on_phantom_oop_field_preloaded(volatile oop* p, oop o) { - if (XResurrection::is_blocked()) { - return barrier(p, o); - } - - return weak_load_barrier_on_oop_field_preloaded(p, o); -} - -// -// Is alive barrier -// -inline bool XBarrier::is_alive_barrier_on_weak_oop(oop o) { - // Check if oop is logically non-null. This operation - // is only valid when resurrection is blocked. - assert(XResurrection::is_blocked(), "Invalid phase"); - return weak_load_barrier_on_weak_oop(o) != nullptr; -} - -inline bool XBarrier::is_alive_barrier_on_phantom_oop(oop o) { - // Check if oop is logically non-null. This operation - // is only valid when resurrection is blocked. - assert(XResurrection::is_blocked(), "Invalid phase"); - return weak_load_barrier_on_phantom_oop(o) != nullptr; -} - -// -// Keep alive barrier -// -inline void XBarrier::keep_alive_barrier_on_weak_oop_field(volatile oop* p) { - assert(XResurrection::is_blocked(), "This operation is only valid when resurrection is blocked"); - const oop o = Atomic::load(p); - barrier(p, o); -} - -inline void XBarrier::keep_alive_barrier_on_phantom_oop_field(volatile oop* p) { - assert(XResurrection::is_blocked(), "This operation is only valid when resurrection is blocked"); - const oop o = Atomic::load(p); - barrier(p, o); -} - -inline void XBarrier::keep_alive_barrier_on_phantom_root_oop_field(oop* p) { - // The keep alive operation is only valid when resurrection is blocked. - // - // Except with Loom, where we intentionally trigger arms nmethods after - // unlinking, to get a sense of what nmethods are alive. This will trigger - // the keep alive barriers, but the oops are healed and the slow-paths - // will not trigger. We have stronger checks in the slow-paths. - assert(XResurrection::is_blocked() || (CodeCache::contains((void*)p)), - "This operation is only valid when resurrection is blocked"); - const oop o = *p; - root_barrier(p, o); -} - -inline void XBarrier::keep_alive_barrier_on_oop(oop o) { - const uintptr_t addr = XOop::to_address(o); - assert(XAddress::is_good(addr), "Invalid address"); - - if (during_mark()) { - keep_alive_barrier_on_oop_slow_path(addr); - } -} - -// -// Mark barrier -// -inline void XBarrier::mark_barrier_on_oop_field(volatile oop* p, bool finalizable) { - const oop o = Atomic::load(p); - - if (finalizable) { - barrier(p, o); - } else { - const uintptr_t addr = XOop::to_address(o); - if (XAddress::is_good(addr)) { - // Mark through good oop - mark_barrier_on_oop_slow_path(addr); - } else { - // Mark through bad oop - barrier(p, o); - } - } -} - -inline void XBarrier::mark_barrier_on_oop_array(volatile oop* p, size_t length, bool finalizable) { - for (volatile const oop* const end = p + length; p < end; p++) { - mark_barrier_on_oop_field(p, finalizable); - } -} - -#endif // SHARE_GC_X_XBARRIER_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xBarrierSet.cpp b/src/hotspot/share/gc/x/xBarrierSet.cpp deleted file mode 100644 index cee53e8c3fa00..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSet.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xBarrierSet.hpp" -#include "gc/x/xBarrierSetAssembler.hpp" -#include "gc/x/xBarrierSetNMethod.hpp" -#include "gc/x/xBarrierSetStackChunk.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xStackWatermark.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "runtime/javaThread.hpp" -#include "utilities/macros.hpp" -#ifdef COMPILER1 -#include "gc/x/c1/xBarrierSetC1.hpp" -#endif -#ifdef COMPILER2 -#include "gc/x/c2/xBarrierSetC2.hpp" -#endif - -class XBarrierSetC1; -class XBarrierSetC2; - -XBarrierSet::XBarrierSet() : - BarrierSet(make_barrier_set_assembler(), - make_barrier_set_c1(), - make_barrier_set_c2(), - new XBarrierSetNMethod(), - new XBarrierSetStackChunk(), - BarrierSet::FakeRtti(BarrierSet::XBarrierSet)) {} - -XBarrierSetAssembler* XBarrierSet::assembler() { - BarrierSetAssembler* const bsa = BarrierSet::barrier_set()->barrier_set_assembler(); - return reinterpret_cast(bsa); -} - -bool XBarrierSet::barrier_needed(DecoratorSet decorators, BasicType type) { - assert((decorators & AS_RAW) == 0, "Unexpected decorator"); - //assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Unexpected decorator"); - - if (is_reference_type(type)) { - assert((decorators & (IN_HEAP | IN_NATIVE)) != 0, "Where is reference?"); - // Barrier needed even when IN_NATIVE, to allow concurrent scanning. - return true; - } - - // Barrier not needed - return false; -} - -void XBarrierSet::on_thread_create(Thread* thread) { - // Create thread local data - XThreadLocalData::create(thread); -} - -void XBarrierSet::on_thread_destroy(Thread* thread) { - // Destroy thread local data - XThreadLocalData::destroy(thread); -} - -void XBarrierSet::on_thread_attach(Thread* thread) { - // Set thread local address bad mask - XThreadLocalData::set_address_bad_mask(thread, XAddressBadMask); - if (thread->is_Java_thread()) { - JavaThread* const jt = JavaThread::cast(thread); - StackWatermark* const watermark = new XStackWatermark(jt); - StackWatermarkSet::add_watermark(jt, watermark); - } -} - -void XBarrierSet::on_thread_detach(Thread* thread) { - // Flush and free any remaining mark stacks - XHeap::heap()->mark_flush_and_free(thread); -} - -void XBarrierSet::print_on(outputStream* st) const { - st->print_cr("XBarrierSet"); -} diff --git a/src/hotspot/share/gc/x/xBarrierSet.hpp b/src/hotspot/share/gc/x/xBarrierSet.hpp deleted file mode 100644 index 3f1eb760033d0..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSet.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * 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_GC_X_XBARRIERSET_HPP -#define SHARE_GC_X_XBARRIERSET_HPP - -#include "gc/shared/barrierSet.hpp" - -class XBarrierSetAssembler; - -class XBarrierSet : public BarrierSet { -public: - XBarrierSet(); - - static XBarrierSetAssembler* assembler(); - static bool barrier_needed(DecoratorSet decorators, BasicType type); - - virtual void on_thread_create(Thread* thread); - virtual void on_thread_destroy(Thread* thread); - virtual void on_thread_attach(Thread* thread); - virtual void on_thread_detach(Thread* thread); - - virtual void print_on(outputStream* st) const; - - template - class AccessBarrier : public BarrierSet::AccessBarrier { - private: - typedef BarrierSet::AccessBarrier Raw; - - template - static void verify_decorators_present(); - - template - static void verify_decorators_absent(); - - static oop* field_addr(oop base, ptrdiff_t offset); - - template - static oop load_barrier_on_oop_field_preloaded(T* addr, oop o); - - template - static oop load_barrier_on_unknown_oop_field_preloaded(oop base, ptrdiff_t offset, T* addr, oop o); - - public: - // - // In heap - // - template - static oop oop_load_in_heap(T* addr); - static oop oop_load_in_heap_at(oop base, ptrdiff_t offset); - - template - static oop oop_atomic_cmpxchg_in_heap(T* addr, oop compare_value, oop new_value); - static oop oop_atomic_cmpxchg_in_heap_at(oop base, ptrdiff_t offset, oop compare_value, oop new_value); - - template - static oop oop_atomic_xchg_in_heap(T* addr, oop new_value); - static oop oop_atomic_xchg_in_heap_at(oop base, ptrdiff_t offset, oop new_value); - - template - static bool oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, - arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, - size_t length); - - static void clone_in_heap(oop src, oop dst, size_t size); - - // - // Not in heap - // - template - static oop oop_load_not_in_heap(T* addr); - - template - static oop oop_atomic_cmpxchg_not_in_heap(T* addr, oop compare_value, oop new_value); - - template - static oop oop_atomic_xchg_not_in_heap(T* addr, oop new_value); - }; -}; - -template<> struct BarrierSet::GetName { - static const BarrierSet::Name value = BarrierSet::XBarrierSet; -}; - -template<> struct BarrierSet::GetType { - typedef ::XBarrierSet type; -}; - -#endif // SHARE_GC_X_XBARRIERSET_HPP diff --git a/src/hotspot/share/gc/x/xBarrierSet.inline.hpp b/src/hotspot/share/gc/x/xBarrierSet.inline.hpp deleted file mode 100644 index 3d92c38647d0b..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSet.inline.hpp +++ /dev/null @@ -1,242 +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. - */ - -#ifndef SHARE_GC_X_XBARRIERSET_INLINE_HPP -#define SHARE_GC_X_XBARRIERSET_INLINE_HPP - -#include "gc/x/xBarrierSet.hpp" - -#include "gc/shared/accessBarrierSupport.inline.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "utilities/debug.hpp" - -template -template -inline void XBarrierSet::AccessBarrier::verify_decorators_present() { - if ((decorators & expected) == 0) { - fatal("Using unsupported access decorators"); - } -} - -template -template -inline void XBarrierSet::AccessBarrier::verify_decorators_absent() { - if ((decorators & expected) != 0) { - fatal("Using unsupported access decorators"); - } -} - -template -inline oop* XBarrierSet::AccessBarrier::field_addr(oop base, ptrdiff_t offset) { - assert(base != nullptr, "Invalid base"); - return reinterpret_cast(reinterpret_cast((void*)base) + offset); -} - -template -template -inline oop XBarrierSet::AccessBarrier::load_barrier_on_oop_field_preloaded(T* addr, oop o) { - verify_decorators_absent(); - - if (HasDecorator::value) { - if (HasDecorator::value) { - return XBarrier::weak_load_barrier_on_oop_field_preloaded(addr, o); - } else if (HasDecorator::value) { - return XBarrier::weak_load_barrier_on_weak_oop_field_preloaded(addr, o); - } else { - assert((HasDecorator::value), "Must be"); - return XBarrier::weak_load_barrier_on_phantom_oop_field_preloaded(addr, o); - } - } else { - if (HasDecorator::value) { - return XBarrier::load_barrier_on_oop_field_preloaded(addr, o); - } else if (HasDecorator::value) { - return XBarrier::load_barrier_on_weak_oop_field_preloaded(addr, o); - } else { - assert((HasDecorator::value), "Must be"); - return XBarrier::load_barrier_on_phantom_oop_field_preloaded(addr, o); - } - } -} - -template -template -inline oop XBarrierSet::AccessBarrier::load_barrier_on_unknown_oop_field_preloaded(oop base, ptrdiff_t offset, T* addr, oop o) { - verify_decorators_present(); - - const DecoratorSet decorators_known_strength = - AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset); - - if (HasDecorator::value) { - if (decorators_known_strength & ON_STRONG_OOP_REF) { - return XBarrier::weak_load_barrier_on_oop_field_preloaded(addr, o); - } else if (decorators_known_strength & ON_WEAK_OOP_REF) { - return XBarrier::weak_load_barrier_on_weak_oop_field_preloaded(addr, o); - } else { - assert(decorators_known_strength & ON_PHANTOM_OOP_REF, "Must be"); - return XBarrier::weak_load_barrier_on_phantom_oop_field_preloaded(addr, o); - } - } else { - if (decorators_known_strength & ON_STRONG_OOP_REF) { - return XBarrier::load_barrier_on_oop_field_preloaded(addr, o); - } else if (decorators_known_strength & ON_WEAK_OOP_REF) { - return XBarrier::load_barrier_on_weak_oop_field_preloaded(addr, o); - } else { - assert(decorators_known_strength & ON_PHANTOM_OOP_REF, "Must be"); - return XBarrier::load_barrier_on_phantom_oop_field_preloaded(addr, o); - } - } -} - -// -// In heap -// -template -template -inline oop XBarrierSet::AccessBarrier::oop_load_in_heap(T* addr) { - verify_decorators_absent(); - - const oop o = Raw::oop_load_in_heap(addr); - return load_barrier_on_oop_field_preloaded(addr, o); -} - -template -inline oop XBarrierSet::AccessBarrier::oop_load_in_heap_at(oop base, ptrdiff_t offset) { - oop* const addr = field_addr(base, offset); - const oop o = Raw::oop_load_in_heap(addr); - - if (HasDecorator::value) { - return load_barrier_on_unknown_oop_field_preloaded(base, offset, addr, o); - } - - return load_barrier_on_oop_field_preloaded(addr, o); -} - -template -template -inline oop XBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap(T* addr, oop compare_value, oop new_value) { - verify_decorators_present(); - verify_decorators_absent(); - - XBarrier::load_barrier_on_oop_field(addr); - return Raw::oop_atomic_cmpxchg_in_heap(addr, compare_value, new_value); -} - -template -inline oop XBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap_at(oop base, ptrdiff_t offset, oop compare_value, oop new_value) { - verify_decorators_present(); - verify_decorators_absent(); - - // Through Unsafe.CompareAndExchangeObject()/CompareAndSetObject() we can receive - // calls with ON_UNKNOWN_OOP_REF set. However, we treat these as ON_STRONG_OOP_REF, - // with the motivation that if you're doing Unsafe operations on a Reference.referent - // field, then you're on your own anyway. - XBarrier::load_barrier_on_oop_field(field_addr(base, offset)); - return Raw::oop_atomic_cmpxchg_in_heap_at(base, offset, compare_value, new_value); -} - -template -template -inline oop XBarrierSet::AccessBarrier::oop_atomic_xchg_in_heap(T* addr, oop new_value) { - verify_decorators_present(); - verify_decorators_absent(); - - const oop o = Raw::oop_atomic_xchg_in_heap(addr, new_value); - return XBarrier::load_barrier_on_oop(o); -} - -template -inline oop XBarrierSet::AccessBarrier::oop_atomic_xchg_in_heap_at(oop base, ptrdiff_t offset, oop new_value) { - verify_decorators_present(); - verify_decorators_absent(); - - const oop o = Raw::oop_atomic_xchg_in_heap_at(base, offset, new_value); - return XBarrier::load_barrier_on_oop(o); -} - -template -template -inline bool XBarrierSet::AccessBarrier::oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, - arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, - size_t length) { - T* src = arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw); - T* dst = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw); - - if (!HasDecorator::value) { - // No check cast, bulk barrier and bulk copy - XBarrier::load_barrier_on_oop_array(src, length); - return Raw::oop_arraycopy_in_heap(nullptr, 0, src, nullptr, 0, dst, length); - } - - // Check cast and copy each elements - Klass* const dst_klass = objArrayOop(dst_obj)->element_klass(); - for (const T* const end = src + length; src < end; src++, dst++) { - const oop elem = XBarrier::load_barrier_on_oop_field(src); - if (!oopDesc::is_instanceof_or_null(elem, dst_klass)) { - // Check cast failed - return false; - } - - // Cast is safe, since we know it's never a narrowOop - *(oop*)dst = elem; - } - - return true; -} - -template -inline void XBarrierSet::AccessBarrier::clone_in_heap(oop src, oop dst, size_t size) { - XBarrier::load_barrier_on_oop_fields(src); - Raw::clone_in_heap(src, dst, size); -} - -// -// Not in heap -// -template -template -inline oop XBarrierSet::AccessBarrier::oop_load_not_in_heap(T* addr) { - verify_decorators_absent(); - - const oop o = Raw::oop_load_not_in_heap(addr); - return load_barrier_on_oop_field_preloaded(addr, o); -} - -template -template -inline oop XBarrierSet::AccessBarrier::oop_atomic_cmpxchg_not_in_heap(T* addr, oop compare_value, oop new_value) { - verify_decorators_present(); - verify_decorators_absent(); - - return Raw::oop_atomic_cmpxchg_not_in_heap(addr, compare_value, new_value); -} - -template -template -inline oop XBarrierSet::AccessBarrier::oop_atomic_xchg_not_in_heap(T* addr, oop new_value) { - verify_decorators_present(); - verify_decorators_absent(); - - return Raw::oop_atomic_xchg_not_in_heap(addr, new_value); -} - -#endif // SHARE_GC_X_XBARRIERSET_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xBarrierSetAssembler.cpp b/src/hotspot/share/gc/x/xBarrierSetAssembler.cpp deleted file mode 100644 index d00c12ed291e4..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSetAssembler.cpp +++ /dev/null @@ -1,35 +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. - */ - -#include "precompiled.hpp" -#include "gc/x/xBarrierSetAssembler.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "runtime/javaThread.hpp" - -Address XBarrierSetAssemblerBase::address_bad_mask_from_thread(Register thread) { - return Address(thread, XThreadLocalData::address_bad_mask_offset()); -} - -Address XBarrierSetAssemblerBase::address_bad_mask_from_jni_env(Register env) { - return Address(env, XThreadLocalData::address_bad_mask_offset() - JavaThread::jni_environment_offset()); -} diff --git a/src/hotspot/share/gc/x/xBarrierSetAssembler.hpp b/src/hotspot/share/gc/x/xBarrierSetAssembler.hpp deleted file mode 100644 index 2f733465bfb97..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSetAssembler.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018, 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 - * 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_GC_X_XBARRIERSETASSEMBLER_HPP -#define SHARE_GC_X_XBARRIERSETASSEMBLER_HPP - -#include "gc/shared/barrierSetAssembler.hpp" -#include "utilities/macros.hpp" - -class XBarrierSetAssemblerBase : public BarrierSetAssembler { -public: - static Address address_bad_mask_from_thread(Register thread); - static Address address_bad_mask_from_jni_env(Register env); -}; - -// Needs to be included after definition of XBarrierSetAssemblerBase -#include CPU_HEADER(gc/x/xBarrierSetAssembler) - -#endif // SHARE_GC_X_XBARRIERSETASSEMBLER_HPP diff --git a/src/hotspot/share/gc/x/xBarrierSetNMethod.cpp b/src/hotspot/share/gc/x/xBarrierSetNMethod.cpp deleted file mode 100644 index 3dc76463028b8..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSetNMethod.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "code/nmethod.hpp" -#include "gc/x/xBarrierSetNMethod.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xNMethod.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "logging/log.hpp" -#include "runtime/threadWXSetters.inline.hpp" - -bool XBarrierSetNMethod::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; - } - - XLocker locker(XNMethod::lock_for_nmethod(nm)); - log_trace(nmethod, barrier)("Entered critical zone for %p", nm); - - if (!is_armed(nm)) { - // Some other thread managed to complete while we were - // waiting for lock. No need to continue. - return true; - } - - MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current())); - - if (nm->is_unloading()) { - // We don't need to take the lock when unlinking nmethods from - // the Method, because it is only concurrently unlinked by - // the entry barrier, which acquires the per nmethod lock. - nm->unlink_from_method(); - - // We can end up calling nmethods that are unloading - // since we clear compiled ICs lazily. Returning false - // will re-resovle the call and update the compiled IC. - return false; - } - - // Heal oops - XNMethod::nmethod_oops_barrier(nm); - - - // CodeCache unloading support - nm->mark_as_maybe_on_stack(); - - // Disarm - disarm(nm); - - return true; -} - -int* XBarrierSetNMethod::disarmed_guard_value_address() const { - return (int*)XAddressBadMaskHighOrderBitsAddr; -} - -ByteSize XBarrierSetNMethod::thread_disarmed_guard_value_offset() const { - return XThreadLocalData::nmethod_disarmed_offset(); -} diff --git a/src/hotspot/share/gc/x/xBarrierSetNMethod.hpp b/src/hotspot/share/gc/x/xBarrierSetNMethod.hpp deleted file mode 100644 index db1ee8c4e8f11..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSetNMethod.hpp +++ /dev/null @@ -1,41 +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. - */ - -#ifndef SHARE_GC_X_XBARRIERSETNMETHOD_HPP -#define SHARE_GC_X_XBARRIERSETNMETHOD_HPP - -#include "gc/shared/barrierSetNMethod.hpp" -#include "memory/allocation.hpp" - -class nmethod; - -class XBarrierSetNMethod : public BarrierSetNMethod { -protected: - virtual bool nmethod_entry_barrier(nmethod* nm); - -public: - virtual ByteSize thread_disarmed_guard_value_offset() const; - virtual int* disarmed_guard_value_address() const; -}; - -#endif // SHARE_GC_X_XBARRIERSETNMETHOD_HPP diff --git a/src/hotspot/share/gc/x/xBarrierSetRuntime.cpp b/src/hotspot/share/gc/x/xBarrierSetRuntime.cpp deleted file mode 100644 index d87df24b9d8e6..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSetRuntime.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xBarrierSetRuntime.hpp" -#include "oops/access.hpp" -#include "runtime/interfaceSupport.inline.hpp" - -JRT_LEAF(oopDesc*, XBarrierSetRuntime::load_barrier_on_oop_field_preloaded(oopDesc* o, oop* p)) - return XBarrier::load_barrier_on_oop_field_preloaded(p, o); -JRT_END - -JRT_LEAF(oopDesc*, XBarrierSetRuntime::weak_load_barrier_on_oop_field_preloaded(oopDesc* o, oop* p)) - return XBarrier::weak_load_barrier_on_oop_field_preloaded(p, o); -JRT_END - -JRT_LEAF(oopDesc*, XBarrierSetRuntime::weak_load_barrier_on_weak_oop_field_preloaded(oopDesc* o, oop* p)) - return XBarrier::weak_load_barrier_on_weak_oop_field_preloaded(p, o); -JRT_END - -JRT_LEAF(oopDesc*, XBarrierSetRuntime::weak_load_barrier_on_phantom_oop_field_preloaded(oopDesc* o, oop* p)) - return XBarrier::weak_load_barrier_on_phantom_oop_field_preloaded(p, o); -JRT_END - -JRT_LEAF(oopDesc*, XBarrierSetRuntime::load_barrier_on_weak_oop_field_preloaded(oopDesc* o, oop* p)) - return XBarrier::load_barrier_on_weak_oop_field_preloaded(p, o); -JRT_END - -JRT_LEAF(oopDesc*, XBarrierSetRuntime::load_barrier_on_phantom_oop_field_preloaded(oopDesc* o, oop* p)) - return XBarrier::load_barrier_on_phantom_oop_field_preloaded(p, o); -JRT_END - -JRT_LEAF(void, XBarrierSetRuntime::load_barrier_on_oop_array(oop* p, size_t length)) - XBarrier::load_barrier_on_oop_array(p, length); -JRT_END - -JRT_LEAF(void, XBarrierSetRuntime::clone(oopDesc* src, oopDesc* dst, size_t size)) - HeapAccess<>::clone(src, dst, size); -JRT_END - -address XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(DecoratorSet decorators) { - if (decorators & ON_PHANTOM_OOP_REF) { - if (decorators & AS_NO_KEEPALIVE) { - return weak_load_barrier_on_phantom_oop_field_preloaded_addr(); - } else { - return load_barrier_on_phantom_oop_field_preloaded_addr(); - } - } else if (decorators & ON_WEAK_OOP_REF) { - if (decorators & AS_NO_KEEPALIVE) { - return weak_load_barrier_on_weak_oop_field_preloaded_addr(); - } else { - return load_barrier_on_weak_oop_field_preloaded_addr(); - } - } else { - if (decorators & AS_NO_KEEPALIVE) { - return weak_load_barrier_on_oop_field_preloaded_addr(); - } else { - return load_barrier_on_oop_field_preloaded_addr(); - } - } -} - -address XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr() { - return reinterpret_cast
    (load_barrier_on_oop_field_preloaded); -} - -address XBarrierSetRuntime::load_barrier_on_weak_oop_field_preloaded_addr() { - return reinterpret_cast
    (load_barrier_on_weak_oop_field_preloaded); -} - -address XBarrierSetRuntime::load_barrier_on_phantom_oop_field_preloaded_addr() { - return reinterpret_cast
    (load_barrier_on_phantom_oop_field_preloaded); -} - -address XBarrierSetRuntime::weak_load_barrier_on_oop_field_preloaded_addr() { - return reinterpret_cast
    (weak_load_barrier_on_oop_field_preloaded); -} - -address XBarrierSetRuntime::weak_load_barrier_on_weak_oop_field_preloaded_addr() { - return reinterpret_cast
    (weak_load_barrier_on_weak_oop_field_preloaded); -} - -address XBarrierSetRuntime::weak_load_barrier_on_phantom_oop_field_preloaded_addr() { - return reinterpret_cast
    (weak_load_barrier_on_phantom_oop_field_preloaded); -} - -address XBarrierSetRuntime::load_barrier_on_oop_array_addr() { - return reinterpret_cast
    (load_barrier_on_oop_array); -} - -address XBarrierSetRuntime::clone_addr() { - return reinterpret_cast
    (clone); -} diff --git a/src/hotspot/share/gc/x/xBarrierSetRuntime.hpp b/src/hotspot/share/gc/x/xBarrierSetRuntime.hpp deleted file mode 100644 index 6302f1ce36dc0..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSetRuntime.hpp +++ /dev/null @@ -1,56 +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. - */ - -#ifndef SHARE_GC_X_XBARRIERSETRUNTIME_HPP -#define SHARE_GC_X_XBARRIERSETRUNTIME_HPP - -#include "memory/allStatic.hpp" -#include "oops/accessDecorators.hpp" -#include "utilities/globalDefinitions.hpp" - -class oopDesc; - -class XBarrierSetRuntime : public AllStatic { -private: - static oopDesc* load_barrier_on_oop_field_preloaded(oopDesc* o, oop* p); - static oopDesc* load_barrier_on_weak_oop_field_preloaded(oopDesc* o, oop* p); - static oopDesc* load_barrier_on_phantom_oop_field_preloaded(oopDesc* o, oop* p); - static oopDesc* weak_load_barrier_on_oop_field_preloaded(oopDesc* o, oop* p); - static oopDesc* weak_load_barrier_on_weak_oop_field_preloaded(oopDesc* o, oop* p); - static oopDesc* weak_load_barrier_on_phantom_oop_field_preloaded(oopDesc* o, oop* p); - static void load_barrier_on_oop_array(oop* p, size_t length); - static void clone(oopDesc* src, oopDesc* dst, size_t size); - -public: - static address load_barrier_on_oop_field_preloaded_addr(DecoratorSet decorators); - static address load_barrier_on_oop_field_preloaded_addr(); - static address load_barrier_on_weak_oop_field_preloaded_addr(); - static address load_barrier_on_phantom_oop_field_preloaded_addr(); - static address weak_load_barrier_on_oop_field_preloaded_addr(); - static address weak_load_barrier_on_weak_oop_field_preloaded_addr(); - static address weak_load_barrier_on_phantom_oop_field_preloaded_addr(); - static address load_barrier_on_oop_array_addr(); - static address clone_addr(); -}; - -#endif // SHARE_GC_X_XBARRIERSETRUNTIME_HPP diff --git a/src/hotspot/share/gc/x/xBarrierSetStackChunk.cpp b/src/hotspot/share/gc/x/xBarrierSetStackChunk.cpp deleted file mode 100644 index 1670a00434fb0..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSetStackChunk.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xBarrierSetStackChunk.hpp" -#include "runtime/atomic.hpp" -#include "utilities/debug.hpp" - -void XBarrierSetStackChunk::encode_gc_mode(stackChunkOop chunk, OopIterator* iterator) { - // Do nothing -} - -void XBarrierSetStackChunk::decode_gc_mode(stackChunkOop chunk, OopIterator* iterator) { - // Do nothing -} - -oop XBarrierSetStackChunk::load_oop(stackChunkOop chunk, oop* addr) { - oop obj = Atomic::load(addr); - return XBarrier::load_barrier_on_oop_field_preloaded((volatile oop*)nullptr, obj); -} - -oop XBarrierSetStackChunk::load_oop(stackChunkOop chunk, narrowOop* addr) { - ShouldNotReachHere(); - return nullptr; -} diff --git a/src/hotspot/share/gc/x/xBarrierSetStackChunk.hpp b/src/hotspot/share/gc/x/xBarrierSetStackChunk.hpp deleted file mode 100644 index 36180db7b8c4a..0000000000000 --- a/src/hotspot/share/gc/x/xBarrierSetStackChunk.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XBARRIERSETSTACKCHUNK_HPP -#define SHARE_GC_X_XBARRIERSETSTACKCHUNK_HPP - -#include "gc/shared/barrierSetStackChunk.hpp" -#include "memory/iterator.hpp" -#include "oops/oopsHierarchy.hpp" -#include "utilities/globalDefinitions.hpp" - -class OopClosure; - -class XBarrierSetStackChunk : public BarrierSetStackChunk { -public: - virtual void encode_gc_mode(stackChunkOop chunk, OopIterator* iterator) override; - virtual void decode_gc_mode(stackChunkOop chunk, OopIterator* iterator) override; - - virtual oop load_oop(stackChunkOop chunk, oop* addr) override; - virtual oop load_oop(stackChunkOop chunk, narrowOop* addr) override; -}; - -#endif // SHARE_GC_X_XBARRIERSETSTACKCHUNK_HPP diff --git a/src/hotspot/share/gc/x/xBitField.hpp b/src/hotspot/share/gc/x/xBitField.hpp deleted file mode 100644 index f11d7cf7ef7a4..0000000000000 --- a/src/hotspot/share/gc/x/xBitField.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XBITFIELD_HPP -#define SHARE_GC_X_XBITFIELD_HPP - -#include "memory/allStatic.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" - -// -// Example -// ------- -// -// typedef XBitField field_word_aligned_size; -// typedef XBitField field_length; -// -// -// 6 3 3 -// 3 2 1 2 10 -// +-----------------------------------+---------------------------------+--+ -// |11111111 11111111 11111111 11111111|11111111 11111111 11111111 111111|11| -// +-----------------------------------+---------------------------------+--+ -// | | | -// | 31-2 field_length (30-bits) * | -// | | -// | 1-0 field_word_aligned_size (2-bits) * -// | -// * 63-32 Unused (32-bits) -// -// -// field_word_aligned_size::encode(16) = 2 -// field_length::encode(2342) = 9368 -// -// field_word_aligned_size::decode(9368 | 2) = 16 -// field_length::decode(9368 | 2) = 2342 -// - -template -class XBitField : public AllStatic { -private: - static const int ContainerBits = sizeof(ContainerType) * BitsPerByte; - - static_assert(FieldBits < ContainerBits, "Field too large"); - static_assert(FieldShift + FieldBits <= ContainerBits, "Field too large"); - static_assert(ValueShift + FieldBits <= ContainerBits, "Field too large"); - - static const ContainerType FieldMask = (((ContainerType)1 << FieldBits) - 1); - -public: - static ValueType decode(ContainerType container) { - return (ValueType)(((container >> FieldShift) & FieldMask) << ValueShift); - } - - static ContainerType encode(ValueType value) { - assert(((ContainerType)value & (FieldMask << ValueShift)) == (ContainerType)value, "Invalid value"); - return ((ContainerType)value >> ValueShift) << FieldShift; - } -}; - -#endif // SHARE_GC_X_XBITFIELD_HPP diff --git a/src/hotspot/share/gc/x/xBitMap.hpp b/src/hotspot/share/gc/x/xBitMap.hpp deleted file mode 100644 index c96f63b4c8985..0000000000000 --- a/src/hotspot/share/gc/x/xBitMap.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XBITMAP_HPP -#define SHARE_GC_X_XBITMAP_HPP - -#include "utilities/bitMap.hpp" - -class XBitMap : public CHeapBitMap { -private: - static bm_word_t bit_mask_pair(idx_t bit); - - bool par_set_bit_pair_finalizable(idx_t bit, bool& inc_live); - bool par_set_bit_pair_strong(idx_t bit, bool& inc_live); - -public: - XBitMap(idx_t size_in_bits); - - bool par_set_bit_pair(idx_t bit, bool finalizable, bool& inc_live); -}; - -#endif // SHARE_GC_X_XBITMAP_HPP diff --git a/src/hotspot/share/gc/x/xBitMap.inline.hpp b/src/hotspot/share/gc/x/xBitMap.inline.hpp deleted file mode 100644 index e35f59eeb880e..0000000000000 --- a/src/hotspot/share/gc/x/xBitMap.inline.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XBITMAP_INLINE_HPP -#define SHARE_GC_X_XBITMAP_INLINE_HPP - -#include "gc/x/xBitMap.hpp" - -#include "runtime/atomic.hpp" -#include "utilities/bitMap.inline.hpp" -#include "utilities/debug.hpp" - -inline XBitMap::XBitMap(idx_t size_in_bits) : - CHeapBitMap(size_in_bits, mtGC, false /* clear */) {} - -inline BitMap::bm_word_t XBitMap::bit_mask_pair(idx_t bit) { - assert(bit_in_word(bit) < BitsPerWord - 1, "Invalid bit index"); - return (bm_word_t)3 << bit_in_word(bit); -} - -inline bool XBitMap::par_set_bit_pair_finalizable(idx_t bit, bool& inc_live) { - inc_live = par_set_bit(bit); - return inc_live; -} - -inline bool XBitMap::par_set_bit_pair_strong(idx_t bit, bool& inc_live) { - verify_index(bit); - volatile bm_word_t* const addr = word_addr(bit); - const bm_word_t pair_mask = bit_mask_pair(bit); - bm_word_t old_val = *addr; - - do { - const bm_word_t new_val = old_val | pair_mask; - if (new_val == old_val) { - // Someone else beat us to it - inc_live = false; - return false; - } - const bm_word_t cur_val = Atomic::cmpxchg(addr, old_val, new_val); - if (cur_val == old_val) { - // Success - const bm_word_t marked_mask = bit_mask(bit); - inc_live = !(old_val & marked_mask); - return true; - } - - // The value changed, retry - old_val = cur_val; - } while (true); -} - -inline bool XBitMap::par_set_bit_pair(idx_t bit, bool finalizable, bool& inc_live) { - if (finalizable) { - return par_set_bit_pair_finalizable(bit, inc_live); - } else { - return par_set_bit_pair_strong(bit, inc_live); - } -} - -#endif // SHARE_GC_X_XBITMAP_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xBreakpoint.cpp b/src/hotspot/share/gc/x/xBreakpoint.cpp deleted file mode 100644 index e053ceaedb956..0000000000000 --- a/src/hotspot/share/gc/x/xBreakpoint.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/concurrentGCBreakpoints.hpp" -#include "gc/x/xBreakpoint.hpp" -#include "runtime/mutexLocker.hpp" -#include "utilities/debug.hpp" - -bool XBreakpoint::_start_gc = false; - -void XBreakpoint::start_gc() { - MonitorLocker ml(ConcurrentGCBreakpoints::monitor()); - assert(ConcurrentGCBreakpoints::is_controlled(), "Invalid state"); - assert(!_start_gc, "Invalid state"); - _start_gc = true; - ml.notify_all(); -} - -void XBreakpoint::at_before_gc() { - MonitorLocker ml(ConcurrentGCBreakpoints::monitor(), Mutex::_no_safepoint_check_flag); - while (ConcurrentGCBreakpoints::is_controlled() && !_start_gc) { - ml.wait(); - } - _start_gc = false; - ConcurrentGCBreakpoints::notify_idle_to_active(); -} - -void XBreakpoint::at_after_gc() { - ConcurrentGCBreakpoints::notify_active_to_idle(); -} - -void XBreakpoint::at_after_marking_started() { - ConcurrentGCBreakpoints::at("AFTER MARKING STARTED"); -} - -void XBreakpoint::at_before_marking_completed() { - ConcurrentGCBreakpoints::at("BEFORE MARKING COMPLETED"); -} - -void XBreakpoint::at_after_reference_processing_started() { - ConcurrentGCBreakpoints::at("AFTER CONCURRENT REFERENCE PROCESSING STARTED"); -} diff --git a/src/hotspot/share/gc/x/xBreakpoint.hpp b/src/hotspot/share/gc/x/xBreakpoint.hpp deleted file mode 100644 index 0c0b9d3c90f69..0000000000000 --- a/src/hotspot/share/gc/x/xBreakpoint.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XBREAKPOINT_HPP -#define SHARE_GC_X_XBREAKPOINT_HPP - -#include "memory/allStatic.hpp" - -class XBreakpoint : public AllStatic { -private: - static bool _start_gc; - -public: - static void start_gc(); - - static void at_before_gc(); - static void at_after_gc(); - static void at_after_marking_started(); - static void at_before_marking_completed(); - static void at_after_reference_processing_started(); -}; - -#endif // SHARE_GC_X_XBREAKPOINT_HPP diff --git a/src/hotspot/share/gc/x/xCPU.cpp b/src/hotspot/share/gc/x/xCPU.cpp deleted file mode 100644 index d21d32aeb352d..0000000000000 --- a/src/hotspot/share/gc/x/xCPU.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xCPU.inline.hpp" -#include "memory/padded.inline.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/os.hpp" -#include "utilities/debug.hpp" - -#define XCPU_UNKNOWN_AFFINITY ((Thread*)-1) -#define XCPU_UNKNOWN_SELF ((Thread*)-2) - -PaddedEnd* XCPU::_affinity = nullptr; -THREAD_LOCAL Thread* XCPU::_self = XCPU_UNKNOWN_SELF; -THREAD_LOCAL uint32_t XCPU::_cpu = 0; - -void XCPU::initialize() { - assert(_affinity == nullptr, "Already initialized"); - const uint32_t ncpus = count(); - - _affinity = PaddedArray::create_unfreeable(ncpus); - - for (uint32_t i = 0; i < ncpus; i++) { - _affinity[i]._thread = XCPU_UNKNOWN_AFFINITY; - } - - log_info_p(gc, init)("CPUs: %u total, %u available", - os::processor_count(), - os::initial_active_processor_count()); -} - -uint32_t XCPU::id_slow() { - // Set current thread - if (_self == XCPU_UNKNOWN_SELF) { - _self = Thread::current(); - } - - // Set current CPU - _cpu = os::processor_id(); - - // Update affinity table - _affinity[_cpu]._thread = _self; - - return _cpu; -} diff --git a/src/hotspot/share/gc/x/xCPU.hpp b/src/hotspot/share/gc/x/xCPU.hpp deleted file mode 100644 index fd931956c4bdc..0000000000000 --- a/src/hotspot/share/gc/x/xCPU.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XCPU_HPP -#define SHARE_GC_X_XCPU_HPP - -#include "memory/allStatic.hpp" -#include "memory/padded.hpp" -#include "utilities/globalDefinitions.hpp" - -class Thread; - -class XCPU : public AllStatic { -private: - struct XCPUAffinity { - Thread* _thread; - }; - - static PaddedEnd* _affinity; - static THREAD_LOCAL Thread* _self; - static THREAD_LOCAL uint32_t _cpu; - - static uint32_t id_slow(); - -public: - static void initialize(); - - static uint32_t count(); - static uint32_t id(); -}; - -#endif // SHARE_GC_X_XCPU_HPP diff --git a/src/hotspot/share/gc/x/xCPU.inline.hpp b/src/hotspot/share/gc/x/xCPU.inline.hpp deleted file mode 100644 index 3cf5bfa96e00e..0000000000000 --- a/src/hotspot/share/gc/x/xCPU.inline.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 - * 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_GC_X_XCPU_INLINE_HPP -#define SHARE_GC_X_XCPU_INLINE_HPP - -#include "gc/x/xCPU.hpp" - -#include "runtime/os.hpp" -#include "utilities/debug.hpp" - -inline uint32_t XCPU::count() { - return os::processor_count(); -} - -inline uint32_t XCPU::id() { - assert(_affinity != nullptr, "Not initialized"); - - // Fast path - if (_affinity[_cpu]._thread == _self) { - return _cpu; - } - - // Slow path - return id_slow(); -} - -#endif // SHARE_GC_X_XCPU_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xCollectedHeap.cpp b/src/hotspot/share/gc/x/xCollectedHeap.cpp deleted file mode 100644 index d03b6312a67dd..0000000000000 --- a/src/hotspot/share/gc/x/xCollectedHeap.cpp +++ /dev/null @@ -1,344 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "classfile/classLoaderData.hpp" -#include "gc/shared/gcHeapSummary.hpp" -#include "gc/shared/gcLocker.inline.hpp" -#include "gc/shared/suspendibleThreadSet.hpp" -#include "gc/x/xCollectedHeap.hpp" -#include "gc/x/xDirector.hpp" -#include "gc/x/xDriver.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xNMethod.hpp" -#include "gc/x/xObjArrayAllocator.hpp" -#include "gc/x/xOop.inline.hpp" -#include "gc/x/xServiceability.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xUtils.inline.hpp" -#include "memory/classLoaderMetaspace.hpp" -#include "memory/iterator.hpp" -#include "memory/metaspaceCriticalAllocation.hpp" -#include "memory/universe.hpp" -#include "oops/stackChunkOop.hpp" -#include "runtime/continuationJavaClasses.hpp" -#include "runtime/stackWatermarkSet.hpp" -#include "utilities/align.hpp" - -XCollectedHeap* XCollectedHeap::heap() { - return named_heap(CollectedHeap::Z); -} - -XCollectedHeap::XCollectedHeap() : - _barrier_set(), - _initialize(&_barrier_set), - _heap(), - _driver(new XDriver()), - _director(new XDirector(_driver)), - _stat(new XStat()), - _runtime_workers() {} - -CollectedHeap::Name XCollectedHeap::kind() const { - return CollectedHeap::Z; -} - -const char* XCollectedHeap::name() const { - return XName; -} - -jint XCollectedHeap::initialize() { - if (!_heap.is_initialized()) { - return JNI_ENOMEM; - } - - Universe::calculate_verify_data((HeapWord*)0, (HeapWord*)UINTPTR_MAX); - - return JNI_OK; -} - -void XCollectedHeap::initialize_serviceability() { - _heap.serviceability_initialize(); -} - -class XStopConcurrentGCThreadClosure : public ThreadClosure { -public: - virtual void do_thread(Thread* thread) { - if (thread->is_ConcurrentGC_thread()) { - ConcurrentGCThread::cast(thread)->stop(); - } - } -}; - -void XCollectedHeap::stop() { - XStopConcurrentGCThreadClosure cl; - gc_threads_do(&cl); -} - -size_t XCollectedHeap::max_capacity() const { - return _heap.max_capacity(); -} - -size_t XCollectedHeap::capacity() const { - return _heap.capacity(); -} - -size_t XCollectedHeap::used() const { - return _heap.used(); -} - -size_t XCollectedHeap::unused() const { - return _heap.unused(); -} - -bool XCollectedHeap::is_maximal_no_gc() const { - // Not supported - ShouldNotReachHere(); - return false; -} - -bool XCollectedHeap::is_in(const void* p) const { - return _heap.is_in((uintptr_t)p); -} - -bool XCollectedHeap::requires_barriers(stackChunkOop obj) const { - uintptr_t* cont_addr = obj->field_addr(jdk_internal_vm_StackChunk::cont_offset()); - - if (!_heap.is_allocating(cast_from_oop(obj))) { - // An object that isn't allocating, is visible from GC tracing. Such - // stack chunks require barriers. - return true; - } - - if (!XAddress::is_good_or_null(*cont_addr)) { - // If a chunk is allocated after a GC started, but before relocate start - // we can have an allocating chunk that isn't deeply good. That means that - // the contained oops might be bad and require GC barriers. - return true; - } - - // The chunk is allocating and its pointers are good. This chunk needs no - // GC barriers - return false; -} - -HeapWord* XCollectedHeap::allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) { - const size_t size_in_bytes = XUtils::words_to_bytes(align_object_size(requested_size)); - const uintptr_t addr = _heap.alloc_tlab(size_in_bytes); - - if (addr != 0) { - *actual_size = requested_size; - } - - return (HeapWord*)addr; -} - -oop XCollectedHeap::array_allocate(Klass* klass, size_t size, int length, bool do_zero, TRAPS) { - XObjArrayAllocator allocator(klass, size, length, do_zero, THREAD); - return allocator.allocate(); -} - -HeapWord* XCollectedHeap::mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) { - const size_t size_in_bytes = XUtils::words_to_bytes(align_object_size(size)); - return (HeapWord*)_heap.alloc_object(size_in_bytes); -} - -MetaWord* XCollectedHeap::satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, - size_t size, - Metaspace::MetadataType mdtype) { - // Start asynchronous GC - collect(GCCause::_metadata_GC_threshold); - - // Expand and retry allocation - MetaWord* const result = loader_data->metaspace_non_null()->expand_and_allocate(size, mdtype); - if (result != nullptr) { - return result; - } - - // As a last resort, try a critical allocation, riding on a synchronous full GC - return MetaspaceCriticalAllocation::allocate(loader_data, size, mdtype); -} - -void XCollectedHeap::collect(GCCause::Cause cause) { - _driver->collect(cause); -} - -void XCollectedHeap::collect_as_vm_thread(GCCause::Cause cause) { - // These collection requests are ignored since ZGC can't run a synchronous - // GC cycle from within the VM thread. This is considered benign, since the - // only GC causes coming in here should be heap dumper and heap inspector. - // If the heap dumper or heap inspector explicitly requests a gc and the - // caller is not the VM thread a synchronous GC cycle is performed from the - // caller thread in the prologue. - assert(Thread::current()->is_VM_thread(), "Should be the VM thread"); - guarantee(cause == GCCause::_heap_dump || - cause == GCCause::_heap_inspection, "Invalid cause"); -} - -void XCollectedHeap::do_full_collection(bool clear_all_soft_refs) { - // Not supported - ShouldNotReachHere(); -} - -size_t XCollectedHeap::tlab_capacity(Thread* ignored) const { - return _heap.tlab_capacity(); -} - -size_t XCollectedHeap::tlab_used(Thread* ignored) const { - return _heap.tlab_used(); -} - -size_t XCollectedHeap::max_tlab_size() const { - return _heap.max_tlab_size(); -} - -size_t XCollectedHeap::unsafe_max_tlab_alloc(Thread* ignored) const { - return _heap.unsafe_max_tlab_alloc(); -} - -MemoryUsage XCollectedHeap::memory_usage() { - return _heap.serviceability_memory_pool()->get_memory_usage(); -} - -GrowableArray XCollectedHeap::memory_managers() { - GrowableArray memory_managers(2); - memory_managers.append(_heap.serviceability_cycle_memory_manager()); - memory_managers.append(_heap.serviceability_pause_memory_manager()); - return memory_managers; -} - -GrowableArray XCollectedHeap::memory_pools() { - GrowableArray memory_pools(1); - memory_pools.append(_heap.serviceability_memory_pool()); - return memory_pools; -} - -void XCollectedHeap::object_iterate(ObjectClosure* cl) { - _heap.object_iterate(cl, true /* visit_weaks */); -} - -ParallelObjectIteratorImpl* XCollectedHeap::parallel_object_iterator(uint nworkers) { - return _heap.parallel_object_iterator(nworkers, true /* visit_weaks */); -} - -void XCollectedHeap::keep_alive(oop obj) { - _heap.keep_alive(obj); -} - -void XCollectedHeap::register_nmethod(nmethod* nm) { - XNMethod::register_nmethod(nm); -} - -void XCollectedHeap::unregister_nmethod(nmethod* nm) { - XNMethod::unregister_nmethod(nm); -} - -void XCollectedHeap::verify_nmethod(nmethod* nm) { - // Does nothing -} - -WorkerThreads* XCollectedHeap::safepoint_workers() { - return _runtime_workers.workers(); -} - -void XCollectedHeap::gc_threads_do(ThreadClosure* tc) const { - tc->do_thread(_director); - tc->do_thread(_driver); - tc->do_thread(_stat); - _heap.threads_do(tc); - _runtime_workers.threads_do(tc); -} - -VirtualSpaceSummary XCollectedHeap::create_heap_space_summary() { - return VirtualSpaceSummary((HeapWord*)0, (HeapWord*)capacity(), (HeapWord*)max_capacity()); -} - -void XCollectedHeap::safepoint_synchronize_begin() { - StackWatermarkSet::safepoint_synchronize_begin(); - SuspendibleThreadSet::synchronize(); -} - -void XCollectedHeap::safepoint_synchronize_end() { - SuspendibleThreadSet::desynchronize(); -} - -void XCollectedHeap::pin_object(JavaThread* thread, oop obj) { - GCLocker::lock_critical(thread); -} - -void XCollectedHeap::unpin_object(JavaThread* thread, oop obj) { - GCLocker::unlock_critical(thread); -} - -void XCollectedHeap::prepare_for_verify() { - // Does nothing -} - -void XCollectedHeap::print_on(outputStream* st) const { - _heap.print_on(st); -} - -void XCollectedHeap::print_on_error(outputStream* st) const { - st->print_cr("ZGC Globals:"); - st->print_cr(" GlobalPhase: %u (%s)", XGlobalPhase, XGlobalPhaseToString()); - st->print_cr(" GlobalSeqNum: %u", XGlobalSeqNum); - st->print_cr(" Offset Max: " SIZE_FORMAT "%s (" PTR_FORMAT ")", - byte_size_in_exact_unit(XAddressOffsetMax), - exact_unit_for_byte_size(XAddressOffsetMax), - XAddressOffsetMax); - st->print_cr(" Page Size Small: " SIZE_FORMAT "M", XPageSizeSmall / M); - st->print_cr(" Page Size Medium: " SIZE_FORMAT "M", XPageSizeMedium / M); - st->cr(); - st->print_cr("ZGC Metadata Bits:"); - st->print_cr(" Good: " PTR_FORMAT, XAddressGoodMask); - st->print_cr(" Bad: " PTR_FORMAT, XAddressBadMask); - st->print_cr(" WeakBad: " PTR_FORMAT, XAddressWeakBadMask); - st->print_cr(" Marked: " PTR_FORMAT, XAddressMetadataMarked); - st->print_cr(" Remapped: " PTR_FORMAT, XAddressMetadataRemapped); - st->cr(); - CollectedHeap::print_on_error(st); -} - -void XCollectedHeap::print_extended_on(outputStream* st) const { - _heap.print_extended_on(st); -} - -void XCollectedHeap::print_tracing_info() const { - // Does nothing -} - -bool XCollectedHeap::print_location(outputStream* st, void* addr) const { - return _heap.print_location(st, (uintptr_t)addr); -} - -void XCollectedHeap::verify(VerifyOption option /* ignored */) { - _heap.verify(); -} - -bool XCollectedHeap::is_oop(oop object) const { - return _heap.is_oop(XOop::to_address(object)); -} - -bool XCollectedHeap::supports_concurrent_gc_breakpoints() const { - return true; -} diff --git a/src/hotspot/share/gc/x/xCollectedHeap.hpp b/src/hotspot/share/gc/x/xCollectedHeap.hpp deleted file mode 100644 index 250c882d15e2a..0000000000000 --- a/src/hotspot/share/gc/x/xCollectedHeap.hpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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 - * 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_GC_X_XCOLLECTEDHEAP_HPP -#define SHARE_GC_X_XCOLLECTEDHEAP_HPP - -#include "gc/shared/collectedHeap.hpp" -#include "gc/shared/softRefPolicy.hpp" -#include "gc/x/xBarrierSet.hpp" -#include "gc/x/xHeap.hpp" -#include "gc/x/xInitialize.hpp" -#include "gc/x/xRuntimeWorkers.hpp" -#include "memory/metaspace.hpp" -#include "services/memoryUsage.hpp" - -class VMStructs; -class XDirector; -class XDriver; -class XStat; - -class XCollectedHeap : public CollectedHeap { - friend class ::VMStructs; - -private: - XBarrierSet _barrier_set; - XInitialize _initialize; - XHeap _heap; - XDriver* _driver; - XDirector* _director; - XStat* _stat; - XRuntimeWorkers _runtime_workers; - - HeapWord* allocate_new_tlab(size_t min_size, - size_t requested_size, - size_t* actual_size) override; - -public: - static XCollectedHeap* heap(); - - XCollectedHeap(); - Name kind() const override; - const char* name() const override; - jint initialize() override; - void initialize_serviceability() override; - void stop() override; - - size_t max_capacity() const override; - size_t capacity() const override; - size_t used() const override; - size_t unused() const override; - - bool is_maximal_no_gc() const override; - bool is_in(const void* p) const override; - bool requires_barriers(stackChunkOop obj) const override; - - oop array_allocate(Klass* klass, size_t size, int length, bool do_zero, TRAPS) override; - HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; - MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, - size_t size, - Metaspace::MetadataType mdtype) override; - void collect(GCCause::Cause cause) override; - void collect_as_vm_thread(GCCause::Cause cause) override; - void do_full_collection(bool clear_all_soft_refs) override; - - size_t tlab_capacity(Thread* thr) const override; - size_t tlab_used(Thread* thr) const override; - size_t max_tlab_size() const override; - size_t unsafe_max_tlab_alloc(Thread* thr) const override; - - MemoryUsage memory_usage() override; - GrowableArray memory_managers() override; - GrowableArray memory_pools() override; - - void object_iterate(ObjectClosure* cl) override; - ParallelObjectIteratorImpl* parallel_object_iterator(uint nworkers) override; - - void keep_alive(oop obj) override; - - void register_nmethod(nmethod* nm) override; - void unregister_nmethod(nmethod* nm) override; - void verify_nmethod(nmethod* nmethod) override; - - WorkerThreads* safepoint_workers() override; - - void gc_threads_do(ThreadClosure* tc) const override; - - VirtualSpaceSummary create_heap_space_summary() override; - - void safepoint_synchronize_begin() override; - void safepoint_synchronize_end() override; - - void pin_object(JavaThread* thread, oop obj) override; - void unpin_object(JavaThread* thread, oop obj) override; - - void print_on(outputStream* st) const override; - void print_on_error(outputStream* st) const override; - void print_extended_on(outputStream* st) const override; - void print_tracing_info() const override; - bool print_location(outputStream* st, void* addr) const override; - - void prepare_for_verify() override; - void verify(VerifyOption option /* ignored */) override; - bool is_oop(oop object) const override; - bool supports_concurrent_gc_breakpoints() const override; -}; - -#endif // SHARE_GC_X_XCOLLECTEDHEAP_HPP diff --git a/src/hotspot/share/gc/x/xDebug.gdb b/src/hotspot/share/gc/x/xDebug.gdb deleted file mode 100644 index 2dbf578b07bc3..0000000000000 --- a/src/hotspot/share/gc/x/xDebug.gdb +++ /dev/null @@ -1,148 +0,0 @@ -# -# GDB functions for debugging the Z Garbage Collector -# - -printf "Loading zDebug.gdb\n" - -# Print Klass* -define zpk - printf "Klass: %s\n", (char*)((Klass*)($arg0))->_name->_body -end - -# Print oop -define zpo - set $obj = (oopDesc*)($arg0) - - printf "Oop: 0x%016llx\tState: ", (uintptr_t)$obj - if ((uintptr_t)$obj & (uintptr_t)XAddressGoodMask) - printf "Good " - if ((uintptr_t)$obj & (uintptr_t)XAddressMetadataRemapped) - printf "(Remapped)" - else - if ((uintptr_t)$obj & (uintptr_t)XAddressMetadataMarked) - printf "(Marked)" - else - printf "(Unknown)" - end - end - else - printf "Bad " - if ((uintptr_t)XAddressGoodMask & (uintptr_t)XAddressMetadataMarked) - # Should be marked - if ((uintptr_t)$obj & (uintptr_t)XAddressMetadataRemapped) - printf "(Not Marked, Remapped)" - else - printf "(Not Marked, Not Remapped)" - end - else - if ((uintptr_t)XAddressGoodMask & (uintptr_t)XAddressMetadataRemapped) - # Should be remapped - if ((uintptr_t)$obj & (uintptr_t)XAddressMetadataMarked) - printf "(Marked, Not Remapped)" - else - printf "(Not Marked, Not Remapped)" - end - else - # Unknown - printf "(Unknown)" - end - end - end - printf "\t Page: %llu\n", ((uintptr_t)$obj & XAddressOffsetMask) >> XGranuleSizeShift - x/16gx $obj - if (UseCompressedClassPointers) - set $klass = (Klass*)(void*)((uintptr_t)CompressedKlassPointers::_base +((uintptr_t)$obj->_metadata->_compressed_klass << CompressedKlassPointers::_shift)) - else - set $klass = $obj->_metadata->_klass - end - printf "Mark: 0x%016llx\tKlass: %s\n", (uintptr_t)$obj->_mark, (char*)$klass->_name->_body -end - -# Print heap page by page table index -define zpp - set $page = (XPage*)((uintptr_t)XHeap::_heap._page_table._map._map[($arg0)] & ~1) - printf "Page %p\n", $page - print *$page -end - -# Print page_table -define zpt - printf "Pagetable (first 128 slots)\n" - x/128gx XHeap::_heap._page_table._map._map -end - -# Print live map -define __zmarked - set $livemap = $arg0 - set $bit = $arg1 - set $size = $livemap._bitmap._size - set $segment = $size / XLiveMap::nsegments - set $segment_bit = 1 << $segment - - printf "Segment is " - if !($livemap._segment_live_bits & $segment_bit) - printf "NOT " - end - printf "live (segment %d)\n", $segment - - if $bit >= $size - print "Error: Bit %z out of bounds (bitmap size %z)\n", $bit, $size - else - set $word_index = $bit / 64 - set $bit_index = $bit % 64 - set $word = $livemap._bitmap._map[$word_index] - set $live_bit = $word & (1 << $bit_index) - - printf "Object is " - if $live_bit == 0 - printf "NOT " - end - printf "live (word index %d, bit index %d)\n", $word_index, $bit_index - end -end - -define zmarked - set $addr = $arg0 - set $obj = ((uintptr_t)$addr & XAddressOffsetMask) - set $page_index = $obj >> XGranuleSizeShift - set $page_entry = (uintptr_t)XHeap::_heap._page_table._map._map[$page_index] - set $page = (XPage*)($page_entry & ~1) - set $page_start = (uintptr_t)$page._virtual._start - set $page_end = (uintptr_t)$page._virtual._end - set $page_seqnum = $page._livemap._seqnum - set $global_seqnum = XGlobalSeqNum - - if $obj < $page_start || $obj >= $page_end - printf "Error: %p not in page %p (start %p, end %p)\n", $obj, $page, $page_start, $page_end - else - printf "Page is " - if $page_seqnum != $global_seqnum - printf "NOT " - end - printf "live (page %p, page seqnum %d, global seqnum %d)\n", $page, $page_seqnum, $global_seqnum - - #if $page_seqnum == $global_seqnum - set $offset = $obj - $page_start - set $bit = $offset / 8 - __zmarked $page._livemap $bit - #end - end -end - -# Print heap information -define zph - printf "Heap\n" - printf " GlobalPhase: %u\n", XGlobalPhase - printf " GlobalSeqNum: %u\n", XGlobalSeqNum - printf " Offset Max: %-15llu (0x%llx)\n", XAddressOffsetMax, XAddressOffsetMax - printf " Page Size Small: %-15llu (0x%llx)\n", XPageSizeSmall, XPageSizeSmall - printf " Page Size Medium: %-15llu (0x%llx)\n", XPageSizeMedium, XPageSizeMedium - printf "Metadata Bits\n" - printf " Good: 0x%016llx\n", XAddressGoodMask - printf " Bad: 0x%016llx\n", XAddressBadMask - printf " WeakBad: 0x%016llx\n", XAddressWeakBadMask - printf " Marked: 0x%016llx\n", XAddressMetadataMarked - printf " Remapped: 0x%016llx\n", XAddressMetadataRemapped -end - -# End of file diff --git a/src/hotspot/share/gc/x/xDirector.cpp b/src/hotspot/share/gc/x/xDirector.cpp deleted file mode 100644 index e1c69bd05b7de..0000000000000 --- a/src/hotspot/share/gc/x/xDirector.cpp +++ /dev/null @@ -1,406 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xDirector.hpp" -#include "gc/x/xDriver.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xHeuristics.hpp" -#include "gc/x/xStat.hpp" -#include "logging/log.hpp" - -constexpr double one_in_1000 = 3.290527; -constexpr double sample_interval = 1.0 / XStatAllocRate::sample_hz; - -XDirector::XDirector(XDriver* driver) : - _driver(driver), - _metronome(XStatAllocRate::sample_hz) { - set_name("XDirector"); - create_and_start(); -} - -static void sample_allocation_rate() { - // Sample allocation rate. This is needed by rule_allocation_rate() - // below to estimate the time we have until we run out of memory. - const double bytes_per_second = XStatAllocRate::sample_and_reset(); - - log_debug(gc, alloc)("Allocation Rate: %.1fMB/s, Predicted: %.1fMB/s, Avg: %.1f(+/-%.1f)MB/s", - bytes_per_second / M, - XStatAllocRate::predict() / M, - XStatAllocRate::avg() / M, - XStatAllocRate::sd() / M); -} - -static XDriverRequest rule_allocation_stall() { - // Perform GC if we've observed at least one allocation stall since - // the last GC started. - if (!XHeap::heap()->has_alloc_stalled()) { - return GCCause::_no_gc; - } - - log_debug(gc, director)("Rule: Allocation Stall Observed"); - - return GCCause::_z_allocation_stall; -} - -static XDriverRequest rule_warmup() { - if (XStatCycle::is_warm()) { - // Rule disabled - return GCCause::_no_gc; - } - - // Perform GC if heap usage passes 10/20/30% and no other GC has been - // performed yet. This allows us to get some early samples of the GC - // duration, which is needed by the other rules. - const size_t soft_max_capacity = XHeap::heap()->soft_max_capacity(); - const size_t used = XHeap::heap()->used(); - const double used_threshold_percent = (XStatCycle::nwarmup_cycles() + 1) * 0.1; - const size_t used_threshold = soft_max_capacity * used_threshold_percent; - - log_debug(gc, director)("Rule: Warmup %.0f%%, Used: " SIZE_FORMAT "MB, UsedThreshold: " SIZE_FORMAT "MB", - used_threshold_percent * 100, used / M, used_threshold / M); - - if (used < used_threshold) { - return GCCause::_no_gc; - } - - return GCCause::_z_warmup; -} - -static XDriverRequest rule_timer() { - if (ZCollectionInterval <= 0) { - // Rule disabled - return GCCause::_no_gc; - } - - // Perform GC if timer has expired. - const double time_since_last_gc = XStatCycle::time_since_last(); - const double time_until_gc = ZCollectionInterval - time_since_last_gc; - - log_debug(gc, director)("Rule: Timer, Interval: %.3fs, TimeUntilGC: %.3fs", - ZCollectionInterval, time_until_gc); - - if (time_until_gc > 0) { - return GCCause::_no_gc; - } - - return GCCause::_z_timer; -} - -static double estimated_gc_workers(double serial_gc_time, double parallelizable_gc_time, double time_until_deadline) { - const double parallelizable_time_until_deadline = MAX2(time_until_deadline - serial_gc_time, 0.001); - return parallelizable_gc_time / parallelizable_time_until_deadline; -} - -static uint discrete_gc_workers(double gc_workers) { - return clamp(ceil(gc_workers), 1, ConcGCThreads); -} - -static double select_gc_workers(double serial_gc_time, double parallelizable_gc_time, double alloc_rate_sd_percent, double time_until_oom) { - // Use all workers until we're warm - if (!XStatCycle::is_warm()) { - const double not_warm_gc_workers = ConcGCThreads; - log_debug(gc, director)("Select GC Workers (Not Warm), GCWorkers: %.3f", not_warm_gc_workers); - return not_warm_gc_workers; - } - - // Calculate number of GC workers needed to avoid a long GC cycle and to avoid OOM. - const double avoid_long_gc_workers = estimated_gc_workers(serial_gc_time, parallelizable_gc_time, 10 /* seconds */); - const double avoid_oom_gc_workers = estimated_gc_workers(serial_gc_time, parallelizable_gc_time, time_until_oom); - - const double gc_workers = MAX2(avoid_long_gc_workers, avoid_oom_gc_workers); - const uint actual_gc_workers = discrete_gc_workers(gc_workers); - const uint last_gc_workers = XStatCycle::last_active_workers(); - - // More than 15% division from the average is considered unsteady - if (alloc_rate_sd_percent >= 0.15) { - const double half_gc_workers = ConcGCThreads / 2.0; - const double unsteady_gc_workers = MAX3(gc_workers, last_gc_workers, half_gc_workers); - log_debug(gc, director)("Select GC Workers (Unsteady), " - "AvoidLongGCWorkers: %.3f, AvoidOOMGCWorkers: %.3f, LastGCWorkers: %.3f, HalfGCWorkers: %.3f, GCWorkers: %.3f", - avoid_long_gc_workers, avoid_oom_gc_workers, (double)last_gc_workers, half_gc_workers, unsteady_gc_workers); - return unsteady_gc_workers; - } - - if (actual_gc_workers < last_gc_workers) { - // Before decreasing number of GC workers compared to the previous GC cycle, check if the - // next GC cycle will need to increase it again. If so, use the same number of GC workers - // that will be needed in the next cycle. - const double gc_duration_delta = (parallelizable_gc_time / actual_gc_workers) - (parallelizable_gc_time / last_gc_workers); - const double additional_time_for_allocations = XStatCycle::time_since_last() - gc_duration_delta - sample_interval; - const double next_time_until_oom = time_until_oom + additional_time_for_allocations; - const double next_avoid_oom_gc_workers = estimated_gc_workers(serial_gc_time, parallelizable_gc_time, next_time_until_oom); - - // Add 0.5 to increase friction and avoid lowering too eagerly - const double next_gc_workers = next_avoid_oom_gc_workers + 0.5; - const double try_lowering_gc_workers = clamp(next_gc_workers, actual_gc_workers, last_gc_workers); - - log_debug(gc, director)("Select GC Workers (Try Lowering), " - "AvoidLongGCWorkers: %.3f, AvoidOOMGCWorkers: %.3f, NextAvoidOOMGCWorkers: %.3f, LastGCWorkers: %.3f, GCWorkers: %.3f", - avoid_long_gc_workers, avoid_oom_gc_workers, next_avoid_oom_gc_workers, (double)last_gc_workers, try_lowering_gc_workers); - return try_lowering_gc_workers; - } - - log_debug(gc, director)("Select GC Workers (Normal), " - "AvoidLongGCWorkers: %.3f, AvoidOOMGCWorkers: %.3f, LastGCWorkers: %.3f, GCWorkers: %.3f", - avoid_long_gc_workers, avoid_oom_gc_workers, (double)last_gc_workers, gc_workers); - return gc_workers; -} - -static XDriverRequest rule_allocation_rate_dynamic() { - if (!XStatCycle::is_time_trustable()) { - // Rule disabled - return GCCause::_no_gc; - } - - // Calculate amount of free memory available. Note that we take the - // relocation headroom into account to avoid in-place relocation. - const size_t soft_max_capacity = XHeap::heap()->soft_max_capacity(); - const size_t used = XHeap::heap()->used(); - const size_t free_including_headroom = soft_max_capacity - MIN2(soft_max_capacity, used); - const size_t free = free_including_headroom - MIN2(free_including_headroom, XHeuristics::relocation_headroom()); - - // Calculate time until OOM given the max allocation rate and the amount - // of free memory. The allocation rate is a moving average and we multiply - // that with an allocation spike tolerance factor to guard against unforeseen - // phase changes in the allocate rate. We then add ~3.3 sigma to account for - // the allocation rate variance, which means the probability is 1 in 1000 - // that a sample is outside of the confidence interval. - const double alloc_rate_predict = XStatAllocRate::predict(); - const double alloc_rate_avg = XStatAllocRate::avg(); - const double alloc_rate_sd = XStatAllocRate::sd(); - const double alloc_rate_sd_percent = alloc_rate_sd / (alloc_rate_avg + 1.0); - const double alloc_rate = (MAX2(alloc_rate_predict, alloc_rate_avg) * ZAllocationSpikeTolerance) + (alloc_rate_sd * one_in_1000) + 1.0; - const double time_until_oom = (free / alloc_rate) / (1.0 + alloc_rate_sd_percent); - - // Calculate max serial/parallel times of a GC cycle. The times are - // moving averages, we add ~3.3 sigma to account for the variance. - const double serial_gc_time = XStatCycle::serial_time().davg() + (XStatCycle::serial_time().dsd() * one_in_1000); - const double parallelizable_gc_time = XStatCycle::parallelizable_time().davg() + (XStatCycle::parallelizable_time().dsd() * one_in_1000); - - // Calculate number of GC workers needed to avoid OOM. - const double gc_workers = select_gc_workers(serial_gc_time, parallelizable_gc_time, alloc_rate_sd_percent, time_until_oom); - - // Convert to a discrete number of GC workers within limits. - const uint actual_gc_workers = discrete_gc_workers(gc_workers); - - // Calculate GC duration given number of GC workers needed. - const double actual_gc_duration = serial_gc_time + (parallelizable_gc_time / actual_gc_workers); - const uint last_gc_workers = XStatCycle::last_active_workers(); - - // Calculate time until GC given the time until OOM and GC duration. - // We also subtract the sample interval, so that we don't overshoot the - // target time and end up starting the GC too late in the next interval. - const double time_until_gc = time_until_oom - actual_gc_duration - sample_interval; - - log_debug(gc, director)("Rule: Allocation Rate (Dynamic GC Workers), " - "MaxAllocRate: %.1fMB/s (+/-%.1f%%), Free: " SIZE_FORMAT "MB, GCCPUTime: %.3f, " - "GCDuration: %.3fs, TimeUntilOOM: %.3fs, TimeUntilGC: %.3fs, GCWorkers: %u -> %u", - alloc_rate / M, - alloc_rate_sd_percent * 100, - free / M, - serial_gc_time + parallelizable_gc_time, - serial_gc_time + (parallelizable_gc_time / actual_gc_workers), - time_until_oom, - time_until_gc, - last_gc_workers, - actual_gc_workers); - - if (actual_gc_workers <= last_gc_workers && time_until_gc > 0) { - return XDriverRequest(GCCause::_no_gc, actual_gc_workers); - } - - return XDriverRequest(GCCause::_z_allocation_rate, actual_gc_workers); -} - -static XDriverRequest rule_allocation_rate_static() { - if (!XStatCycle::is_time_trustable()) { - // Rule disabled - return GCCause::_no_gc; - } - - // Perform GC if the estimated max allocation rate indicates that we - // will run out of memory. The estimated max allocation rate is based - // on the moving average of the sampled allocation rate plus a safety - // margin based on variations in the allocation rate and unforeseen - // allocation spikes. - - // Calculate amount of free memory available. Note that we take the - // relocation headroom into account to avoid in-place relocation. - const size_t soft_max_capacity = XHeap::heap()->soft_max_capacity(); - const size_t used = XHeap::heap()->used(); - const size_t free_including_headroom = soft_max_capacity - MIN2(soft_max_capacity, used); - const size_t free = free_including_headroom - MIN2(free_including_headroom, XHeuristics::relocation_headroom()); - - // Calculate time until OOM given the max allocation rate and the amount - // of free memory. The allocation rate is a moving average and we multiply - // that with an allocation spike tolerance factor to guard against unforeseen - // phase changes in the allocate rate. We then add ~3.3 sigma to account for - // the allocation rate variance, which means the probability is 1 in 1000 - // that a sample is outside of the confidence interval. - const double max_alloc_rate = (XStatAllocRate::avg() * ZAllocationSpikeTolerance) + (XStatAllocRate::sd() * one_in_1000); - const double time_until_oom = free / (max_alloc_rate + 1.0); // Plus 1.0B/s to avoid division by zero - - // Calculate max serial/parallel times of a GC cycle. The times are - // moving averages, we add ~3.3 sigma to account for the variance. - const double serial_gc_time = XStatCycle::serial_time().davg() + (XStatCycle::serial_time().dsd() * one_in_1000); - const double parallelizable_gc_time = XStatCycle::parallelizable_time().davg() + (XStatCycle::parallelizable_time().dsd() * one_in_1000); - - // Calculate GC duration given number of GC workers needed. - const double gc_duration = serial_gc_time + (parallelizable_gc_time / ConcGCThreads); - - // Calculate time until GC given the time until OOM and max duration of GC. - // We also deduct the sample interval, so that we don't overshoot the target - // time and end up starting the GC too late in the next interval. - const double time_until_gc = time_until_oom - gc_duration - sample_interval; - - log_debug(gc, director)("Rule: Allocation Rate (Static GC Workers), MaxAllocRate: %.1fMB/s, Free: " SIZE_FORMAT "MB, GCDuration: %.3fs, TimeUntilGC: %.3fs", - max_alloc_rate / M, free / M, gc_duration, time_until_gc); - - if (time_until_gc > 0) { - return GCCause::_no_gc; - } - - return GCCause::_z_allocation_rate; -} - -static XDriverRequest rule_allocation_rate() { - if (UseDynamicNumberOfGCThreads) { - return rule_allocation_rate_dynamic(); - } else { - return rule_allocation_rate_static(); - } -} - -static XDriverRequest rule_high_usage() { - // Perform GC if the amount of free memory is 5% or less. This is a preventive - // meassure in the case where the application has a very low allocation rate, - // such that the allocation rate rule doesn't trigger, but the amount of free - // memory is still slowly but surely heading towards zero. In this situation, - // we start a GC cycle to avoid a potential allocation stall later. - - // Calculate amount of free memory available. Note that we take the - // relocation headroom into account to avoid in-place relocation. - const size_t soft_max_capacity = XHeap::heap()->soft_max_capacity(); - const size_t used = XHeap::heap()->used(); - const size_t free_including_headroom = soft_max_capacity - MIN2(soft_max_capacity, used); - const size_t free = free_including_headroom - MIN2(free_including_headroom, XHeuristics::relocation_headroom()); - const double free_percent = percent_of(free, soft_max_capacity); - - log_debug(gc, director)("Rule: High Usage, Free: " SIZE_FORMAT "MB(%.1f%%)", - free / M, free_percent); - - if (free_percent > 5.0) { - return GCCause::_no_gc; - } - - return GCCause::_z_high_usage; -} - -static XDriverRequest rule_proactive() { - if (!ZProactive || !XStatCycle::is_warm()) { - // Rule disabled - return GCCause::_no_gc; - } - - // Perform GC if the impact of doing so, in terms of application throughput - // reduction, is considered acceptable. This rule allows us to keep the heap - // size down and allow reference processing to happen even when we have a lot - // of free space on the heap. - - // Only consider doing a proactive GC if the heap usage has grown by at least - // 10% of the max capacity since the previous GC, or more than 5 minutes has - // passed since the previous GC. This helps avoid superfluous GCs when running - // applications with very low allocation rate. - const size_t used_after_last_gc = XStatHeap::used_at_relocate_end(); - const size_t used_increase_threshold = XHeap::heap()->soft_max_capacity() * 0.10; // 10% - const size_t used_threshold = used_after_last_gc + used_increase_threshold; - const size_t used = XHeap::heap()->used(); - const double time_since_last_gc = XStatCycle::time_since_last(); - const double time_since_last_gc_threshold = 5 * 60; // 5 minutes - if (used < used_threshold && time_since_last_gc < time_since_last_gc_threshold) { - // Don't even consider doing a proactive GC - log_debug(gc, director)("Rule: Proactive, UsedUntilEnabled: " SIZE_FORMAT "MB, TimeUntilEnabled: %.3fs", - (used_threshold - used) / M, - time_since_last_gc_threshold - time_since_last_gc); - return GCCause::_no_gc; - } - - const double assumed_throughput_drop_during_gc = 0.50; // 50% - const double acceptable_throughput_drop = 0.01; // 1% - const double serial_gc_time = XStatCycle::serial_time().davg() + (XStatCycle::serial_time().dsd() * one_in_1000); - const double parallelizable_gc_time = XStatCycle::parallelizable_time().davg() + (XStatCycle::parallelizable_time().dsd() * one_in_1000); - const double gc_duration = serial_gc_time + (parallelizable_gc_time / ConcGCThreads); - const double acceptable_gc_interval = gc_duration * ((assumed_throughput_drop_during_gc / acceptable_throughput_drop) - 1.0); - const double time_until_gc = acceptable_gc_interval - time_since_last_gc; - - log_debug(gc, director)("Rule: Proactive, AcceptableGCInterval: %.3fs, TimeSinceLastGC: %.3fs, TimeUntilGC: %.3fs", - acceptable_gc_interval, time_since_last_gc, time_until_gc); - - if (time_until_gc > 0) { - return GCCause::_no_gc; - } - - return GCCause::_z_proactive; -} - -static XDriverRequest make_gc_decision() { - // List of rules - using XDirectorRule = XDriverRequest (*)(); - const XDirectorRule rules[] = { - rule_allocation_stall, - rule_warmup, - rule_timer, - rule_allocation_rate, - rule_high_usage, - rule_proactive, - }; - - // Execute rules - for (size_t i = 0; i < ARRAY_SIZE(rules); i++) { - const XDriverRequest request = rules[i](); - if (request.cause() != GCCause::_no_gc) { - return request; - } - } - - return GCCause::_no_gc; -} - -void XDirector::run_service() { - // Main loop - while (_metronome.wait_for_tick()) { - sample_allocation_rate(); - if (!_driver->is_busy()) { - const XDriverRequest request = make_gc_decision(); - if (request.cause() != GCCause::_no_gc) { - _driver->collect(request); - } - } - } -} - -void XDirector::stop_service() { - _metronome.stop(); -} diff --git a/src/hotspot/share/gc/x/xDirector.hpp b/src/hotspot/share/gc/x/xDirector.hpp deleted file mode 100644 index eacce20e8c9c6..0000000000000 --- a/src/hotspot/share/gc/x/xDirector.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XDIRECTOR_HPP -#define SHARE_GC_X_XDIRECTOR_HPP - -#include "gc/shared/concurrentGCThread.hpp" -#include "gc/x/xMetronome.hpp" - -class XDriver; - -class XDirector : public ConcurrentGCThread { -private: - XDriver* const _driver; - XMetronome _metronome; - -protected: - virtual void run_service(); - virtual void stop_service(); - -public: - XDirector(XDriver* driver); -}; - -#endif // SHARE_GC_X_XDIRECTOR_HPP diff --git a/src/hotspot/share/gc/x/xDriver.cpp b/src/hotspot/share/gc/x/xDriver.cpp deleted file mode 100644 index 3e6fd03134e12..0000000000000 --- a/src/hotspot/share/gc/x/xDriver.cpp +++ /dev/null @@ -1,518 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcId.hpp" -#include "gc/shared/gcLocker.hpp" -#include "gc/shared/gcVMOperations.hpp" -#include "gc/shared/isGCActiveMark.hpp" -#include "gc/x/xAbort.inline.hpp" -#include "gc/x/xBreakpoint.hpp" -#include "gc/x/xCollectedHeap.hpp" -#include "gc/x/xDriver.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xMessagePort.inline.hpp" -#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" -#include "runtime/vmOperations.hpp" -#include "runtime/vmThread.hpp" - -static const XStatPhaseCycle XPhaseCycle("Garbage Collection Cycle"); -static const XStatPhasePause XPhasePauseMarkStart("Pause Mark Start"); -static const XStatPhaseConcurrent XPhaseConcurrentMark("Concurrent Mark"); -static const XStatPhaseConcurrent XPhaseConcurrentMarkContinue("Concurrent Mark Continue"); -static const XStatPhaseConcurrent XPhaseConcurrentMarkFree("Concurrent Mark Free"); -static const XStatPhasePause XPhasePauseMarkEnd("Pause Mark End"); -static const XStatPhaseConcurrent XPhaseConcurrentProcessNonStrongReferences("Concurrent Process Non-Strong References"); -static const XStatPhaseConcurrent XPhaseConcurrentResetRelocationSet("Concurrent Reset Relocation Set"); -static const XStatPhaseConcurrent XPhaseConcurrentSelectRelocationSet("Concurrent Select Relocation Set"); -static const XStatPhasePause XPhasePauseRelocateStart("Pause Relocate Start"); -static const XStatPhaseConcurrent XPhaseConcurrentRelocated("Concurrent Relocate"); -static const XStatCriticalPhase XCriticalPhaseGCLockerStall("GC Locker Stall", false /* verbose */); -static const XStatSampler XSamplerJavaThreads("System", "Java Threads", XStatUnitThreads); - -XDriverRequest::XDriverRequest() : - XDriverRequest(GCCause::_no_gc) {} - -XDriverRequest::XDriverRequest(GCCause::Cause cause) : - XDriverRequest(cause, ConcGCThreads) {} - -XDriverRequest::XDriverRequest(GCCause::Cause cause, uint nworkers) : - _cause(cause), - _nworkers(nworkers) {} - -bool XDriverRequest::operator==(const XDriverRequest& other) const { - return _cause == other._cause; -} - -GCCause::Cause XDriverRequest::cause() const { - return _cause; -} - -uint XDriverRequest::nworkers() const { - return _nworkers; -} - -class VM_XOperation : public VM_Operation { -private: - const uint _gc_id; - bool _gc_locked; - bool _success; - -public: - VM_XOperation() : - _gc_id(GCId::current()), - _gc_locked(false), - _success(false) {} - - virtual bool needs_inactive_gc_locker() const { - // An inactive GC locker is needed in operations where we change the bad - // mask or move objects. Changing the bad mask will invalidate all oops, - // which makes it conceptually the same thing as moving all objects. - return false; - } - - virtual bool skip_thread_oop_barriers() const { - return true; - } - - virtual bool do_operation() = 0; - - virtual bool doit_prologue() { - Heap_lock->lock(); - return true; - } - - virtual void doit() { - // Abort if GC locker state is incompatible - if (needs_inactive_gc_locker() && GCLocker::check_active_before_gc()) { - _gc_locked = true; - return; - } - - // Setup GC id and active marker - GCIdMark gc_id_mark(_gc_id); - IsSTWGCActiveMark gc_active_mark; - - // Verify before operation - XVerify::before_zoperation(); - - // Execute operation - _success = do_operation(); - - // Update statistics - XStatSample(XSamplerJavaThreads, Threads::number_of_threads()); - } - - 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 { - return _gc_locked; - } - - bool success() const { - return _success; - } -}; - -class VM_XMarkStart : public VM_XOperation { -public: - virtual VMOp_Type type() const { - return VMOp_XMarkStart; - } - - virtual bool needs_inactive_gc_locker() const { - return true; - } - - virtual bool do_operation() { - XStatTimer timer(XPhasePauseMarkStart); - XServiceabilityPauseTracer tracer; - - XCollectedHeap::heap()->increment_total_collections(true /* full */); - - XHeap::heap()->mark_start(); - return true; - } -}; - -class VM_XMarkEnd : public VM_XOperation { -public: - virtual VMOp_Type type() const { - return VMOp_XMarkEnd; - } - - virtual bool do_operation() { - XStatTimer timer(XPhasePauseMarkEnd); - XServiceabilityPauseTracer tracer; - return XHeap::heap()->mark_end(); - } -}; - -class VM_XRelocateStart : public VM_XOperation { -public: - virtual VMOp_Type type() const { - return VMOp_XRelocateStart; - } - - virtual bool needs_inactive_gc_locker() const { - return true; - } - - virtual bool do_operation() { - XStatTimer timer(XPhasePauseRelocateStart); - XServiceabilityPauseTracer tracer; - XHeap::heap()->relocate_start(); - return true; - } -}; - -class VM_XVerify : public VM_Operation { -public: - virtual VMOp_Type type() const { - return VMOp_XVerify; - } - - virtual bool skip_thread_oop_barriers() const { - return true; - } - - virtual void doit() { - XVerify::after_weak_processing(); - } -}; - -XDriver::XDriver() : - _gc_cycle_port(), - _gc_locker_port() { - set_name("XDriver"); - create_and_start(); -} - -bool XDriver::is_busy() const { - return _gc_cycle_port.is_busy(); -} - -void XDriver::collect(const XDriverRequest& request) { - switch (request.cause()) { - case GCCause::_heap_dump: - case GCCause::_heap_inspection: - case GCCause::_wb_young_gc: - case GCCause::_wb_full_gc: - case GCCause::_dcmd_gc_run: - case GCCause::_java_lang_system_gc: - case GCCause::_full_gc_alot: - case GCCause::_scavenge_alot: - case GCCause::_jvmti_force_gc: - case GCCause::_metadata_GC_clear_soft_refs: - case GCCause::_codecache_GC_aggressive: - // Start synchronous GC - _gc_cycle_port.send_sync(request); - break; - - case GCCause::_z_timer: - case GCCause::_z_warmup: - case GCCause::_z_allocation_rate: - case GCCause::_z_allocation_stall: - case GCCause::_z_proactive: - case GCCause::_z_high_usage: - case GCCause::_codecache_GC_threshold: - case GCCause::_metadata_GC_threshold: - // Start asynchronous GC - _gc_cycle_port.send_async(request); - break; - - case GCCause::_gc_locker: - // Restart VM operation previously blocked by the GC locker - _gc_locker_port.signal(); - break; - - case GCCause::_wb_breakpoint: - XBreakpoint::start_gc(); - _gc_cycle_port.send_async(request); - break; - - default: - // Other causes not supported - fatal("Unsupported GC cause (%s)", GCCause::to_string(request.cause())); - break; - } -} - -template -bool XDriver::pause() { - for (;;) { - T op; - VMThread::execute(&op); - if (op.gc_locked()) { - // Wait for GC to become unlocked and restart the VM operation - XStatTimer timer(XCriticalPhaseGCLockerStall); - _gc_locker_port.wait(); - continue; - } - - // Notify VM operation completed - _gc_locker_port.ack(); - - return op.success(); - } -} - -void XDriver::pause_mark_start() { - pause(); -} - -void XDriver::concurrent_mark() { - XStatTimer timer(XPhaseConcurrentMark); - XBreakpoint::at_after_marking_started(); - XHeap::heap()->mark(true /* initial */); - XBreakpoint::at_before_marking_completed(); -} - -bool XDriver::pause_mark_end() { - return pause(); -} - -void XDriver::concurrent_mark_continue() { - XStatTimer timer(XPhaseConcurrentMarkContinue); - XHeap::heap()->mark(false /* initial */); -} - -void XDriver::concurrent_mark_free() { - XStatTimer timer(XPhaseConcurrentMarkFree); - XHeap::heap()->mark_free(); -} - -void XDriver::concurrent_process_non_strong_references() { - XStatTimer timer(XPhaseConcurrentProcessNonStrongReferences); - XBreakpoint::at_after_reference_processing_started(); - XHeap::heap()->process_non_strong_references(); -} - -void XDriver::concurrent_reset_relocation_set() { - XStatTimer timer(XPhaseConcurrentResetRelocationSet); - XHeap::heap()->reset_relocation_set(); -} - -void XDriver::pause_verify() { - if (ZVerifyRoots || ZVerifyObjects) { - VM_XVerify op; - VMThread::execute(&op); - } -} - -void XDriver::concurrent_select_relocation_set() { - XStatTimer timer(XPhaseConcurrentSelectRelocationSet); - XHeap::heap()->select_relocation_set(); -} - -void XDriver::pause_relocate_start() { - pause(); -} - -void XDriver::concurrent_relocate() { - XStatTimer timer(XPhaseConcurrentRelocated); - XHeap::heap()->relocate(); -} - -void XDriver::check_out_of_memory() { - XHeap::heap()->check_out_of_memory(); -} - -static bool should_clear_soft_references(const XDriverRequest& request) { - // Clear soft references if implied by the GC cause - if (request.cause() == GCCause::_wb_full_gc || - request.cause() == GCCause::_metadata_GC_clear_soft_refs || - request.cause() == GCCause::_z_allocation_stall) { - // Clear - return true; - } - - // Don't clear - return false; -} - -static uint select_active_worker_threads_dynamic(const XDriverRequest& request) { - // Use requested number of worker threads - return request.nworkers(); -} - -static uint select_active_worker_threads_static(const XDriverRequest& request) { - const GCCause::Cause cause = request.cause(); - const uint nworkers = request.nworkers(); - - // Boost number of worker threads if implied by the GC cause - if (cause == GCCause::_wb_full_gc || - cause == GCCause::_java_lang_system_gc || - cause == GCCause::_metadata_GC_clear_soft_refs || - cause == GCCause::_z_allocation_stall) { - // Boost - const uint boosted_nworkers = MAX2(nworkers, ParallelGCThreads); - return boosted_nworkers; - } - - // Use requested number of worker threads - return nworkers; -} - -static uint select_active_worker_threads(const XDriverRequest& request) { - if (UseDynamicNumberOfGCThreads) { - return select_active_worker_threads_dynamic(request); - } else { - return select_active_worker_threads_static(request); - } -} - -class XDriverGCScope : public StackObj { -private: - GCIdMark _gc_id; - GCCause::Cause _gc_cause; - GCCauseSetter _gc_cause_setter; - XStatTimer _timer; - XServiceabilityCycleTracer _tracer; - -public: - XDriverGCScope(const XDriverRequest& request) : - _gc_id(), - _gc_cause(request.cause()), - _gc_cause_setter(XCollectedHeap::heap(), _gc_cause), - _timer(XPhaseCycle), - _tracer() { - // Update statistics - XStatCycle::at_start(); - - // Set up soft reference policy - const bool clear = should_clear_soft_references(request); - XHeap::heap()->set_soft_reference_policy(clear); - - // Select number of worker threads to use - const uint nworkers = select_active_worker_threads(request); - XHeap::heap()->set_active_workers(nworkers); - } - - ~XDriverGCScope() { - // Update statistics - XStatCycle::at_end(_gc_cause, XHeap::heap()->active_workers()); - - // Update data used by soft reference policy - Universe::heap()->update_capacity_and_used_at_gc(); - - // Signal that we have completed a visit to all live objects - Universe::heap()->record_whole_heap_examined_timestamp(); - } -}; - -// Macro to execute a termination check after a concurrent phase. Note -// that it's important that the termination check comes after the call -// to the function f, since we can't abort between pause_relocate_start() -// and concurrent_relocate(). We need to let concurrent_relocate() call -// abort_page() on the remaining entries in the relocation set. -#define concurrent(f) \ - do { \ - concurrent_##f(); \ - if (should_terminate()) { \ - return; \ - } \ - } while (false) - -void XDriver::gc(const XDriverRequest& request) { - XDriverGCScope scope(request); - - // Phase 1: Pause Mark Start - pause_mark_start(); - - // Phase 2: Concurrent Mark - concurrent(mark); - - // Phase 3: Pause Mark End - while (!pause_mark_end()) { - // Phase 3.5: Concurrent Mark Continue - concurrent(mark_continue); - } - - // Phase 4: Concurrent Mark Free - concurrent(mark_free); - - // Phase 5: Concurrent Process Non-Strong References - concurrent(process_non_strong_references); - - // Phase 6: Concurrent Reset Relocation Set - concurrent(reset_relocation_set); - - // Phase 7: Pause Verify - pause_verify(); - - // Phase 8: Concurrent Select Relocation Set - concurrent(select_relocation_set); - - // Phase 9: Pause Relocate Start - pause_relocate_start(); - - // Phase 10: Concurrent Relocate - concurrent(relocate); -} - -void XDriver::run_service() { - // Main loop - while (!should_terminate()) { - // Wait for GC request - const XDriverRequest request = _gc_cycle_port.receive(); - if (request.cause() == GCCause::_no_gc) { - continue; - } - - XBreakpoint::at_before_gc(); - - // Run GC - gc(request); - - if (should_terminate()) { - // Abort - break; - } - - // Notify GC completed - _gc_cycle_port.ack(); - - // Check for out of memory condition - check_out_of_memory(); - - XBreakpoint::at_after_gc(); - } -} - -void XDriver::stop_service() { - XAbort::abort(); - _gc_cycle_port.send_async(GCCause::_no_gc); -} diff --git a/src/hotspot/share/gc/x/xDriver.hpp b/src/hotspot/share/gc/x/xDriver.hpp deleted file mode 100644 index 3803b699b85df..0000000000000 --- a/src/hotspot/share/gc/x/xDriver.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XDRIVER_HPP -#define SHARE_GC_X_XDRIVER_HPP - -#include "gc/shared/concurrentGCThread.hpp" -#include "gc/shared/gcCause.hpp" -#include "gc/x/xMessagePort.hpp" - -class VM_XOperation; - -class XDriverRequest { -private: - GCCause::Cause _cause; - uint _nworkers; - -public: - XDriverRequest(); - XDriverRequest(GCCause::Cause cause); - XDriverRequest(GCCause::Cause cause, uint nworkers); - - bool operator==(const XDriverRequest& other) const; - - GCCause::Cause cause() const; - uint nworkers() const; -}; - -class XDriver : public ConcurrentGCThread { -private: - XMessagePort _gc_cycle_port; - XRendezvousPort _gc_locker_port; - - template bool pause(); - - void pause_mark_start(); - void concurrent_mark(); - bool pause_mark_end(); - void concurrent_mark_continue(); - void concurrent_mark_free(); - void concurrent_process_non_strong_references(); - void concurrent_reset_relocation_set(); - void pause_verify(); - void concurrent_select_relocation_set(); - void pause_relocate_start(); - void concurrent_relocate(); - - void check_out_of_memory(); - - void gc(const XDriverRequest& request); - -protected: - virtual void run_service(); - virtual void stop_service(); - -public: - XDriver(); - - bool is_busy() const; - - void collect(const XDriverRequest& request); -}; - -#endif // SHARE_GC_X_XDRIVER_HPP diff --git a/src/hotspot/share/gc/x/xErrno.cpp b/src/hotspot/share/gc/x/xErrno.cpp deleted file mode 100644 index 64951bc47ab15..0000000000000 --- a/src/hotspot/share/gc/x/xErrno.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xErrno.hpp" -#include "runtime/os.hpp" - -#include -#include - -XErrno::XErrno() : - _error(errno) {} - -XErrno::XErrno(int error) : - _error(error) {} - -XErrno::operator bool() const { - return _error != 0; -} - -bool XErrno::operator==(int error) const { - return _error == error; -} - -bool XErrno::operator!=(int error) const { - return _error != error; -} - -const char* XErrno::to_string() const { - return os::strerror(_error); -} diff --git a/src/hotspot/share/gc/x/xErrno.hpp b/src/hotspot/share/gc/x/xErrno.hpp deleted file mode 100644 index eb72d43da3f8f..0000000000000 --- a/src/hotspot/share/gc/x/xErrno.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XERRNO_HPP -#define SHARE_GC_X_XERRNO_HPP - -#include "memory/allocation.hpp" - -class XErrno : public StackObj { -private: - const int _error; - -public: - XErrno(); - XErrno(int error); - - operator bool() const; - bool operator==(int error) const; - bool operator!=(int error) const; - const char* to_string() const; -}; - -#endif // SHARE_GC_X_XERRNO_HPP diff --git a/src/hotspot/share/gc/x/xForwarding.cpp b/src/hotspot/share/gc/x/xForwarding.cpp deleted file mode 100644 index aa0cd4dff0bcd..0000000000000 --- a/src/hotspot/share/gc/x/xForwarding.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -#include "precompiled.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xForwarding.inline.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xUtils.inline.hpp" -#include "utilities/align.hpp" - -// -// Reference count states: -// -// * If the reference count is zero, it will never change again. -// -// * If the reference count is positive, it can be both retained -// (increased) and released (decreased). -// -// * If the reference count is negative, is can only be released -// (increased). A negative reference count means that one or more -// threads are waiting for one or more other threads to release -// their references. -// -// The reference lock is used for waiting until the reference -// count has become zero (released) or negative one (claimed). -// - -static const XStatCriticalPhase XCriticalPhaseRelocationStall("Relocation Stall"); - -bool XForwarding::retain_page() { - for (;;) { - const int32_t ref_count = Atomic::load_acquire(&_ref_count); - - if (ref_count == 0) { - // Released - return false; - } - - if (ref_count < 0) { - // Claimed - const bool success = wait_page_released(); - assert(success, "Should always succeed"); - return false; - } - - if (Atomic::cmpxchg(&_ref_count, ref_count, ref_count + 1) == ref_count) { - // Retained - return true; - } - } -} - -XPage* XForwarding::claim_page() { - for (;;) { - const int32_t ref_count = Atomic::load(&_ref_count); - assert(ref_count > 0, "Invalid state"); - - // Invert reference count - if (Atomic::cmpxchg(&_ref_count, ref_count, -ref_count) != ref_count) { - continue; - } - - // If the previous reference count was 1, then we just changed it to -1, - // and we have now claimed the page. Otherwise we wait until it is claimed. - if (ref_count != 1) { - XLocker locker(&_ref_lock); - while (Atomic::load_acquire(&_ref_count) != -1) { - _ref_lock.wait(); - } - } - - return _page; - } -} - -void XForwarding::release_page() { - for (;;) { - const int32_t ref_count = Atomic::load(&_ref_count); - assert(ref_count != 0, "Invalid state"); - - if (ref_count > 0) { - // Decrement reference count - if (Atomic::cmpxchg(&_ref_count, ref_count, ref_count - 1) != ref_count) { - continue; - } - - // If the previous reference count was 1, then we just decremented - // it to 0 and we should signal that the page is now released. - if (ref_count == 1) { - // Notify released - XLocker locker(&_ref_lock); - _ref_lock.notify_all(); - } - } else { - // Increment reference count - if (Atomic::cmpxchg(&_ref_count, ref_count, ref_count + 1) != ref_count) { - continue; - } - - // If the previous reference count was -2 or -1, then we just incremented it - // to -1 or 0, and we should signal the that page is now claimed or released. - if (ref_count == -2 || ref_count == -1) { - // Notify claimed or released - XLocker locker(&_ref_lock); - _ref_lock.notify_all(); - } - } - - return; - } -} - -bool XForwarding::wait_page_released() const { - if (Atomic::load_acquire(&_ref_count) != 0) { - XStatTimer timer(XCriticalPhaseRelocationStall); - XLocker locker(&_ref_lock); - while (Atomic::load_acquire(&_ref_count) != 0) { - if (_ref_abort) { - return false; - } - - _ref_lock.wait(); - } - } - - return true; -} - -XPage* XForwarding::detach_page() { - // Wait until released - if (Atomic::load_acquire(&_ref_count) != 0) { - XLocker locker(&_ref_lock); - while (Atomic::load_acquire(&_ref_count) != 0) { - _ref_lock.wait(); - } - } - - // Detach and return page - XPage* const page = _page; - _page = nullptr; - return page; -} - -void XForwarding::abort_page() { - XLocker locker(&_ref_lock); - assert(Atomic::load(&_ref_count) > 0, "Invalid state"); - assert(!_ref_abort, "Invalid state"); - _ref_abort = true; - _ref_lock.notify_all(); -} - -void XForwarding::verify() const { - guarantee(_ref_count != 0, "Invalid reference count"); - guarantee(_page != nullptr, "Invalid page"); - - uint32_t live_objects = 0; - size_t live_bytes = 0; - - for (XForwardingCursor i = 0; i < _entries.length(); i++) { - const XForwardingEntry entry = at(&i); - if (!entry.populated()) { - // Skip empty entries - continue; - } - - // Check from index - guarantee(entry.from_index() < _page->object_max_count(), "Invalid from index"); - - // Check for duplicates - for (XForwardingCursor j = i + 1; j < _entries.length(); j++) { - const XForwardingEntry other = at(&j); - if (!other.populated()) { - // Skip empty entries - continue; - } - - guarantee(entry.from_index() != other.from_index(), "Duplicate from"); - guarantee(entry.to_offset() != other.to_offset(), "Duplicate to"); - } - - const uintptr_t to_addr = XAddress::good(entry.to_offset()); - const size_t size = XUtils::object_size(to_addr); - const size_t aligned_size = align_up(size, _page->object_alignment()); - live_bytes += aligned_size; - live_objects++; - } - - // Verify number of live objects and bytes - _page->verify_live(live_objects, live_bytes); -} diff --git a/src/hotspot/share/gc/x/xForwarding.hpp b/src/hotspot/share/gc/x/xForwarding.hpp deleted file mode 100644 index a6185e23ced27..0000000000000 --- a/src/hotspot/share/gc/x/xForwarding.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XFORWARDING_HPP -#define SHARE_GC_X_XFORWARDING_HPP - -#include "gc/x/xAttachedArray.hpp" -#include "gc/x/xForwardingEntry.hpp" -#include "gc/x/xLock.hpp" -#include "gc/x/xVirtualMemory.hpp" - -class ObjectClosure; -class VMStructs; -class XForwardingAllocator; -class XPage; - -typedef size_t XForwardingCursor; - -class XForwarding { - friend class ::VMStructs; - friend class XForwardingTest; - -private: - typedef XAttachedArray AttachedArray; - - const XVirtualMemory _virtual; - const size_t _object_alignment_shift; - const AttachedArray _entries; - XPage* _page; - mutable XConditionLock _ref_lock; - volatile int32_t _ref_count; - bool _ref_abort; - bool _in_place; - - XForwardingEntry* entries() const; - XForwardingEntry at(XForwardingCursor* cursor) const; - XForwardingEntry first(uintptr_t from_index, XForwardingCursor* cursor) const; - XForwardingEntry next(XForwardingCursor* cursor) const; - - XForwarding(XPage* page, size_t nentries); - -public: - static uint32_t nentries(const XPage* page); - static XForwarding* alloc(XForwardingAllocator* allocator, XPage* page); - - uint8_t type() const; - uintptr_t start() const; - size_t size() const; - size_t object_alignment_shift() const; - void object_iterate(ObjectClosure *cl); - - bool retain_page(); - XPage* claim_page(); - void release_page(); - bool wait_page_released() const; - XPage* detach_page(); - void abort_page(); - - void set_in_place(); - bool in_place() const; - - XForwardingEntry find(uintptr_t from_index, XForwardingCursor* cursor) const; - uintptr_t insert(uintptr_t from_index, uintptr_t to_offset, XForwardingCursor* cursor); - - void verify() const; -}; - -#endif // SHARE_GC_X_XFORWARDING_HPP diff --git a/src/hotspot/share/gc/x/xForwarding.inline.hpp b/src/hotspot/share/gc/x/xForwarding.inline.hpp deleted file mode 100644 index 257109f3de926..0000000000000 --- a/src/hotspot/share/gc/x/xForwarding.inline.hpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XFORWARDING_INLINE_HPP -#define SHARE_GC_X_XFORWARDING_INLINE_HPP - -#include "gc/x/xForwarding.hpp" - -#include "gc/x/xAttachedArray.inline.hpp" -#include "gc/x/xForwardingAllocator.inline.hpp" -#include "gc/x/xHash.inline.hpp" -#include "gc/x/xHeap.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xVirtualMemory.inline.hpp" -#include "runtime/atomic.hpp" -#include "utilities/debug.hpp" -#include "utilities/powerOfTwo.hpp" - -inline uint32_t XForwarding::nentries(const XPage* page) { - // The number returned by the function is used to size the hash table of - // forwarding entries for this page. This hash table uses linear probing. - // The size of the table must be a power of two to allow for quick and - // inexpensive indexing/masking. The table is also sized to have a load - // factor of 50%, i.e. sized to have double the number of entries actually - // inserted, to allow for good lookup/insert performance. - return round_up_power_of_2(page->live_objects() * 2); -} - -inline XForwarding* XForwarding::alloc(XForwardingAllocator* allocator, XPage* page) { - const size_t nentries = XForwarding::nentries(page); - void* const addr = AttachedArray::alloc(allocator, nentries); - return ::new (addr) XForwarding(page, nentries); -} - -inline XForwarding::XForwarding(XPage* page, size_t nentries) : - _virtual(page->virtual_memory()), - _object_alignment_shift(page->object_alignment_shift()), - _entries(nentries), - _page(page), - _ref_lock(), - _ref_count(1), - _ref_abort(false), - _in_place(false) {} - -inline uint8_t XForwarding::type() const { - return _page->type(); -} - -inline uintptr_t XForwarding::start() const { - return _virtual.start(); -} - -inline size_t XForwarding::size() const { - return _virtual.size(); -} - -inline size_t XForwarding::object_alignment_shift() const { - return _object_alignment_shift; -} - -inline void XForwarding::object_iterate(ObjectClosure *cl) { - return _page->object_iterate(cl); -} - -inline void XForwarding::set_in_place() { - _in_place = true; -} - -inline bool XForwarding::in_place() const { - return _in_place; -} - -inline XForwardingEntry* XForwarding::entries() const { - return _entries(this); -} - -inline XForwardingEntry XForwarding::at(XForwardingCursor* cursor) const { - // Load acquire for correctness with regards to - // accesses to the contents of the forwarded object. - return Atomic::load_acquire(entries() + *cursor); -} - -inline XForwardingEntry XForwarding::first(uintptr_t from_index, XForwardingCursor* cursor) const { - const size_t mask = _entries.length() - 1; - const size_t hash = XHash::uint32_to_uint32((uint32_t)from_index); - *cursor = hash & mask; - return at(cursor); -} - -inline XForwardingEntry XForwarding::next(XForwardingCursor* cursor) const { - const size_t mask = _entries.length() - 1; - *cursor = (*cursor + 1) & mask; - return at(cursor); -} - -inline XForwardingEntry XForwarding::find(uintptr_t from_index, XForwardingCursor* cursor) const { - // Reading entries in the table races with the atomic CAS done for - // insertion into the table. This is safe because each entry is at - // most updated once (from zero to something else). - XForwardingEntry entry = first(from_index, cursor); - while (entry.populated()) { - if (entry.from_index() == from_index) { - // Match found, return matching entry - return entry; - } - - entry = next(cursor); - } - - // Match not found, return empty entry - return entry; -} - -inline uintptr_t XForwarding::insert(uintptr_t from_index, uintptr_t to_offset, XForwardingCursor* cursor) { - const XForwardingEntry new_entry(from_index, to_offset); - const XForwardingEntry old_entry; // Empty - - // Make sure that object copy is finished - // before forwarding table installation - OrderAccess::release(); - - for (;;) { - const XForwardingEntry prev_entry = Atomic::cmpxchg(entries() + *cursor, old_entry, new_entry, memory_order_relaxed); - if (!prev_entry.populated()) { - // Success - return to_offset; - } - - // Find next empty or matching entry - XForwardingEntry entry = at(cursor); - while (entry.populated()) { - if (entry.from_index() == from_index) { - // Match found, return already inserted address - return entry.to_offset(); - } - - entry = next(cursor); - } - } -} - -#endif // SHARE_GC_X_XFORWARDING_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xForwardingAllocator.cpp b/src/hotspot/share/gc/x/xForwardingAllocator.cpp deleted file mode 100644 index c8368fde5f5cc..0000000000000 --- a/src/hotspot/share/gc/x/xForwardingAllocator.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xForwardingAllocator.hpp" -#include "memory/allocation.inline.hpp" - -XForwardingAllocator::XForwardingAllocator() : - _start(nullptr), - _end(nullptr), - _top(nullptr) {} - -XForwardingAllocator::~XForwardingAllocator() { - FREE_C_HEAP_ARRAY(char, _start); -} - -void XForwardingAllocator::reset(size_t size) { - _start = _top = REALLOC_C_HEAP_ARRAY(char, _start, size, mtGC); - _end = _start + size; -} diff --git a/src/hotspot/share/gc/x/xForwardingAllocator.hpp b/src/hotspot/share/gc/x/xForwardingAllocator.hpp deleted file mode 100644 index 75495944e8ae3..0000000000000 --- a/src/hotspot/share/gc/x/xForwardingAllocator.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XFORWARDINGALLOCATOR_HPP -#define SHARE_GC_X_XFORWARDINGALLOCATOR_HPP - -#include "utilities/globalDefinitions.hpp" - -class XForwardingAllocator { -private: - char* _start; - char* _end; - char* _top; - -public: - XForwardingAllocator(); - ~XForwardingAllocator(); - - void reset(size_t size); - size_t size() const; - bool is_full() const; - - void* alloc(size_t size); -}; - -#endif // SHARE_GC_X_XFORWARDINGALLOCATOR_HPP diff --git a/src/hotspot/share/gc/x/xForwardingAllocator.inline.hpp b/src/hotspot/share/gc/x/xForwardingAllocator.inline.hpp deleted file mode 100644 index e70986f52062e..0000000000000 --- a/src/hotspot/share/gc/x/xForwardingAllocator.inline.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2020, 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. - */ - -#ifndef SHARE_GC_X_XFORWARDINGALLOCATOR_INLINE_HPP -#define SHARE_GC_X_XFORWARDINGALLOCATOR_INLINE_HPP - -#include "gc/x/xForwardingAllocator.hpp" - -#include "runtime/atomic.hpp" -#include "utilities/debug.hpp" - -inline size_t XForwardingAllocator::size() const { - return _end - _start; -} - -inline bool XForwardingAllocator::is_full() const { - return _top == _end; -} - -inline void* XForwardingAllocator::alloc(size_t size) { - char* const addr = Atomic::fetch_then_add(&_top, size); - assert(addr + size <= _end, "Allocation should never fail"); - return addr; -} - -#endif // SHARE_GC_X_XFORWARDINGALLOCATOR_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xForwardingEntry.hpp b/src/hotspot/share/gc/x/xForwardingEntry.hpp deleted file mode 100644 index 3f8846abbaa2b..0000000000000 --- a/src/hotspot/share/gc/x/xForwardingEntry.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XFORWARDINGENTRY_HPP -#define SHARE_GC_X_XFORWARDINGENTRY_HPP - -#include "gc/x/xBitField.hpp" -#include "memory/allocation.hpp" -#include "metaprogramming/primitiveConversions.hpp" - -#include - -class VMStructs; - -// -// Forwarding entry layout -// ----------------------- -// -// 6 4 4 -// 3 6 5 1 0 -// +--------------------+--------------------------------------------------+-+ -// |11111111 11111111 11|111111 11111111 11111111 11111111 11111111 1111111|1| -// +--------------------+--------------------------------------------------+-+ -// | | | -// | | 0-0 Populated Flag (1-bits) * -// | | -// | * 45-1 To Object Offset (45-bits) -// | -// * 63-46 From Object Index (18-bits) -// - -class XForwardingEntry { - friend struct PrimitiveConversions::Translate; - friend class ::VMStructs; - -private: - typedef XBitField field_populated; - typedef XBitField field_to_offset; - typedef XBitField field_from_index; - - uint64_t _entry; - -public: - XForwardingEntry() : - _entry(0) {} - - XForwardingEntry(size_t from_index, size_t to_offset) : - _entry(field_populated::encode(true) | - field_to_offset::encode(to_offset) | - field_from_index::encode(from_index)) {} - - bool populated() const { - return field_populated::decode(_entry); - } - - size_t to_offset() const { - return field_to_offset::decode(_entry); - } - - size_t from_index() const { - return field_from_index::decode(_entry); - } -}; - -// Needed to allow atomic operations on XForwardingEntry -template <> -struct PrimitiveConversions::Translate : public std::true_type { - typedef XForwardingEntry Value; - typedef uint64_t Decayed; - - static Decayed decay(Value v) { - return v._entry; - } - - static Value recover(Decayed d) { - XForwardingEntry entry; - entry._entry = d; - return entry; - } -}; - -#endif // SHARE_GC_X_XFORWARDINGENTRY_HPP diff --git a/src/hotspot/share/gc/x/xForwardingTable.hpp b/src/hotspot/share/gc/x/xForwardingTable.hpp deleted file mode 100644 index 1f110292be516..0000000000000 --- a/src/hotspot/share/gc/x/xForwardingTable.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 - * 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_GC_X_XFORWARDINGTABLE_HPP -#define SHARE_GC_X_XFORWARDINGTABLE_HPP - -#include "gc/x/xGranuleMap.hpp" - -class VMStructs; -class XForwarding; - -class XForwardingTable { - friend class ::VMStructs; - -private: - XGranuleMap _map; - -public: - XForwardingTable(); - - XForwarding* get(uintptr_t addr) const; - - void insert(XForwarding* forwarding); - void remove(XForwarding* forwarding); -}; - -#endif // SHARE_GC_X_XFORWARDINGTABLE_HPP diff --git a/src/hotspot/share/gc/x/xForwardingTable.inline.hpp b/src/hotspot/share/gc/x/xForwardingTable.inline.hpp deleted file mode 100644 index b65b68da4e234..0000000000000 --- a/src/hotspot/share/gc/x/xForwardingTable.inline.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XFORWARDINGTABLE_INLINE_HPP -#define SHARE_GC_X_XFORWARDINGTABLE_INLINE_HPP - -#include "gc/x/xForwardingTable.hpp" - -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xForwarding.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xGranuleMap.inline.hpp" -#include "utilities/debug.hpp" - -inline XForwardingTable::XForwardingTable() : - _map(XAddressOffsetMax) {} - -inline XForwarding* XForwardingTable::get(uintptr_t addr) const { - assert(!XAddress::is_null(addr), "Invalid address"); - return _map.get(XAddress::offset(addr)); -} - -inline void XForwardingTable::insert(XForwarding* forwarding) { - const uintptr_t offset = forwarding->start(); - const size_t size = forwarding->size(); - - assert(_map.get(offset) == nullptr, "Invalid entry"); - _map.put(offset, size, forwarding); -} - -inline void XForwardingTable::remove(XForwarding* forwarding) { - const uintptr_t offset = forwarding->start(); - const size_t size = forwarding->size(); - - assert(_map.get(offset) == forwarding, "Invalid entry"); - _map.put(offset, size, nullptr); -} - -#endif // SHARE_GC_X_XFORWARDINGTABLE_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xFuture.hpp b/src/hotspot/share/gc/x/xFuture.hpp deleted file mode 100644 index 931f4b58f123c..0000000000000 --- a/src/hotspot/share/gc/x/xFuture.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XFUTURE_HPP -#define SHARE_GC_X_XFUTURE_HPP - -#include "memory/allocation.hpp" -#include "runtime/semaphore.hpp" - -template -class XFuture { -private: - Semaphore _sema; - T _value; - -public: - XFuture(); - - void set(T value); - T get(); -}; - -#endif // SHARE_GC_X_XFUTURE_HPP diff --git a/src/hotspot/share/gc/x/xFuture.inline.hpp b/src/hotspot/share/gc/x/xFuture.inline.hpp deleted file mode 100644 index d3dba3b7151d7..0000000000000 --- a/src/hotspot/share/gc/x/xFuture.inline.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XFUTURE_INLINE_HPP -#define SHARE_GC_X_XFUTURE_INLINE_HPP - -#include "gc/x/xFuture.hpp" - -#include "runtime/javaThread.hpp" -#include "runtime/semaphore.inline.hpp" - -template -inline XFuture::XFuture() : - _value() {} - -template -inline void XFuture::set(T value) { - // Set value - _value = value; - - // Notify waiter - _sema.signal(); -} - -template -inline T XFuture::get() { - // Wait for notification - Thread* const thread = Thread::current(); - if (thread->is_Java_thread()) { - _sema.wait_with_safepoint_check(JavaThread::cast(thread)); - } else { - _sema.wait(); - } - - // Return value - return _value; -} - -#endif // SHARE_GC_X_XFUTURE_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xGlobals.cpp b/src/hotspot/share/gc/x/xGlobals.cpp deleted file mode 100644 index b247565bc011d..0000000000000 --- a/src/hotspot/share/gc/x/xGlobals.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -#include "precompiled.hpp" -#include "gc/x/xGlobals.hpp" - -uint32_t XGlobalPhase = XPhaseRelocate; -uint32_t XGlobalSeqNum = 1; - -size_t XPageSizeMediumShift; -size_t XPageSizeMedium; - -size_t XObjectSizeLimitMedium; - -const int& XObjectAlignmentSmallShift = LogMinObjAlignmentInBytes; -int XObjectAlignmentMediumShift; - -const int& XObjectAlignmentSmall = MinObjAlignmentInBytes; -int XObjectAlignmentMedium; - -uintptr_t XAddressGoodMask; -uintptr_t XAddressBadMask; -uintptr_t XAddressWeakBadMask; - -static uint32_t* XAddressCalculateBadMaskHighOrderBitsAddr() { - const uintptr_t addr = reinterpret_cast(&XAddressBadMask); - return reinterpret_cast(addr + XAddressBadMaskHighOrderBitsOffset); -} - -uint32_t* XAddressBadMaskHighOrderBitsAddr = XAddressCalculateBadMaskHighOrderBitsAddr(); - -size_t XAddressOffsetBits; -uintptr_t XAddressOffsetMask; -size_t XAddressOffsetMax; - -size_t XAddressMetadataShift; -uintptr_t XAddressMetadataMask; - -uintptr_t XAddressMetadataMarked; -uintptr_t XAddressMetadataMarked0; -uintptr_t XAddressMetadataMarked1; -uintptr_t XAddressMetadataRemapped; -uintptr_t XAddressMetadataFinalizable; - -const char* XGlobalPhaseToString() { - switch (XGlobalPhase) { - case XPhaseMark: - return "Mark"; - - case XPhaseMarkCompleted: - return "MarkCompleted"; - - case XPhaseRelocate: - return "Relocate"; - - default: - return "Unknown"; - } -} diff --git a/src/hotspot/share/gc/x/xGlobals.hpp b/src/hotspot/share/gc/x/xGlobals.hpp deleted file mode 100644 index 662a502a79f86..0000000000000 --- a/src/hotspot/share/gc/x/xGlobals.hpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XGLOBALS_HPP -#define SHARE_GC_X_XGLOBALS_HPP - -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" -#include CPU_HEADER(gc/x/xGlobals) - -// Collector name -const char* const XName = "The Z Garbage Collector"; - -// Global phase state -extern uint32_t XGlobalPhase; -const uint32_t XPhaseMark = 0; -const uint32_t XPhaseMarkCompleted = 1; -const uint32_t XPhaseRelocate = 2; -const char* XGlobalPhaseToString(); - -// Global sequence number -extern uint32_t XGlobalSeqNum; - -// Granule shift/size -const size_t XGranuleSizeShift = 21; // 2MB -const size_t XGranuleSize = (size_t)1 << XGranuleSizeShift; - -// Number of heap views -const size_t XHeapViews = XPlatformHeapViews; - -// Virtual memory to physical memory ratio -const size_t XVirtualToPhysicalRatio = 16; // 16:1 - -// Page types -const uint8_t XPageTypeSmall = 0; -const uint8_t XPageTypeMedium = 1; -const uint8_t XPageTypeLarge = 2; - -// Page size shifts -const size_t XPageSizeSmallShift = XGranuleSizeShift; -extern size_t XPageSizeMediumShift; - -// Page sizes -const size_t XPageSizeSmall = (size_t)1 << XPageSizeSmallShift; -extern size_t XPageSizeMedium; - -// Object size limits -const size_t XObjectSizeLimitSmall = XPageSizeSmall / 8; // 12.5% max waste -extern size_t XObjectSizeLimitMedium; - -// Object alignment shifts -extern const int& XObjectAlignmentSmallShift; -extern int XObjectAlignmentMediumShift; -const int XObjectAlignmentLargeShift = XGranuleSizeShift; - -// Object alignments -extern const int& XObjectAlignmentSmall; -extern int XObjectAlignmentMedium; -const int XObjectAlignmentLarge = 1 << XObjectAlignmentLargeShift; - -// -// Good/Bad mask states -// -------------------- -// -// GoodMask BadMask WeakGoodMask WeakBadMask -// -------------------------------------------------------------- -// Marked0 001 110 101 010 -// Marked1 010 101 110 001 -// Remapped 100 011 100 011 -// - -// Good/bad masks -extern uintptr_t XAddressGoodMask; -extern uintptr_t XAddressBadMask; -extern uintptr_t XAddressWeakBadMask; - -// The bad mask is 64 bit. Its high order 32 bits contain all possible value combinations -// that this mask will have. Therefore, the memory where the 32 high order bits are stored, -// can be used as a 32 bit GC epoch counter, that has a different bit pattern every time -// the bad mask is flipped. This provides a pointer to said 32 bits. -extern uint32_t* XAddressBadMaskHighOrderBitsAddr; -const int XAddressBadMaskHighOrderBitsOffset = LITTLE_ENDIAN_ONLY(4) BIG_ENDIAN_ONLY(0); - -// Pointer part of address -extern size_t XAddressOffsetBits; -const size_t XAddressOffsetShift = 0; -extern uintptr_t XAddressOffsetMask; -extern size_t XAddressOffsetMax; - -// Metadata part of address -const size_t XAddressMetadataBits = 4; -extern size_t XAddressMetadataShift; -extern uintptr_t XAddressMetadataMask; - -// Metadata types -extern uintptr_t XAddressMetadataMarked; -extern uintptr_t XAddressMetadataMarked0; -extern uintptr_t XAddressMetadataMarked1; -extern uintptr_t XAddressMetadataRemapped; -extern uintptr_t XAddressMetadataFinalizable; - -// Cache line size -const size_t XCacheLineSize = XPlatformCacheLineSize; -#define XCACHE_ALIGNED ATTRIBUTE_ALIGNED(XCacheLineSize) - -// Mark stack space -extern uintptr_t XMarkStackSpaceStart; -const size_t XMarkStackSpaceExpandSize = (size_t)1 << 25; // 32M - -// Mark stack and magazine sizes -const size_t XMarkStackSizeShift = 11; // 2K -const size_t XMarkStackSize = (size_t)1 << XMarkStackSizeShift; -const size_t XMarkStackHeaderSize = (size_t)1 << 4; // 16B -const size_t XMarkStackSlots = (XMarkStackSize - XMarkStackHeaderSize) / sizeof(uintptr_t); -const size_t XMarkStackMagazineSize = (size_t)1 << 15; // 32K -const size_t XMarkStackMagazineSlots = (XMarkStackMagazineSize / XMarkStackSize) - 1; - -// Mark stripe size -const size_t XMarkStripeShift = XGranuleSizeShift; - -// Max number of mark stripes -const size_t XMarkStripesMax = 16; // Must be a power of two - -// Mark cache size -const size_t XMarkCacheSize = 1024; // Must be a power of two - -// Partial array minimum size -const size_t XMarkPartialArrayMinSizeShift = 12; // 4K -const size_t XMarkPartialArrayMinSize = (size_t)1 << XMarkPartialArrayMinSizeShift; - -// Max number of proactive/terminate flush attempts -const size_t XMarkProactiveFlushMax = 10; -const size_t XMarkTerminateFlushMax = 3; - -// Try complete mark timeout -const uint64_t XMarkCompleteTimeout = 200; // us - -#endif // SHARE_GC_X_XGLOBALS_HPP diff --git a/src/hotspot/share/gc/x/xGranuleMap.hpp b/src/hotspot/share/gc/x/xGranuleMap.hpp deleted file mode 100644 index a9447e1469c6c..0000000000000 --- a/src/hotspot/share/gc/x/xGranuleMap.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XGRANULEMAP_HPP -#define SHARE_GC_X_XGRANULEMAP_HPP - -#include "gc/x/xArray.hpp" -#include "memory/allocation.hpp" - -class VMStructs; - -template -class XGranuleMap { - friend class ::VMStructs; - template friend class XGranuleMapIterator; - -private: - const size_t _size; - T* const _map; - - size_t index_for_offset(uintptr_t offset) const; - -public: - XGranuleMap(size_t max_offset); - ~XGranuleMap(); - - T get(uintptr_t offset) const; - void put(uintptr_t offset, T value); - void put(uintptr_t offset, size_t size, T value); - - T get_acquire(uintptr_t offset) const; - void release_put(uintptr_t offset, T value); -}; - -template -class XGranuleMapIterator : public XArrayIteratorImpl { -public: - XGranuleMapIterator(const XGranuleMap* granule_map); -}; - -#endif // SHARE_GC_X_XGRANULEMAP_HPP diff --git a/src/hotspot/share/gc/x/xGranuleMap.inline.hpp b/src/hotspot/share/gc/x/xGranuleMap.inline.hpp deleted file mode 100644 index 95ef5ee2b2d5b..0000000000000 --- a/src/hotspot/share/gc/x/xGranuleMap.inline.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XGRANULEMAP_INLINE_HPP -#define SHARE_GC_X_XGRANULEMAP_INLINE_HPP - -#include "gc/x/xGranuleMap.hpp" - -#include "gc/x/xArray.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "memory/allocation.inline.hpp" -#include "runtime/atomic.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" - -template -inline XGranuleMap::XGranuleMap(size_t max_offset) : - _size(max_offset >> XGranuleSizeShift), - _map(MmapArrayAllocator::allocate(_size, mtGC)) { - assert(is_aligned(max_offset, XGranuleSize), "Misaligned"); -} - -template -inline XGranuleMap::~XGranuleMap() { - MmapArrayAllocator::free(_map, _size); -} - -template -inline size_t XGranuleMap::index_for_offset(uintptr_t offset) const { - const size_t index = offset >> XGranuleSizeShift; - assert(index < _size, "Invalid index"); - return index; -} - -template -inline T XGranuleMap::get(uintptr_t offset) const { - const size_t index = index_for_offset(offset); - return _map[index]; -} - -template -inline void XGranuleMap::put(uintptr_t offset, T value) { - const size_t index = index_for_offset(offset); - _map[index] = value; -} - -template -inline void XGranuleMap::put(uintptr_t offset, size_t size, T value) { - assert(is_aligned(size, XGranuleSize), "Misaligned"); - - const size_t start_index = index_for_offset(offset); - const size_t end_index = start_index + (size >> XGranuleSizeShift); - for (size_t index = start_index; index < end_index; index++) { - _map[index] = value; - } -} - -template -inline T XGranuleMap::get_acquire(uintptr_t offset) const { - const size_t index = index_for_offset(offset); - return Atomic::load_acquire(_map + index); -} - -template -inline void XGranuleMap::release_put(uintptr_t offset, T value) { - const size_t index = index_for_offset(offset); - Atomic::release_store(_map + index, value); -} - -template -inline XGranuleMapIterator::XGranuleMapIterator(const XGranuleMap* granule_map) : - XArrayIteratorImpl(granule_map->_map, granule_map->_size) {} - -#endif // SHARE_GC_X_XGRANULEMAP_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xHash.hpp b/src/hotspot/share/gc/x/xHash.hpp deleted file mode 100644 index 253f4d231c1c3..0000000000000 --- a/src/hotspot/share/gc/x/xHash.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XHASH_HPP -#define SHARE_GC_X_XHASH_HPP - -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" - -class XHash : public AllStatic { -public: - static uint32_t uint32_to_uint32(uint32_t key); - static uint32_t address_to_uint32(uintptr_t key); -}; - -#endif // SHARE_GC_X_XHASH_HPP diff --git a/src/hotspot/share/gc/x/xHash.inline.hpp b/src/hotspot/share/gc/x/xHash.inline.hpp deleted file mode 100644 index 5ff5f540821e0..0000000000000 --- a/src/hotspot/share/gc/x/xHash.inline.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -/* - * 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: - * - * (C) 2009 by Remo Dentato (rdentato@gmail.com) - * - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://opensource.org/licenses/bsd-license.php - */ - -#ifndef SHARE_GC_X_XHASH_INLINE_HPP -#define SHARE_GC_X_XHASH_INLINE_HPP - -#include "gc/x/xHash.hpp" - -#include "gc/x/xAddress.inline.hpp" - -inline uint32_t XHash::uint32_to_uint32(uint32_t key) { - key = ~key + (key << 15); - key = key ^ (key >> 12); - key = key + (key << 2); - key = key ^ (key >> 4); - key = key * 2057; - key = key ^ (key >> 16); - return key; -} - -inline uint32_t XHash::address_to_uint32(uintptr_t key) { - return uint32_to_uint32((uint32_t)(key >> 3)); -} - -#endif // SHARE_GC_X_XHASH_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xHeap.cpp b/src/hotspot/share/gc/x/xHeap.cpp deleted file mode 100644 index 3872db785f3bf..0000000000000 --- a/src/hotspot/share/gc/x/xHeap.cpp +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "classfile/classLoaderDataGraph.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/shared/classUnloadingContext.hpp" -#include "gc/shared/locationPrinter.hpp" -#include "gc/shared/tlab_globals.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xArray.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xHeapIterator.hpp" -#include "gc/x/xHeuristics.hpp" -#include "gc/x/xMark.inline.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xPageTable.inline.hpp" -#include "gc/x/xRelocationSet.inline.hpp" -#include "gc/x/xRelocationSetSelector.inline.hpp" -#include "gc/x/xResurrection.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xThread.inline.hpp" -#include "gc/x/xVerify.hpp" -#include "gc/x/xWorkers.hpp" -#include "logging/log.hpp" -#include "memory/iterator.hpp" -#include "memory/metaspaceUtils.hpp" -#include "memory/resourceArea.hpp" -#include "prims/jvmtiTagMap.hpp" -#include "runtime/handshake.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/safepoint.hpp" -#include "utilities/debug.hpp" - -static const XStatCounter XCounterUndoPageAllocation("Memory", "Undo Page Allocation", XStatUnitOpsPerSecond); -static const XStatCounter XCounterOutOfMemory("Memory", "Out Of Memory", XStatUnitOpsPerSecond); - -XHeap* XHeap::_heap = nullptr; - -XHeap::XHeap() : - _workers(), - _object_allocator(), - _page_allocator(&_workers, MinHeapSize, InitialHeapSize, MaxHeapSize), - _page_table(), - _forwarding_table(), - _mark(&_workers, &_page_table), - _reference_processor(&_workers), - _weak_roots_processor(&_workers), - _relocate(&_workers), - _relocation_set(&_workers), - _unload(&_workers), - _serviceability(min_capacity(), max_capacity()) { - // Install global heap instance - assert(_heap == nullptr, "Already initialized"); - _heap = this; - - // Update statistics - XStatHeap::set_at_initialize(_page_allocator.stats()); -} - -bool XHeap::is_initialized() const { - return _page_allocator.is_initialized() && _mark.is_initialized(); -} - -size_t XHeap::min_capacity() const { - return _page_allocator.min_capacity(); -} - -size_t XHeap::max_capacity() const { - return _page_allocator.max_capacity(); -} - -size_t XHeap::soft_max_capacity() const { - return _page_allocator.soft_max_capacity(); -} - -size_t XHeap::capacity() const { - return _page_allocator.capacity(); -} - -size_t XHeap::used() const { - return _page_allocator.used(); -} - -size_t XHeap::unused() const { - return _page_allocator.unused(); -} - -size_t XHeap::tlab_capacity() const { - return capacity(); -} - -size_t XHeap::tlab_used() const { - return _object_allocator.used(); -} - -size_t XHeap::max_tlab_size() const { - return XObjectSizeLimitSmall; -} - -size_t XHeap::unsafe_max_tlab_alloc() const { - size_t size = _object_allocator.remaining(); - - if (size < MinTLABSize) { - // The remaining space in the allocator is not enough to - // fit the smallest possible TLAB. This means that the next - // TLAB allocation will force the allocator to get a new - // backing page anyway, which in turn means that we can then - // fit the largest possible TLAB. - size = max_tlab_size(); - } - - return MIN2(size, max_tlab_size()); -} - -bool XHeap::is_in(uintptr_t addr) const { - // An address is considered to be "in the heap" if it points into - // the allocated part of a page, regardless of which heap view is - // used. Note that an address with the finalizable metadata bit set - // is not pointing into a heap view, and therefore not considered - // to be "in the heap". - - if (XAddress::is_in(addr)) { - const XPage* const page = _page_table.get(addr); - if (page != nullptr) { - return page->is_in(addr); - } - } - - return false; -} - -uint XHeap::active_workers() const { - return _workers.active_workers(); -} - -void XHeap::set_active_workers(uint nworkers) { - _workers.set_active_workers(nworkers); -} - -void XHeap::threads_do(ThreadClosure* tc) const { - _page_allocator.threads_do(tc); - _workers.threads_do(tc); -} - -void XHeap::out_of_memory() { - ResourceMark rm; - - XStatInc(XCounterOutOfMemory); - log_info(gc)("Out Of Memory (%s)", Thread::current()->name()); -} - -XPage* XHeap::alloc_page(uint8_t type, size_t size, XAllocationFlags flags) { - XPage* const page = _page_allocator.alloc_page(type, size, flags); - if (page != nullptr) { - // Insert page table entry - _page_table.insert(page); - } - - return page; -} - -void XHeap::undo_alloc_page(XPage* page) { - assert(page->is_allocating(), "Invalid page state"); - - XStatInc(XCounterUndoPageAllocation); - log_trace(gc)("Undo page allocation, thread: " PTR_FORMAT " (%s), page: " PTR_FORMAT ", size: " SIZE_FORMAT, - XThread::id(), XThread::name(), p2i(page), page->size()); - - free_page(page, false /* reclaimed */); -} - -void XHeap::free_page(XPage* page, bool reclaimed) { - // Remove page table entry - _page_table.remove(page); - - // Free page - _page_allocator.free_page(page, reclaimed); -} - -void XHeap::free_pages(const XArray* pages, bool reclaimed) { - // Remove page table entries - XArrayIterator iter(pages); - for (XPage* page; iter.next(&page);) { - _page_table.remove(page); - } - - // Free pages - _page_allocator.free_pages(pages, reclaimed); -} - -void XHeap::flip_to_marked() { - XVerifyViewsFlip flip(&_page_allocator); - XAddress::flip_to_marked(); -} - -void XHeap::flip_to_remapped() { - XVerifyViewsFlip flip(&_page_allocator); - XAddress::flip_to_remapped(); -} - -void XHeap::mark_start() { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - - // Verification - ClassLoaderDataGraph::verify_claimed_marks_cleared(ClassLoaderData::_claim_strong); - - if (XHeap::heap()->has_alloc_stalled()) { - // If there are stalled allocations, ensure that regardless of the - // cause of the GC, we have to clear soft references, as we are just - // about to increment the sequence number, and all previous allocations - // will throw if not presented with enough memory. - XHeap::heap()->set_soft_reference_policy(true); - } - - // Flip address view - flip_to_marked(); - - // Retire allocating pages - _object_allocator.retire_pages(); - - // Reset allocated/reclaimed/used statistics - _page_allocator.reset_statistics(); - - // Reset encountered/dropped/enqueued statistics - _reference_processor.reset_statistics(); - - // Enter mark phase - XGlobalPhase = XPhaseMark; - - // Reset marking information - _mark.start(); - - // Update statistics - XStatHeap::set_at_mark_start(_page_allocator.stats()); -} - -void XHeap::mark(bool initial) { - _mark.mark(initial); -} - -void XHeap::mark_flush_and_free(Thread* thread) { - _mark.flush_and_free(thread); -} - -bool XHeap::mark_end() { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - - // Try end marking - if (!_mark.end()) { - // Marking not completed, continue concurrent mark - return false; - } - - // Enter mark completed phase - XGlobalPhase = XPhaseMarkCompleted; - - // Verify after mark - XVerify::after_mark(); - - // Update statistics - XStatHeap::set_at_mark_end(_page_allocator.stats()); - - // Block resurrection of weak/phantom references - XResurrection::block(); - - // Prepare to unload stale metadata and nmethods - _unload.prepare(); - - // Notify JVMTI that some tagmap entry objects may have died. - JvmtiTagMap::set_needs_cleaning(); - - return true; -} - -void XHeap::mark_free() { - _mark.free(); -} - -void XHeap::keep_alive(oop obj) { - XBarrier::keep_alive_barrier_on_oop(obj); -} - -void XHeap::set_soft_reference_policy(bool clear) { - _reference_processor.set_soft_reference_policy(clear); -} - -class XRendezvousClosure : public HandshakeClosure { -public: - XRendezvousClosure() : - HandshakeClosure("XRendezvous") {} - - void do_thread(Thread* thread) {} -}; - -void XHeap::process_non_strong_references() { - // Process Soft/Weak/Final/PhantomReferences - _reference_processor.process_references(); - - // Process weak roots - _weak_roots_processor.process_weak_roots(); - - ClassUnloadingContext ctx(_workers.active_workers(), - true /* unregister_nmethods_during_purge */, - true /* lock_nmethod_free_separately */); - - // Unlink stale metadata and nmethods - _unload.unlink(); - - // Perform a handshake. This is needed 1) to make sure that stale - // metadata and nmethods are no longer observable. And 2), to - // prevent the race where a mutator first loads an oop, which is - // logically null but not yet cleared. Then this oop gets cleared - // by the reference processor and resurrection is unblocked. At - // this point the mutator could see the unblocked state and pass - // this invalid oop through the normal barrier path, which would - // incorrectly try to mark the oop. - XRendezvousClosure cl; - Handshake::execute(&cl); - - // Unblock resurrection of weak/phantom references - XResurrection::unblock(); - - // Purge stale metadata and nmethods that were unlinked - _unload.purge(); - - // Enqueue Soft/Weak/Final/PhantomReferences. Note that this - // must be done after unblocking resurrection. Otherwise the - // Finalizer thread could call Reference.get() on the Finalizers - // that were just enqueued, which would incorrectly return null - // during the resurrection block window, since such referents - // are only Finalizable marked. - _reference_processor.enqueue_references(); - - // Clear old markings claim bits. - // Note: Clearing _claim_strong also clears _claim_finalizable. - ClassLoaderDataGraph::clear_claimed_marks(ClassLoaderData::_claim_strong); -} - -void XHeap::free_empty_pages(XRelocationSetSelector* selector, int bulk) { - // Freeing empty pages in bulk is an optimization to avoid grabbing - // the page allocator lock, and trying to satisfy stalled allocations - // too frequently. - if (selector->should_free_empty_pages(bulk)) { - free_pages(selector->empty_pages(), true /* reclaimed */); - selector->clear_empty_pages(); - } -} - -void XHeap::select_relocation_set() { - // Do not allow pages to be deleted - _page_allocator.enable_deferred_delete(); - - // Register relocatable pages with selector - XRelocationSetSelector selector; - XPageTableIterator pt_iter(&_page_table); - for (XPage* page; pt_iter.next(&page);) { - if (!page->is_relocatable()) { - // Not relocatable, don't register - continue; - } - - if (page->is_marked()) { - // Register live page - selector.register_live_page(page); - } else { - // Register empty page - selector.register_empty_page(page); - - // Reclaim empty pages in bulk - free_empty_pages(&selector, 64 /* bulk */); - } - } - - // Reclaim remaining empty pages - free_empty_pages(&selector, 0 /* bulk */); - - // Allow pages to be deleted - _page_allocator.disable_deferred_delete(); - - // Select relocation set - selector.select(); - - // Install relocation set - _relocation_set.install(&selector); - - // Setup forwarding table - XRelocationSetIterator rs_iter(&_relocation_set); - for (XForwarding* forwarding; rs_iter.next(&forwarding);) { - _forwarding_table.insert(forwarding); - } - - // Update statistics - XStatRelocation::set_at_select_relocation_set(selector.stats()); - XStatHeap::set_at_select_relocation_set(selector.stats()); -} - -void XHeap::reset_relocation_set() { - // Reset forwarding table - XRelocationSetIterator iter(&_relocation_set); - for (XForwarding* forwarding; iter.next(&forwarding);) { - _forwarding_table.remove(forwarding); - } - - // Reset relocation set - _relocation_set.reset(); -} - -void XHeap::relocate_start() { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - - // Finish unloading stale metadata and nmethods - _unload.finish(); - - // Flip address view - flip_to_remapped(); - - // Enter relocate phase - XGlobalPhase = XPhaseRelocate; - - // Update statistics - XStatHeap::set_at_relocate_start(_page_allocator.stats()); -} - -void XHeap::relocate() { - // Relocate relocation set - _relocate.relocate(&_relocation_set); - - // Update statistics - XStatHeap::set_at_relocate_end(_page_allocator.stats(), _object_allocator.relocated()); -} - -bool XHeap::is_allocating(uintptr_t addr) const { - const XPage* const page = _page_table.get(addr); - return page->is_allocating(); -} - -void XHeap::object_iterate(ObjectClosure* cl, bool visit_weaks) { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - XHeapIterator iter(1 /* nworkers */, visit_weaks); - iter.object_iterate(cl, 0 /* worker_id */); -} - -ParallelObjectIteratorImpl* XHeap::parallel_object_iterator(uint nworkers, bool visit_weaks) { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - return new XHeapIterator(nworkers, visit_weaks); -} - -void XHeap::pages_do(XPageClosure* cl) { - XPageTableIterator iter(&_page_table); - for (XPage* page; iter.next(&page);) { - cl->do_page(page); - } - _page_allocator.pages_do(cl); -} - -void XHeap::serviceability_initialize() { - _serviceability.initialize(); -} - -GCMemoryManager* XHeap::serviceability_cycle_memory_manager() { - return _serviceability.cycle_memory_manager(); -} - -GCMemoryManager* XHeap::serviceability_pause_memory_manager() { - return _serviceability.pause_memory_manager(); -} - -MemoryPool* XHeap::serviceability_memory_pool() { - return _serviceability.memory_pool(); -} - -XServiceabilityCounters* XHeap::serviceability_counters() { - return _serviceability.counters(); -} - -void XHeap::print_on(outputStream* st) const { - st->print_cr(" ZHeap used " SIZE_FORMAT "M, capacity " SIZE_FORMAT "M, max capacity " SIZE_FORMAT "M", - used() / M, - capacity() / M, - max_capacity() / M); - MetaspaceUtils::print_on(st); -} - -void XHeap::print_extended_on(outputStream* st) const { - print_on(st); - st->cr(); - - // Do not allow pages to be deleted - _page_allocator.enable_deferred_delete(); - - // Print all pages - st->print_cr("ZGC Page Table:"); - XPageTableIterator iter(&_page_table); - for (XPage* page; iter.next(&page);) { - page->print_on(st); - } - - // Allow pages to be deleted - _page_allocator.disable_deferred_delete(); -} - -bool XHeap::print_location(outputStream* st, uintptr_t addr) const { - if (LocationPrinter::is_valid_obj((void*)addr)) { - st->print(PTR_FORMAT " is a %s oop: ", addr, XAddress::is_good(addr) ? "good" : "bad"); - XOop::from_address(addr)->print_on(st); - return true; - } - - return false; -} - -void XHeap::verify() { - // Heap verification can only be done between mark end and - // relocate start. This is the only window where all oop are - // good and the whole heap is in a consistent state. - guarantee(XGlobalPhase == XPhaseMarkCompleted, "Invalid phase"); - - XVerify::after_weak_processing(); -} diff --git a/src/hotspot/share/gc/x/xHeap.hpp b/src/hotspot/share/gc/x/xHeap.hpp deleted file mode 100644 index af2c73180d91a..0000000000000 --- a/src/hotspot/share/gc/x/xHeap.hpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XHEAP_HPP -#define SHARE_GC_X_XHEAP_HPP - -#include "gc/x/xAllocationFlags.hpp" -#include "gc/x/xArray.hpp" -#include "gc/x/xForwardingTable.hpp" -#include "gc/x/xMark.hpp" -#include "gc/x/xObjectAllocator.hpp" -#include "gc/x/xPageAllocator.hpp" -#include "gc/x/xPageTable.hpp" -#include "gc/x/xReferenceProcessor.hpp" -#include "gc/x/xRelocate.hpp" -#include "gc/x/xRelocationSet.hpp" -#include "gc/x/xWeakRootsProcessor.hpp" -#include "gc/x/xServiceability.hpp" -#include "gc/x/xUnload.hpp" -#include "gc/x/xWorkers.hpp" - -class ThreadClosure; -class VMStructs; -class XPage; -class XRelocationSetSelector; - -class XHeap { - friend class ::VMStructs; - -private: - static XHeap* _heap; - - XWorkers _workers; - XObjectAllocator _object_allocator; - XPageAllocator _page_allocator; - XPageTable _page_table; - XForwardingTable _forwarding_table; - XMark _mark; - XReferenceProcessor _reference_processor; - XWeakRootsProcessor _weak_roots_processor; - XRelocate _relocate; - XRelocationSet _relocation_set; - XUnload _unload; - XServiceability _serviceability; - - void flip_to_marked(); - void flip_to_remapped(); - - void free_empty_pages(XRelocationSetSelector* selector, int bulk); - - void out_of_memory(); - -public: - static XHeap* heap(); - - XHeap(); - - bool is_initialized() const; - - // Heap metrics - size_t min_capacity() const; - size_t max_capacity() const; - size_t soft_max_capacity() const; - size_t capacity() const; - size_t used() const; - size_t unused() const; - - size_t tlab_capacity() const; - size_t tlab_used() const; - size_t max_tlab_size() const; - size_t unsafe_max_tlab_alloc() const; - - bool is_in(uintptr_t addr) const; - - // Threads - uint active_workers() const; - void set_active_workers(uint nworkers); - void threads_do(ThreadClosure* tc) const; - - // Reference processing - ReferenceDiscoverer* reference_discoverer(); - void set_soft_reference_policy(bool clear); - - // Non-strong reference processing - void process_non_strong_references(); - - // Page allocation - XPage* alloc_page(uint8_t type, size_t size, XAllocationFlags flags); - void undo_alloc_page(XPage* page); - void free_page(XPage* page, bool reclaimed); - void free_pages(const XArray* pages, bool reclaimed); - - // Object allocation - uintptr_t alloc_tlab(size_t size); - uintptr_t alloc_object(size_t size); - uintptr_t alloc_object_for_relocation(size_t size); - void undo_alloc_object_for_relocation(uintptr_t addr, size_t size); - bool has_alloc_stalled() const; - void check_out_of_memory(); - - // Marking - bool is_object_live(uintptr_t addr) const; - bool is_object_strongly_live(uintptr_t addr) const; - template void mark_object(uintptr_t addr); - void mark_start(); - void mark(bool initial); - void mark_flush_and_free(Thread* thread); - bool mark_end(); - void mark_free(); - void keep_alive(oop obj); - - // Relocation set - void select_relocation_set(); - void reset_relocation_set(); - - // Relocation - void relocate_start(); - uintptr_t relocate_object(uintptr_t addr); - uintptr_t remap_object(uintptr_t addr); - void relocate(); - - // Continuations - bool is_allocating(uintptr_t addr) const; - - // Iteration - void object_iterate(ObjectClosure* cl, bool visit_weaks); - ParallelObjectIteratorImpl* parallel_object_iterator(uint nworkers, bool visit_weaks); - void pages_do(XPageClosure* cl); - - // Serviceability - void serviceability_initialize(); - GCMemoryManager* serviceability_cycle_memory_manager(); - GCMemoryManager* serviceability_pause_memory_manager(); - MemoryPool* serviceability_memory_pool(); - XServiceabilityCounters* serviceability_counters(); - - // Printing - void print_on(outputStream* st) const; - void print_extended_on(outputStream* st) const; - bool print_location(outputStream* st, uintptr_t addr) const; - - // Verification - bool is_oop(uintptr_t addr) const; - void verify(); -}; - -#endif // SHARE_GC_X_XHEAP_HPP diff --git a/src/hotspot/share/gc/x/xHeap.inline.hpp b/src/hotspot/share/gc/x/xHeap.inline.hpp deleted file mode 100644 index 793a720017704..0000000000000 --- a/src/hotspot/share/gc/x/xHeap.inline.hpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XHEAP_INLINE_HPP -#define SHARE_GC_X_XHEAP_INLINE_HPP - -#include "gc/x/xHeap.hpp" - -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xForwardingTable.inline.hpp" -#include "gc/x/xMark.inline.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xPageTable.inline.hpp" -#include "utilities/debug.hpp" - -inline XHeap* XHeap::heap() { - assert(_heap != nullptr, "Not initialized"); - return _heap; -} - -inline ReferenceDiscoverer* XHeap::reference_discoverer() { - return &_reference_processor; -} - -inline bool XHeap::is_object_live(uintptr_t addr) const { - XPage* page = _page_table.get(addr); - return page->is_object_live(addr); -} - -inline bool XHeap::is_object_strongly_live(uintptr_t addr) const { - XPage* page = _page_table.get(addr); - return page->is_object_strongly_live(addr); -} - -template -inline void XHeap::mark_object(uintptr_t addr) { - assert(XGlobalPhase == XPhaseMark, "Mark not allowed"); - _mark.mark_object(addr); -} - -inline uintptr_t XHeap::alloc_tlab(size_t size) { - guarantee(size <= max_tlab_size(), "TLAB too large"); - return _object_allocator.alloc_object(size); -} - -inline uintptr_t XHeap::alloc_object(size_t size) { - uintptr_t addr = _object_allocator.alloc_object(size); - assert(XAddress::is_good_or_null(addr), "Bad address"); - - if (addr == 0) { - out_of_memory(); - } - - return addr; -} - -inline uintptr_t XHeap::alloc_object_for_relocation(size_t size) { - const uintptr_t addr = _object_allocator.alloc_object_for_relocation(&_page_table, size); - assert(XAddress::is_good_or_null(addr), "Bad address"); - return addr; -} - -inline void XHeap::undo_alloc_object_for_relocation(uintptr_t addr, size_t size) { - XPage* const page = _page_table.get(addr); - _object_allocator.undo_alloc_object_for_relocation(page, addr, size); -} - -inline uintptr_t XHeap::relocate_object(uintptr_t addr) { - assert(XGlobalPhase == XPhaseRelocate, "Relocate not allowed"); - - XForwarding* const forwarding = _forwarding_table.get(addr); - if (forwarding == nullptr) { - // Not forwarding - return XAddress::good(addr); - } - - // Relocate object - return _relocate.relocate_object(forwarding, XAddress::good(addr)); -} - -inline uintptr_t XHeap::remap_object(uintptr_t addr) { - assert(XGlobalPhase == XPhaseMark || - XGlobalPhase == XPhaseMarkCompleted, "Forward not allowed"); - - XForwarding* const forwarding = _forwarding_table.get(addr); - if (forwarding == nullptr) { - // Not forwarding - return XAddress::good(addr); - } - - // Forward object - return _relocate.forward_object(forwarding, XAddress::good(addr)); -} - -inline bool XHeap::has_alloc_stalled() const { - return _page_allocator.has_alloc_stalled(); -} - -inline void XHeap::check_out_of_memory() { - _page_allocator.check_out_of_memory(); -} - -inline bool XHeap::is_oop(uintptr_t addr) const { - return XAddress::is_good(addr) && is_object_aligned(addr) && is_in(addr); -} - -#endif // SHARE_GC_X_XHEAP_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xHeapIterator.cpp b/src/hotspot/share/gc/x/xHeapIterator.cpp deleted file mode 100644 index 47a6db26f6984..0000000000000 --- a/src/hotspot/share/gc/x/xHeapIterator.cpp +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "classfile/classLoaderDataGraph.hpp" -#include "gc/shared/barrierSetNMethod.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/shared/taskqueue.inline.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xCollectedHeap.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xGranuleMap.inline.hpp" -#include "gc/x/xHeapIterator.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xNMethod.hpp" -#include "gc/x/xOop.inline.hpp" -#include "memory/iterator.inline.hpp" -#include "utilities/bitMap.inline.hpp" - -class XHeapIteratorBitMap : public CHeapObj { -private: - CHeapBitMap _bitmap; - -public: - XHeapIteratorBitMap(size_t size_in_bits) : - _bitmap(size_in_bits, mtGC) {} - - bool try_set_bit(size_t index) { - return _bitmap.par_set_bit(index); - } -}; - -class XHeapIteratorContext { -private: - XHeapIterator* const _iter; - XHeapIteratorQueue* const _queue; - XHeapIteratorArrayQueue* const _array_queue; - const uint _worker_id; - XStatTimerDisable _timer_disable; - -public: - XHeapIteratorContext(XHeapIterator* iter, uint worker_id) : - _iter(iter), - _queue(_iter->_queues.queue(worker_id)), - _array_queue(_iter->_array_queues.queue(worker_id)), - _worker_id(worker_id) {} - - void mark_and_push(oop obj) const { - if (_iter->mark_object(obj)) { - _queue->push(obj); - } - } - - void push_array(const ObjArrayTask& array) const { - _array_queue->push(array); - } - - bool pop(oop& obj) const { - return _queue->pop_overflow(obj) || _queue->pop_local(obj); - } - - bool pop_array(ObjArrayTask& array) const { - return _array_queue->pop_overflow(array) || _array_queue->pop_local(array); - } - - bool steal(oop& obj) const { - return _iter->_queues.steal(_worker_id, obj); - } - - bool steal_array(ObjArrayTask& array) const { - return _iter->_array_queues.steal(_worker_id, array); - } - - bool is_drained() const { - return _queue->is_empty() && _array_queue->is_empty(); - } -}; - -template -class XHeapIteratorRootOopClosure : public OopClosure { -private: - const XHeapIteratorContext& _context; - - oop load_oop(oop* p) { - if (Weak) { - return NativeAccess::oop_load(p); - } - - return NativeAccess::oop_load(p); - } - -public: - XHeapIteratorRootOopClosure(const XHeapIteratorContext& context) : - _context(context) {} - - virtual void do_oop(oop* p) { - const oop obj = load_oop(p); - _context.mark_and_push(obj); - } - - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } -}; - -template -class XHeapIteratorOopClosure : public OopIterateClosure { -private: - const XHeapIteratorContext& _context; - const oop _base; - - oop load_oop(oop* p) { - assert(XCollectedHeap::heap()->is_in(p), "Should be in heap"); - - if (VisitReferents) { - return HeapAccess::oop_load_at(_base, _base->field_offset(p)); - } - - return HeapAccess::oop_load(p); - } - -public: - XHeapIteratorOopClosure(const XHeapIteratorContext& context, oop base) : - OopIterateClosure(), - _context(context), - _base(base) {} - - virtual ReferenceIterationMode reference_iteration_mode() { - return VisitReferents ? DO_FIELDS : DO_FIELDS_EXCEPT_REFERENT; - } - - virtual void do_oop(oop* p) { - const oop obj = load_oop(p); - _context.mark_and_push(obj); - } - - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } - - virtual bool do_metadata() { - return true; - } - - virtual void do_klass(Klass* k) { - ClassLoaderData* const cld = k->class_loader_data(); - XHeapIteratorOopClosure::do_cld(cld); - } - - virtual void do_cld(ClassLoaderData* cld) { - class NativeAccessClosure : public OopClosure { - private: - const XHeapIteratorContext& _context; - - public: - explicit NativeAccessClosure(const XHeapIteratorContext& context) : - _context(context) {} - - virtual void do_oop(oop* p) { - assert(!XCollectedHeap::heap()->is_in(p), "Should not be in heap"); - const oop obj = NativeAccess::oop_load(p); - _context.mark_and_push(obj); - } - - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } - }; - - NativeAccessClosure cl(_context); - cld->oops_do(&cl, ClassLoaderData::_claim_other); - } - - // Don't follow loom stack metadata; it's already followed in other ways through CLDs - virtual void do_nmethod(nmethod* nm) {} - virtual void do_method(Method* m) {} -}; - -XHeapIterator::XHeapIterator(uint nworkers, bool visit_weaks) : - _visit_weaks(visit_weaks), - _timer_disable(), - _bitmaps(XAddressOffsetMax), - _bitmaps_lock(), - _queues(nworkers), - _array_queues(nworkers), - _roots(ClassLoaderData::_claim_other), - _weak_roots(), - _terminator(nworkers, &_queues) { - - // Create queues - for (uint i = 0; i < _queues.size(); i++) { - XHeapIteratorQueue* const queue = new XHeapIteratorQueue(); - _queues.register_queue(i, queue); - } - - // Create array queues - for (uint i = 0; i < _array_queues.size(); i++) { - XHeapIteratorArrayQueue* const array_queue = new XHeapIteratorArrayQueue(); - _array_queues.register_queue(i, array_queue); - } -} - -XHeapIterator::~XHeapIterator() { - // Destroy bitmaps - XHeapIteratorBitMapsIterator iter(&_bitmaps); - for (XHeapIteratorBitMap* bitmap; iter.next(&bitmap);) { - delete bitmap; - } - - // Destroy array queues - for (uint i = 0; i < _array_queues.size(); i++) { - delete _array_queues.queue(i); - } - - // Destroy queues - for (uint i = 0; i < _queues.size(); i++) { - delete _queues.queue(i); - } - - // Clear claimed CLD bits - ClassLoaderDataGraph::clear_claimed_marks(ClassLoaderData::_claim_other); -} - -static size_t object_index_max() { - return XGranuleSize >> XObjectAlignmentSmallShift; -} - -static size_t object_index(oop obj) { - const uintptr_t addr = XOop::to_address(obj); - const uintptr_t offset = XAddress::offset(addr); - const uintptr_t mask = XGranuleSize - 1; - return (offset & mask) >> XObjectAlignmentSmallShift; -} - -XHeapIteratorBitMap* XHeapIterator::object_bitmap(oop obj) { - const uintptr_t offset = XAddress::offset(XOop::to_address(obj)); - XHeapIteratorBitMap* bitmap = _bitmaps.get_acquire(offset); - if (bitmap == nullptr) { - XLocker locker(&_bitmaps_lock); - bitmap = _bitmaps.get(offset); - if (bitmap == nullptr) { - // Install new bitmap - bitmap = new XHeapIteratorBitMap(object_index_max()); - _bitmaps.release_put(offset, bitmap); - } - } - - return bitmap; -} - -bool XHeapIterator::mark_object(oop obj) { - if (obj == nullptr) { - return false; - } - - XHeapIteratorBitMap* const bitmap = object_bitmap(obj); - const size_t index = object_index(obj); - return bitmap->try_set_bit(index); -} - -typedef ClaimingCLDToOopClosure XHeapIteratorCLDCLosure; - -class XHeapIteratorNMethodClosure : public NMethodClosure { -private: - OopClosure* const _cl; - BarrierSetNMethod* const _bs_nm; - -public: - XHeapIteratorNMethodClosure(OopClosure* cl) : - _cl(cl), - _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {} - - virtual void do_nmethod(nmethod* nm) { - // If ClassUnloading is turned off, all nmethods are considered strong, - // not only those on the call stacks. The heap iteration might happen - // before the concurrent processign of the code cache, make sure that - // all nmethods have been processed before visiting the oops. - _bs_nm->nmethod_entry_barrier(nm); - - XNMethod::nmethod_oops_do(nm, _cl); - } -}; - -class XHeapIteratorThreadClosure : public ThreadClosure { -private: - OopClosure* const _cl; - NMethodClosure* const _nm_cl; - -public: - XHeapIteratorThreadClosure(OopClosure* cl, NMethodClosure* nm_cl) : - _cl(cl), - _nm_cl(nm_cl) {} - - void do_thread(Thread* thread) { - thread->oops_do(_cl, _nm_cl); - } -}; - -void XHeapIterator::push_strong_roots(const XHeapIteratorContext& context) { - XHeapIteratorRootOopClosure cl(context); - XHeapIteratorCLDCLosure cld_cl(&cl); - XHeapIteratorNMethodClosure nm_cl(&cl); - XHeapIteratorThreadClosure thread_cl(&cl, &nm_cl); - - _roots.apply(&cl, - &cld_cl, - &thread_cl, - &nm_cl); -} - -void XHeapIterator::push_weak_roots(const XHeapIteratorContext& context) { - XHeapIteratorRootOopClosure cl(context); - _weak_roots.apply(&cl); -} - -template -void XHeapIterator::push_roots(const XHeapIteratorContext& context) { - push_strong_roots(context); - if (VisitWeaks) { - push_weak_roots(context); - } -} - -template -void XHeapIterator::follow_object(const XHeapIteratorContext& context, oop obj) { - XHeapIteratorOopClosure cl(context, obj); - obj->oop_iterate(&cl); -} - -void XHeapIterator::follow_array(const XHeapIteratorContext& context, oop obj) { - // Follow klass - XHeapIteratorOopClosure cl(context, obj); - cl.do_klass(obj->klass()); - - // Push array chunk - context.push_array(ObjArrayTask(obj, 0 /* index */)); -} - -void XHeapIterator::follow_array_chunk(const XHeapIteratorContext& context, const ObjArrayTask& array) { - const objArrayOop obj = objArrayOop(array.obj()); - const int length = obj->length(); - const int start = array.index(); - const int stride = MIN2(length - start, ObjArrayMarkingStride); - const int end = start + stride; - - // Push remaining array chunk first - if (end < length) { - context.push_array(ObjArrayTask(obj, end)); - } - - // Follow array chunk - XHeapIteratorOopClosure cl(context, obj); - obj->oop_iterate_range(&cl, start, end); -} - -template -void XHeapIterator::visit_and_follow(const XHeapIteratorContext& context, ObjectClosure* cl, oop obj) { - // Visit - cl->do_object(obj); - - // Follow - if (obj->is_objArray()) { - follow_array(context, obj); - } else { - follow_object(context, obj); - } -} - -template -void XHeapIterator::drain(const XHeapIteratorContext& context, ObjectClosure* cl) { - ObjArrayTask array; - oop obj; - - do { - while (context.pop(obj)) { - visit_and_follow(context, cl, obj); - } - - if (context.pop_array(array)) { - follow_array_chunk(context, array); - } - } while (!context.is_drained()); -} - -template -void XHeapIterator::steal(const XHeapIteratorContext& context, ObjectClosure* cl) { - ObjArrayTask array; - oop obj; - - if (context.steal_array(array)) { - follow_array_chunk(context, array); - } else if (context.steal(obj)) { - visit_and_follow(context, cl, obj); - } -} - -template -void XHeapIterator::drain_and_steal(const XHeapIteratorContext& context, ObjectClosure* cl) { - do { - drain(context, cl); - steal(context, cl); - } while (!context.is_drained() || !_terminator.offer_termination()); -} - -template -void XHeapIterator::object_iterate_inner(const XHeapIteratorContext& context, ObjectClosure* object_cl) { - push_roots(context); - drain_and_steal(context, object_cl); -} - -void XHeapIterator::object_iterate(ObjectClosure* cl, uint worker_id) { - XHeapIteratorContext context(this, worker_id); - - if (_visit_weaks) { - object_iterate_inner(context, cl); - } else { - object_iterate_inner(context, cl); - } -} diff --git a/src/hotspot/share/gc/x/xHeapIterator.hpp b/src/hotspot/share/gc/x/xHeapIterator.hpp deleted file mode 100644 index 0d990a616f886..0000000000000 --- a/src/hotspot/share/gc/x/xHeapIterator.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XHEAPITERATOR_HPP -#define SHARE_GC_X_XHEAPITERATOR_HPP - -#include "gc/shared/collectedHeap.hpp" -#include "gc/shared/taskTerminator.hpp" -#include "gc/shared/taskqueue.hpp" -#include "gc/x/xGranuleMap.hpp" -#include "gc/x/xLock.hpp" -#include "gc/x/xRootsIterator.hpp" -#include "gc/x/xStat.hpp" - -class XHeapIteratorBitMap; -class XHeapIteratorContext; - -using XHeapIteratorBitMaps = XGranuleMap; -using XHeapIteratorBitMapsIterator = XGranuleMapIterator; -using XHeapIteratorQueue = OverflowTaskQueue; -using XHeapIteratorQueues = GenericTaskQueueSet; -using XHeapIteratorArrayQueue = OverflowTaskQueue; -using XHeapIteratorArrayQueues = GenericTaskQueueSet; - -class XHeapIterator : public ParallelObjectIteratorImpl { - friend class XHeapIteratorContext; - -private: - const bool _visit_weaks; - XStatTimerDisable _timer_disable; - XHeapIteratorBitMaps _bitmaps; - XLock _bitmaps_lock; - XHeapIteratorQueues _queues; - XHeapIteratorArrayQueues _array_queues; - XRootsIterator _roots; - XWeakRootsIterator _weak_roots; - TaskTerminator _terminator; - - XHeapIteratorBitMap* object_bitmap(oop obj); - - bool mark_object(oop obj); - - void push_strong_roots(const XHeapIteratorContext& context); - void push_weak_roots(const XHeapIteratorContext& context); - - template - void push_roots(const XHeapIteratorContext& context); - - template - void follow_object(const XHeapIteratorContext& context, oop obj); - - void follow_array(const XHeapIteratorContext& context, oop obj); - void follow_array_chunk(const XHeapIteratorContext& context, const ObjArrayTask& array); - - template - void visit_and_follow(const XHeapIteratorContext& context, ObjectClosure* cl, oop obj); - - template - void drain(const XHeapIteratorContext& context, ObjectClosure* cl); - - template - void steal(const XHeapIteratorContext& context, ObjectClosure* cl); - - template - void drain_and_steal(const XHeapIteratorContext& context, ObjectClosure* cl); - - template - void object_iterate_inner(const XHeapIteratorContext& context, ObjectClosure* cl); - -public: - XHeapIterator(uint nworkers, bool visit_weaks); - virtual ~XHeapIterator(); - - virtual void object_iterate(ObjectClosure* cl, uint worker_id); -}; - -#endif // SHARE_GC_X_XHEAPITERATOR_HPP diff --git a/src/hotspot/share/gc/x/xHeuristics.cpp b/src/hotspot/share/gc/x/xHeuristics.cpp deleted file mode 100644 index ec89fa41919da..0000000000000 --- a/src/hotspot/share/gc/x/xHeuristics.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xCPU.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xHeuristics.hpp" -#include "runtime/globals.hpp" -#include "runtime/os.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/powerOfTwo.hpp" - -void XHeuristics::set_medium_page_size() { - // Set XPageSizeMedium so that a medium page occupies at most 3.125% of the - // max heap size. XPageSizeMedium is initially set to 0, which means medium - // pages are effectively disabled. It is adjusted only if XPageSizeMedium - // becomes larger than XPageSizeSmall. - const size_t min = XGranuleSize; - const size_t max = XGranuleSize * 16; - const size_t unclamped = MaxHeapSize * 0.03125; - const size_t clamped = clamp(unclamped, min, max); - const size_t size = round_down_power_of_2(clamped); - - if (size > XPageSizeSmall) { - // Enable medium pages - XPageSizeMedium = size; - XPageSizeMediumShift = log2i_exact(XPageSizeMedium); - XObjectSizeLimitMedium = XPageSizeMedium / 8; - XObjectAlignmentMediumShift = (int)XPageSizeMediumShift - 13; - XObjectAlignmentMedium = 1 << XObjectAlignmentMediumShift; - } -} - -size_t XHeuristics::relocation_headroom() { - // Calculate headroom needed to avoid in-place relocation. Each worker will try - // to allocate a small page, and all workers will share a single medium page. - const uint nworkers = UseDynamicNumberOfGCThreads ? ConcGCThreads : MAX2(ConcGCThreads, ParallelGCThreads); - return (nworkers * XPageSizeSmall) + XPageSizeMedium; -} - -bool XHeuristics::use_per_cpu_shared_small_pages() { - // Use per-CPU shared small pages only if these pages occupy at most 3.125% - // of the max heap size. Otherwise fall back to using a single shared small - // page. This is useful when using small heaps on large machines. - const size_t per_cpu_share = (MaxHeapSize * 0.03125) / XCPU::count(); - return per_cpu_share >= XPageSizeSmall; -} - -static uint nworkers_based_on_ncpus(double cpu_share_in_percent) { - return ceil(os::initial_active_processor_count() * cpu_share_in_percent / 100.0); -} - -static uint nworkers_based_on_heap_size(double heap_share_in_percent) { - const int nworkers = (MaxHeapSize * (heap_share_in_percent / 100.0)) / XPageSizeSmall; - return MAX2(nworkers, 1); -} - -static uint nworkers(double cpu_share_in_percent) { - // Cap number of workers so that they don't use more than 2% of the max heap - // during relocation. This is useful when using small heaps on large machines. - return MIN2(nworkers_based_on_ncpus(cpu_share_in_percent), - nworkers_based_on_heap_size(2.0)); -} - -uint XHeuristics::nparallel_workers() { - // Use 60% of the CPUs, rounded up. We would like to use as many threads as - // possible to increase parallelism. However, using a thread count that is - // close to the number of processors tends to lead to over-provisioning and - // scheduling latency issues. Using 60% of the active processors appears to - // be a fairly good balance. - return nworkers(60.0); -} - -uint XHeuristics::nconcurrent_workers() { - // The number of concurrent threads we would like to use heavily depends - // on the type of workload we are running. Using too many threads will have - // a negative impact on the application throughput, while using too few - // threads will prolong the GC-cycle and we then risk being out-run by the - // application. When in dynamic mode, use up to 25% of the active processors. - // When in non-dynamic mode, use 12.5% of the active processors. - return nworkers(UseDynamicNumberOfGCThreads ? 25.0 : 12.5); -} diff --git a/src/hotspot/share/gc/x/xHeuristics.hpp b/src/hotspot/share/gc/x/xHeuristics.hpp deleted file mode 100644 index 2ca798257b233..0000000000000 --- a/src/hotspot/share/gc/x/xHeuristics.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XHEURISTICS_HPP -#define SHARE_GC_X_XHEURISTICS_HPP - -#include "memory/allStatic.hpp" - -class XHeuristics : public AllStatic { -public: - static void set_medium_page_size(); - - static size_t relocation_headroom(); - - static bool use_per_cpu_shared_small_pages(); - - static uint nparallel_workers(); - static uint nconcurrent_workers(); -}; - -#endif // SHARE_GC_X_XHEURISTICS_HPP diff --git a/src/hotspot/share/gc/x/xInitialize.cpp b/src/hotspot/share/gc/x/xInitialize.cpp deleted file mode 100644 index 156be17971fce..0000000000000 --- a/src/hotspot/share/gc/x/xInitialize.cpp +++ /dev/null @@ -1,58 +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. - */ - -#include "precompiled.hpp" -#include "gc/x/xAddress.hpp" -#include "gc/x/xBarrierSet.hpp" -#include "gc/x/xCPU.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xHeuristics.hpp" -#include "gc/x/xInitialize.hpp" -#include "gc/x/xLargePages.hpp" -#include "gc/x/xNUMA.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xThreadLocalAllocBuffer.hpp" -#include "gc/x/xTracer.hpp" -#include "logging/log.hpp" -#include "runtime/vm_version.hpp" - -XInitialize::XInitialize(XBarrierSet* barrier_set) { - log_info(gc, init)("Initializing %s", XName); - log_info(gc, init)("Version: %s (%s)", - VM_Version::vm_release(), - VM_Version::jdk_debug_level()); - log_info(gc, init)("Using deprecated non-generational mode"); - - // Early initialization - XAddress::initialize(); - XNUMA::initialize(); - XCPU::initialize(); - XStatValue::initialize(); - XThreadLocalAllocBuffer::initialize(); - XTracer::initialize(); - XLargePages::initialize(); - XHeuristics::set_medium_page_size(); - XBarrierSet::set_barrier_set(barrier_set); - - pd_initialize(); -} diff --git a/src/hotspot/share/gc/x/xInitialize.hpp b/src/hotspot/share/gc/x/xInitialize.hpp deleted file mode 100644 index 30e7b65293ed6..0000000000000 --- a/src/hotspot/share/gc/x/xInitialize.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XINITIALIZE_HPP -#define SHARE_GC_X_XINITIALIZE_HPP - -#include "memory/allocation.hpp" - -class XBarrierSet; - -class XInitialize { -private: - void pd_initialize(); - -public: - XInitialize(XBarrierSet* barrier_set); -}; - -#endif // SHARE_GC_X_XINITIALIZE_HPP diff --git a/src/hotspot/share/gc/x/xLargePages.cpp b/src/hotspot/share/gc/x/xLargePages.cpp deleted file mode 100644 index 13da763c6a39c..0000000000000 --- a/src/hotspot/share/gc/x/xLargePages.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xLargePages.hpp" -#include "runtime/os.hpp" - -XLargePages::State XLargePages::_state; - -void XLargePages::initialize() { - pd_initialize(); - - log_info_p(gc, init)("Memory: " JULONG_FORMAT "M", os::physical_memory() / M); - log_info_p(gc, init)("Large Page Support: %s", to_string()); -} - -const char* XLargePages::to_string() { - switch (_state) { - case Explicit: - return "Enabled (Explicit)"; - - case Transparent: - return "Enabled (Transparent)"; - - default: - return "Disabled"; - } -} diff --git a/src/hotspot/share/gc/x/xLargePages.hpp b/src/hotspot/share/gc/x/xLargePages.hpp deleted file mode 100644 index 562e83ffbd088..0000000000000 --- a/src/hotspot/share/gc/x/xLargePages.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XLARGEPAGES_HPP -#define SHARE_GC_X_XLARGEPAGES_HPP - -#include "memory/allStatic.hpp" - -class XLargePages : public AllStatic { -private: - enum State { - Disabled, - Explicit, - Transparent - }; - - static State _state; - - static void pd_initialize(); - -public: - static void initialize(); - - static bool is_enabled(); - static bool is_explicit(); - static bool is_transparent(); - - static const char* to_string(); -}; - -#endif // SHARE_GC_X_XLARGEPAGES_HPP diff --git a/src/hotspot/share/gc/x/xLargePages.inline.hpp b/src/hotspot/share/gc/x/xLargePages.inline.hpp deleted file mode 100644 index 2f027c3b17605..0000000000000 --- a/src/hotspot/share/gc/x/xLargePages.inline.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XLARGEPAGES_INLINE_HPP -#define SHARE_GC_X_XLARGEPAGES_INLINE_HPP - -#include "gc/x/xLargePages.hpp" - -inline bool XLargePages::is_enabled() { - return _state != Disabled; -} - -inline bool XLargePages::is_explicit() { - return _state == Explicit; -} - -inline bool XLargePages::is_transparent() { - return _state == Transparent; -} - -#endif // SHARE_GC_X_XLARGEPAGES_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xList.hpp b/src/hotspot/share/gc/x/xList.hpp deleted file mode 100644 index d689704d65388..0000000000000 --- a/src/hotspot/share/gc/x/xList.hpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XLIST_HPP -#define SHARE_GC_X_XLIST_HPP - -#include "memory/allocation.hpp" -#include "utilities/globalDefinitions.hpp" - -template class XList; - -// Element in a doubly linked list -template -class XListNode { - friend class XList; - -private: - XListNode* _next; - XListNode* _prev; - - NONCOPYABLE(XListNode); - - void verify_links() const; - void verify_links_linked() const; - void verify_links_unlinked() const; - -public: - XListNode(); - ~XListNode(); -}; - -// Doubly linked list -template -class XList { -private: - XListNode _head; - size_t _size; - - NONCOPYABLE(XList); - - void verify_head() const; - - void insert(XListNode* before, XListNode* node); - - XListNode* cast_to_inner(T* elem) const; - T* cast_to_outer(XListNode* node) const; - -public: - XList(); - - size_t size() const; - bool is_empty() const; - - T* first() const; - T* last() const; - T* next(T* elem) const; - T* prev(T* elem) const; - - void insert_first(T* elem); - void insert_last(T* elem); - void insert_before(T* before, T* elem); - void insert_after(T* after, T* elem); - - void remove(T* elem); - T* remove_first(); - T* remove_last(); -}; - -template -class XListIteratorImpl : public StackObj { -private: - const XList* const _list; - T* _next; - -public: - XListIteratorImpl(const XList* list); - - bool next(T** elem); -}; - -template -class XListRemoveIteratorImpl : public StackObj { -private: - XList* const _list; - -public: - XListRemoveIteratorImpl(XList* list); - - bool next(T** elem); -}; - -template using XListIterator = XListIteratorImpl; -template using XListReverseIterator = XListIteratorImpl; -template using XListRemoveIterator = XListRemoveIteratorImpl; - -#endif // SHARE_GC_X_XLIST_HPP diff --git a/src/hotspot/share/gc/x/xList.inline.hpp b/src/hotspot/share/gc/x/xList.inline.hpp deleted file mode 100644 index 22ca5b820597a..0000000000000 --- a/src/hotspot/share/gc/x/xList.inline.hpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XLIST_INLINE_HPP -#define SHARE_GC_X_XLIST_INLINE_HPP - -#include "gc/x/xList.hpp" - -#include "utilities/debug.hpp" - -template -inline XListNode::XListNode() : - _next(this), - _prev(this) {} - -template -inline XListNode::~XListNode() { - verify_links_unlinked(); -} - -template -inline void XListNode::verify_links() const { - assert(_next->_prev == this, "Corrupt list node"); - assert(_prev->_next == this, "Corrupt list node"); -} - -template -inline void XListNode::verify_links_linked() const { - assert(_next != this, "Should be in a list"); - assert(_prev != this, "Should be in a list"); - verify_links(); -} - -template -inline void XListNode::verify_links_unlinked() const { - assert(_next == this, "Should not be in a list"); - assert(_prev == this, "Should not be in a list"); -} - -template -inline void XList::verify_head() const { - _head.verify_links(); -} - -template -inline void XList::insert(XListNode* before, XListNode* node) { - verify_head(); - - before->verify_links(); - node->verify_links_unlinked(); - - node->_prev = before; - node->_next = before->_next; - before->_next = node; - node->_next->_prev = node; - - before->verify_links_linked(); - node->verify_links_linked(); - - _size++; -} - -template -inline XListNode* XList::cast_to_inner(T* elem) const { - return &elem->_node; -} - -template -inline T* XList::cast_to_outer(XListNode* node) const { - return (T*)((uintptr_t)node - offset_of(T, _node)); -} - -template -inline XList::XList() : - _head(), - _size(0) { - verify_head(); -} - -template -inline size_t XList::size() const { - verify_head(); - return _size; -} - -template -inline bool XList::is_empty() const { - return size() == 0; -} - -template -inline T* XList::first() const { - return is_empty() ? nullptr : cast_to_outer(_head._next); -} - -template -inline T* XList::last() const { - return is_empty() ? nullptr : cast_to_outer(_head._prev); -} - -template -inline T* XList::next(T* elem) const { - verify_head(); - - XListNode* const node = cast_to_inner(elem); - node->verify_links_linked(); - - XListNode* const next = node->_next; - next->verify_links_linked(); - - return (next == &_head) ? nullptr : cast_to_outer(next); -} - -template -inline T* XList::prev(T* elem) const { - verify_head(); - - XListNode* const node = cast_to_inner(elem); - node->verify_links_linked(); - - XListNode* const prev = node->_prev; - prev->verify_links_linked(); - - return (prev == &_head) ? nullptr : cast_to_outer(prev); -} - -template -inline void XList::insert_first(T* elem) { - insert(&_head, cast_to_inner(elem)); -} - -template -inline void XList::insert_last(T* elem) { - insert(_head._prev, cast_to_inner(elem)); -} - -template -inline void XList::insert_before(T* before, T* elem) { - insert(cast_to_inner(before)->_prev, cast_to_inner(elem)); -} - -template -inline void XList::insert_after(T* after, T* elem) { - insert(cast_to_inner(after), cast_to_inner(elem)); -} - -template -inline void XList::remove(T* elem) { - verify_head(); - - XListNode* const node = cast_to_inner(elem); - node->verify_links_linked(); - - XListNode* const next = node->_next; - XListNode* const prev = node->_prev; - next->verify_links_linked(); - prev->verify_links_linked(); - - node->_next = prev->_next; - node->_prev = next->_prev; - node->verify_links_unlinked(); - - next->_prev = prev; - prev->_next = next; - next->verify_links(); - prev->verify_links(); - - _size--; -} - -template -inline T* XList::remove_first() { - T* elem = first(); - if (elem != nullptr) { - remove(elem); - } - - return elem; -} - -template -inline T* XList::remove_last() { - T* elem = last(); - if (elem != nullptr) { - remove(elem); - } - - return elem; -} - -template -inline XListIteratorImpl::XListIteratorImpl(const XList* list) : - _list(list), - _next(Forward ? list->first() : list->last()) {} - -template -inline bool XListIteratorImpl::next(T** elem) { - if (_next != nullptr) { - *elem = _next; - _next = Forward ? _list->next(_next) : _list->prev(_next); - return true; - } - - // No more elements - return false; -} - -template -inline XListRemoveIteratorImpl::XListRemoveIteratorImpl(XList* list) : - _list(list) {} - -template -inline bool XListRemoveIteratorImpl::next(T** elem) { - *elem = Forward ? _list->remove_first() : _list->remove_last(); - return *elem != nullptr; -} - -#endif // SHARE_GC_X_XLIST_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xLiveMap.cpp b/src/hotspot/share/gc/x/xLiveMap.cpp deleted file mode 100644 index 91ef99754f791..0000000000000 --- a/src/hotspot/share/gc/x/xLiveMap.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xLiveMap.inline.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xThread.inline.hpp" -#include "logging/log.hpp" -#include "runtime/atomic.hpp" -#include "utilities/debug.hpp" -#include "utilities/powerOfTwo.hpp" - -static const XStatCounter XCounterMarkSeqNumResetContention("Contention", "Mark SeqNum Reset Contention", XStatUnitOpsPerSecond); -static const XStatCounter XCounterMarkSegmentResetContention("Contention", "Mark Segment Reset Contention", XStatUnitOpsPerSecond); - -static size_t bitmap_size(uint32_t size, size_t nsegments) { - // We need at least one bit per segment - return MAX2(size, nsegments) * 2; -} - -XLiveMap::XLiveMap(uint32_t size) : - _seqnum(0), - _live_objects(0), - _live_bytes(0), - _segment_live_bits(0), - _segment_claim_bits(0), - _bitmap(bitmap_size(size, nsegments)), - _segment_shift(exact_log2(segment_size())) {} - -void XLiveMap::reset(size_t index) { - const uint32_t seqnum_initializing = (uint32_t)-1; - bool contention = false; - - // Multiple threads can enter here, make sure only one of them - // resets the marking information while the others busy wait. - for (uint32_t seqnum = Atomic::load_acquire(&_seqnum); - seqnum != XGlobalSeqNum; - seqnum = Atomic::load_acquire(&_seqnum)) { - if ((seqnum != seqnum_initializing) && - (Atomic::cmpxchg(&_seqnum, seqnum, seqnum_initializing) == seqnum)) { - // Reset marking information - _live_bytes = 0; - _live_objects = 0; - - // Clear segment claimed/live bits - segment_live_bits().clear(); - segment_claim_bits().clear(); - - assert(_seqnum == seqnum_initializing, "Invalid"); - - // Make sure the newly reset marking information is ordered - // before the update of the page seqnum, such that when the - // up-to-date seqnum is load acquired, the bit maps will not - // contain stale information. - Atomic::release_store(&_seqnum, XGlobalSeqNum); - break; - } - - // Mark reset contention - if (!contention) { - // Count contention once - XStatInc(XCounterMarkSeqNumResetContention); - contention = true; - - log_trace(gc)("Mark seqnum reset contention, thread: " PTR_FORMAT " (%s), map: " PTR_FORMAT ", bit: " SIZE_FORMAT, - XThread::id(), XThread::name(), p2i(this), index); - } - } -} - -void XLiveMap::reset_segment(BitMap::idx_t segment) { - bool contention = false; - - if (!claim_segment(segment)) { - // Already claimed, wait for live bit to be set - while (!is_segment_live(segment)) { - // Mark reset contention - if (!contention) { - // Count contention once - XStatInc(XCounterMarkSegmentResetContention); - contention = true; - - log_trace(gc)("Mark segment reset contention, thread: " PTR_FORMAT " (%s), map: " PTR_FORMAT ", segment: " SIZE_FORMAT, - XThread::id(), XThread::name(), p2i(this), segment); - } - } - - // Segment is live - return; - } - - // Segment claimed, clear it - const BitMap::idx_t start_index = segment_start(segment); - const BitMap::idx_t end_index = segment_end(segment); - if (segment_size() / BitsPerWord >= 32) { - _bitmap.clear_large_range(start_index, end_index); - } else { - _bitmap.clear_range(start_index, end_index); - } - - // Set live bit - const bool success = set_segment_live(segment); - assert(success, "Should never fail"); -} - -void XLiveMap::resize(uint32_t size) { - const size_t new_bitmap_size = bitmap_size(size, nsegments); - if (_bitmap.size() != new_bitmap_size) { - _bitmap.reinitialize(new_bitmap_size, false /* clear */); - _segment_shift = exact_log2(segment_size()); - } -} diff --git a/src/hotspot/share/gc/x/xLiveMap.hpp b/src/hotspot/share/gc/x/xLiveMap.hpp deleted file mode 100644 index 7bad774c6c6c9..0000000000000 --- a/src/hotspot/share/gc/x/xLiveMap.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * 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_GC_X_XLIVEMAP_HPP -#define SHARE_GC_X_XLIVEMAP_HPP - -#include "gc/x/xBitMap.hpp" -#include "memory/allocation.hpp" - -class ObjectClosure; - -class XLiveMap { - friend class XLiveMapTest; - -private: - static const size_t nsegments = 64; - - volatile uint32_t _seqnum; - volatile uint32_t _live_objects; - volatile size_t _live_bytes; - BitMap::bm_word_t _segment_live_bits; - BitMap::bm_word_t _segment_claim_bits; - XBitMap _bitmap; - size_t _segment_shift; - - const BitMapView segment_live_bits() const; - const BitMapView segment_claim_bits() const; - - BitMapView segment_live_bits(); - BitMapView segment_claim_bits(); - - BitMap::idx_t segment_size() const; - - BitMap::idx_t segment_start(BitMap::idx_t segment) const; - BitMap::idx_t segment_end(BitMap::idx_t segment) const; - - bool is_segment_live(BitMap::idx_t segment) const; - bool set_segment_live(BitMap::idx_t segment); - - BitMap::idx_t first_live_segment() const; - BitMap::idx_t next_live_segment(BitMap::idx_t segment) const; - BitMap::idx_t index_to_segment(BitMap::idx_t index) const; - - bool claim_segment(BitMap::idx_t segment); - - void reset(size_t index); - void reset_segment(BitMap::idx_t segment); - - void iterate_segment(ObjectClosure* cl, BitMap::idx_t segment, uintptr_t page_start, size_t page_object_alignment_shift); - -public: - XLiveMap(uint32_t size); - - void reset(); - void resize(uint32_t size); - - bool is_marked() const; - - uint32_t live_objects() const; - size_t live_bytes() const; - - bool get(size_t index) const; - bool set(size_t index, bool finalizable, bool& inc_live); - - void inc_live(uint32_t objects, size_t bytes); - - void iterate(ObjectClosure* cl, uintptr_t page_start, size_t page_object_alignment_shift); -}; - -#endif // SHARE_GC_X_XLIVEMAP_HPP diff --git a/src/hotspot/share/gc/x/xLiveMap.inline.hpp b/src/hotspot/share/gc/x/xLiveMap.inline.hpp deleted file mode 100644 index f836f9ab4c21f..0000000000000 --- a/src/hotspot/share/gc/x/xLiveMap.inline.hpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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 - * 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_GC_X_XLIVEMAP_INLINE_HPP -#define SHARE_GC_X_XLIVEMAP_INLINE_HPP - -#include "gc/x/xLiveMap.hpp" - -#include "gc/x/xBitMap.inline.hpp" -#include "gc/x/xMark.hpp" -#include "gc/x/xOop.inline.hpp" -#include "gc/x/xUtils.inline.hpp" -#include "runtime/atomic.hpp" -#include "utilities/bitMap.inline.hpp" -#include "utilities/debug.hpp" - -inline void XLiveMap::reset() { - _seqnum = 0; -} - -inline bool XLiveMap::is_marked() const { - return Atomic::load_acquire(&_seqnum) == XGlobalSeqNum; -} - -inline uint32_t XLiveMap::live_objects() const { - assert(XGlobalPhase != XPhaseMark, "Invalid phase"); - return _live_objects; -} - -inline size_t XLiveMap::live_bytes() const { - assert(XGlobalPhase != XPhaseMark, "Invalid phase"); - return _live_bytes; -} - -inline const BitMapView XLiveMap::segment_live_bits() const { - return BitMapView(const_cast(&_segment_live_bits), nsegments); -} - -inline const BitMapView XLiveMap::segment_claim_bits() const { - return BitMapView(const_cast(&_segment_claim_bits), nsegments); -} - -inline BitMapView XLiveMap::segment_live_bits() { - return BitMapView(&_segment_live_bits, nsegments); -} - -inline BitMapView XLiveMap::segment_claim_bits() { - return BitMapView(&_segment_claim_bits, nsegments); -} - -inline bool XLiveMap::is_segment_live(BitMap::idx_t segment) const { - return segment_live_bits().par_at(segment); -} - -inline bool XLiveMap::set_segment_live(BitMap::idx_t segment) { - return segment_live_bits().par_set_bit(segment, memory_order_release); -} - -inline bool XLiveMap::claim_segment(BitMap::idx_t segment) { - return segment_claim_bits().par_set_bit(segment, memory_order_acq_rel); -} - -inline BitMap::idx_t XLiveMap::first_live_segment() const { - return segment_live_bits().find_first_set_bit(0, nsegments); -} - -inline BitMap::idx_t XLiveMap::next_live_segment(BitMap::idx_t segment) const { - return segment_live_bits().find_first_set_bit(segment + 1, nsegments); -} - -inline BitMap::idx_t XLiveMap::segment_size() const { - return _bitmap.size() / nsegments; -} - -inline BitMap::idx_t XLiveMap::index_to_segment(BitMap::idx_t index) const { - return index >> _segment_shift; -} - -inline bool XLiveMap::get(size_t index) const { - BitMap::idx_t segment = index_to_segment(index); - return is_marked() && // Page is marked - is_segment_live(segment) && // Segment is marked - _bitmap.par_at(index, memory_order_relaxed); // Object is marked -} - -inline bool XLiveMap::set(size_t index, bool finalizable, bool& inc_live) { - if (!is_marked()) { - // First object to be marked during this - // cycle, reset marking information. - reset(index); - } - - const BitMap::idx_t segment = index_to_segment(index); - if (!is_segment_live(segment)) { - // First object to be marked in this segment during - // this cycle, reset segment bitmap. - reset_segment(segment); - } - - return _bitmap.par_set_bit_pair(index, finalizable, inc_live); -} - -inline void XLiveMap::inc_live(uint32_t objects, size_t bytes) { - Atomic::add(&_live_objects, objects); - Atomic::add(&_live_bytes, bytes); -} - -inline BitMap::idx_t XLiveMap::segment_start(BitMap::idx_t segment) const { - return segment_size() * segment; -} - -inline BitMap::idx_t XLiveMap::segment_end(BitMap::idx_t segment) const { - return segment_start(segment) + segment_size(); -} - -inline void XLiveMap::iterate_segment(ObjectClosure* cl, BitMap::idx_t segment, uintptr_t page_start, size_t page_object_alignment_shift) { - assert(is_segment_live(segment), "Must be"); - - const BitMap::idx_t start_index = segment_start(segment); - const BitMap::idx_t end_index = segment_end(segment); - BitMap::idx_t index = _bitmap.find_first_set_bit(start_index, end_index); - - while (index < end_index) { - // Calculate object address - const uintptr_t addr = page_start + ((index / 2) << page_object_alignment_shift); - - // Get the size of the object before calling the closure, which - // might overwrite the object in case we are relocating in-place. - const size_t size = XUtils::object_size(addr); - - // Apply closure - cl->do_object(XOop::from_address(addr)); - - // Find next bit after this object - const uintptr_t next_addr = align_up(addr + size, 1 << page_object_alignment_shift); - const BitMap::idx_t next_index = ((next_addr - page_start) >> page_object_alignment_shift) * 2; - if (next_index >= end_index) { - // End of live map - break; - } - - index = _bitmap.find_first_set_bit(next_index, end_index); - } -} - -inline void XLiveMap::iterate(ObjectClosure* cl, uintptr_t page_start, size_t page_object_alignment_shift) { - if (is_marked()) { - for (BitMap::idx_t segment = first_live_segment(); segment < nsegments; segment = next_live_segment(segment)) { - // For each live segment - iterate_segment(cl, segment, page_start, page_object_alignment_shift); - } - } -} - -#endif // SHARE_GC_X_XLIVEMAP_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xLock.hpp b/src/hotspot/share/gc/x/xLock.hpp deleted file mode 100644 index 2ba612d033cc0..0000000000000 --- a/src/hotspot/share/gc/x/xLock.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XLOCK_HPP -#define SHARE_GC_X_XLOCK_HPP - -#include "memory/allocation.hpp" -#include "runtime/mutex.hpp" - -class XLock { -private: - PlatformMutex _lock; - -public: - void lock(); - bool try_lock(); - void unlock(); -}; - -class XReentrantLock { -private: - XLock _lock; - Thread* volatile _owner; - uint64_t _count; - -public: - XReentrantLock(); - - void lock(); - void unlock(); - - bool is_owned() const; -}; - -class XConditionLock { -private: - PlatformMonitor _lock; - -public: - void lock(); - bool try_lock(); - void unlock(); - - bool wait(uint64_t millis = 0); - void notify(); - void notify_all(); -}; - -template -class XLocker : public StackObj { -private: - T* const _lock; - -public: - XLocker(T* lock); - ~XLocker(); -}; - -#endif // SHARE_GC_X_XLOCK_HPP diff --git a/src/hotspot/share/gc/x/xLock.inline.hpp b/src/hotspot/share/gc/x/xLock.inline.hpp deleted file mode 100644 index a72b65aa22852..0000000000000 --- a/src/hotspot/share/gc/x/xLock.inline.hpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XLOCK_INLINE_HPP -#define SHARE_GC_X_XLOCK_INLINE_HPP - -#include "gc/x/xLock.hpp" - -#include "runtime/atomic.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/os.inline.hpp" -#include "utilities/debug.hpp" - -inline void XLock::lock() { - _lock.lock(); -} - -inline bool XLock::try_lock() { - return _lock.try_lock(); -} - -inline void XLock::unlock() { - _lock.unlock(); -} - -inline XReentrantLock::XReentrantLock() : - _lock(), - _owner(nullptr), - _count(0) {} - -inline void XReentrantLock::lock() { - Thread* const thread = Thread::current(); - Thread* const owner = Atomic::load(&_owner); - - if (owner != thread) { - _lock.lock(); - Atomic::store(&_owner, thread); - } - - _count++; -} - -inline void XReentrantLock::unlock() { - assert(is_owned(), "Invalid owner"); - assert(_count > 0, "Invalid count"); - - _count--; - - if (_count == 0) { - Atomic::store(&_owner, (Thread*)nullptr); - _lock.unlock(); - } -} - -inline bool XReentrantLock::is_owned() const { - Thread* const thread = Thread::current(); - Thread* const owner = Atomic::load(&_owner); - return owner == thread; -} - -inline void XConditionLock::lock() { - _lock.lock(); -} - -inline bool XConditionLock::try_lock() { - return _lock.try_lock(); -} - -inline void XConditionLock::unlock() { - _lock.unlock(); -} - -inline bool XConditionLock::wait(uint64_t millis) { - return _lock.wait(millis) == OS_OK; -} - -inline void XConditionLock::notify() { - _lock.notify(); -} - -inline void XConditionLock::notify_all() { - _lock.notify_all(); -} - -template -inline XLocker::XLocker(T* lock) : - _lock(lock) { - if (_lock != nullptr) { - _lock->lock(); - } -} - -template -inline XLocker::~XLocker() { - if (_lock != nullptr) { - _lock->unlock(); - } -} - -#endif // SHARE_GC_X_XLOCK_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xMark.cpp b/src/hotspot/share/gc/x/xMark.cpp deleted file mode 100644 index 016c570261552..0000000000000 --- a/src/hotspot/share/gc/x/xMark.cpp +++ /dev/null @@ -1,877 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "classfile/classLoaderData.hpp" -#include "classfile/classLoaderDataGraph.hpp" -#include "classfile/javaClasses.inline.hpp" -#include "code/nmethod.hpp" -#include "gc/shared/continuationGCSupport.inline.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/shared/stringdedup/stringDedup.hpp" -#include "gc/shared/suspendibleThreadSet.hpp" -#include "gc/x/xAbort.inline.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xMark.inline.hpp" -#include "gc/x/xMarkCache.inline.hpp" -#include "gc/x/xMarkContext.inline.hpp" -#include "gc/x/xMarkStack.inline.hpp" -#include "gc/x/xMarkTerminate.inline.hpp" -#include "gc/x/xNMethod.hpp" -#include "gc/x/xOop.inline.hpp" -#include "gc/x/xPage.hpp" -#include "gc/x/xPageTable.inline.hpp" -#include "gc/x/xRootsIterator.hpp" -#include "gc/x/xStackWatermark.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xThread.inline.hpp" -#include "gc/x/xThreadLocalAllocBuffer.hpp" -#include "gc/x/xUtils.inline.hpp" -#include "gc/x/xWorkers.hpp" -#include "logging/log.hpp" -#include "memory/iterator.inline.hpp" -#include "oops/objArrayOop.inline.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/atomic.hpp" -#include "runtime/continuation.hpp" -#include "runtime/handshake.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/prefetch.inline.hpp" -#include "runtime/safepointMechanism.hpp" -#include "runtime/stackWatermark.hpp" -#include "runtime/stackWatermarkSet.inline.hpp" -#include "runtime/threads.hpp" -#include "utilities/align.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/powerOfTwo.hpp" -#include "utilities/ticks.hpp" - -static const XStatSubPhase XSubPhaseConcurrentMark("Concurrent Mark"); -static const XStatSubPhase XSubPhaseConcurrentMarkTryFlush("Concurrent Mark Try Flush"); -static const XStatSubPhase XSubPhaseConcurrentMarkTryTerminate("Concurrent Mark Try Terminate"); -static const XStatSubPhase XSubPhaseMarkTryComplete("Pause Mark Try Complete"); - -XMark::XMark(XWorkers* workers, XPageTable* page_table) : - _workers(workers), - _page_table(page_table), - _allocator(), - _stripes(), - _terminate(), - _work_terminateflush(true), - _work_nproactiveflush(0), - _work_nterminateflush(0), - _nproactiveflush(0), - _nterminateflush(0), - _ntrycomplete(0), - _ncontinue(0), - _nworkers(0) {} - -bool XMark::is_initialized() const { - return _allocator.is_initialized(); -} - -size_t XMark::calculate_nstripes(uint nworkers) const { - // Calculate the number of stripes from the number of workers we use, - // where the number of stripes must be a power of two and we want to - // have at least one worker per stripe. - const size_t nstripes = round_down_power_of_2(nworkers); - return MIN2(nstripes, XMarkStripesMax); -} - -void XMark::start() { - // Verification - if (ZVerifyMarking) { - verify_all_stacks_empty(); - } - - // Increment global sequence number to invalidate - // marking information for all pages. - XGlobalSeqNum++; - - // Note that we start a marking cycle. - // Unlike other GCs, the color switch implicitly changes the nmethods - // to be armed, and the thread-local disarm values are lazily updated - // when JavaThreads wake up from safepoints. - CodeCache::on_gc_marking_cycle_start(); - - // Reset flush/continue counters - _nproactiveflush = 0; - _nterminateflush = 0; - _ntrycomplete = 0; - _ncontinue = 0; - - // Set number of workers to use - _nworkers = _workers->active_workers(); - - // Set number of mark stripes to use, based on number - // of workers we will use in the concurrent mark phase. - const size_t nstripes = calculate_nstripes(_nworkers); - _stripes.set_nstripes(nstripes); - - // Update statistics - XStatMark::set_at_mark_start(nstripes); - - // Print worker/stripe distribution - LogTarget(Debug, gc, marking) log; - if (log.is_enabled()) { - log.print("Mark Worker/Stripe Distribution"); - for (uint worker_id = 0; worker_id < _nworkers; worker_id++) { - const XMarkStripe* const stripe = _stripes.stripe_for_worker(_nworkers, worker_id); - const size_t stripe_id = _stripes.stripe_id(stripe); - log.print(" Worker %u(%u) -> Stripe " SIZE_FORMAT "(" SIZE_FORMAT ")", - worker_id, _nworkers, stripe_id, nstripes); - } - } -} - -void XMark::prepare_work() { - assert(_nworkers == _workers->active_workers(), "Invalid number of workers"); - - // Set number of active workers - _terminate.reset(_nworkers); - - // Reset flush counters - _work_nproactiveflush = _work_nterminateflush = 0; - _work_terminateflush = true; -} - -void XMark::finish_work() { - // Accumulate proactive/terminate flush counters - _nproactiveflush += _work_nproactiveflush; - _nterminateflush += _work_nterminateflush; -} - -bool XMark::is_array(uintptr_t addr) const { - return XOop::from_address(addr)->is_objArray(); -} - -void XMark::push_partial_array(uintptr_t addr, size_t size, bool finalizable) { - assert(is_aligned(addr, XMarkPartialArrayMinSize), "Address misaligned"); - XMarkThreadLocalStacks* const stacks = XThreadLocalData::stacks(Thread::current()); - XMarkStripe* const stripe = _stripes.stripe_for_addr(addr); - const uintptr_t offset = XAddress::offset(addr) >> XMarkPartialArrayMinSizeShift; - const uintptr_t length = size / oopSize; - const XMarkStackEntry entry(offset, length, finalizable); - - log_develop_trace(gc, marking)("Array push partial: " PTR_FORMAT " (" SIZE_FORMAT "), stripe: " SIZE_FORMAT, - addr, size, _stripes.stripe_id(stripe)); - - stacks->push(&_allocator, &_stripes, stripe, entry, false /* publish */); -} - -void XMark::follow_small_array(uintptr_t addr, size_t size, bool finalizable) { - assert(size <= XMarkPartialArrayMinSize, "Too large, should be split"); - const size_t length = size / oopSize; - - log_develop_trace(gc, marking)("Array follow small: " PTR_FORMAT " (" SIZE_FORMAT ")", addr, size); - - XBarrier::mark_barrier_on_oop_array((oop*)addr, length, finalizable); -} - -void XMark::follow_large_array(uintptr_t addr, size_t size, bool finalizable) { - assert(size <= (size_t)arrayOopDesc::max_array_length(T_OBJECT) * oopSize, "Too large"); - assert(size > XMarkPartialArrayMinSize, "Too small, should not be split"); - const uintptr_t start = addr; - const uintptr_t end = start + size; - - // Calculate the aligned middle start/end/size, where the middle start - // should always be greater than the start (hence the +1 below) to make - // sure we always do some follow work, not just split the array into pieces. - const uintptr_t middle_start = align_up(start + 1, XMarkPartialArrayMinSize); - const size_t middle_size = align_down(end - middle_start, XMarkPartialArrayMinSize); - const uintptr_t middle_end = middle_start + middle_size; - - log_develop_trace(gc, marking)("Array follow large: " PTR_FORMAT "-" PTR_FORMAT" (" SIZE_FORMAT "), " - "middle: " PTR_FORMAT "-" PTR_FORMAT " (" SIZE_FORMAT ")", - start, end, size, middle_start, middle_end, middle_size); - - // Push unaligned trailing part - if (end > middle_end) { - const uintptr_t trailing_addr = middle_end; - const size_t trailing_size = end - middle_end; - push_partial_array(trailing_addr, trailing_size, finalizable); - } - - // Push aligned middle part(s) - uintptr_t partial_addr = middle_end; - while (partial_addr > middle_start) { - const size_t parts = 2; - const size_t partial_size = align_up((partial_addr - middle_start) / parts, XMarkPartialArrayMinSize); - partial_addr -= partial_size; - push_partial_array(partial_addr, partial_size, finalizable); - } - - // Follow leading part - assert(start < middle_start, "Miscalculated middle start"); - const uintptr_t leading_addr = start; - const size_t leading_size = middle_start - start; - follow_small_array(leading_addr, leading_size, finalizable); -} - -void XMark::follow_array(uintptr_t addr, size_t size, bool finalizable) { - if (size <= XMarkPartialArrayMinSize) { - follow_small_array(addr, size, finalizable); - } else { - follow_large_array(addr, size, finalizable); - } -} - -void XMark::follow_partial_array(XMarkStackEntry entry, bool finalizable) { - const uintptr_t addr = XAddress::good(entry.partial_array_offset() << XMarkPartialArrayMinSizeShift); - const size_t size = entry.partial_array_length() * oopSize; - - follow_array(addr, size, finalizable); -} - -template -class XMarkBarrierOopClosure : public ClaimMetadataVisitingOopIterateClosure { -public: - XMarkBarrierOopClosure() : - ClaimMetadataVisitingOopIterateClosure(finalizable - ? ClassLoaderData::_claim_finalizable - : ClassLoaderData::_claim_strong, - finalizable - ? nullptr - : XHeap::heap()->reference_discoverer()) {} - - virtual void do_oop(oop* p) { - XBarrier::mark_barrier_on_oop_field(p, finalizable); - } - - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } - - virtual void do_nmethod(nmethod* nm) { - assert(!finalizable, "Can't handle finalizable marking of nmethods"); - nm->run_nmethod_entry_barrier(); - } -}; - -void XMark::follow_array_object(objArrayOop obj, bool finalizable) { - if (finalizable) { - XMarkBarrierOopClosure cl; - cl.do_klass(obj->klass()); - } else { - XMarkBarrierOopClosure cl; - cl.do_klass(obj->klass()); - } - - const uintptr_t addr = (uintptr_t)obj->base(); - const size_t size = (size_t)obj->length() * oopSize; - - follow_array(addr, size, finalizable); -} - -void XMark::follow_object(oop obj, bool finalizable) { - if (ContinuationGCSupport::relativize_stack_chunk(obj)) { - // Loom doesn't support mixing of finalizable marking and strong marking of - // stack chunks. See: RelativizeDerivedOopClosure. - XMarkBarrierOopClosure cl; - obj->oop_iterate(&cl); - return; - } - - if (finalizable) { - XMarkBarrierOopClosure cl; - obj->oop_iterate(&cl); - } else { - XMarkBarrierOopClosure cl; - obj->oop_iterate(&cl); - } -} - -static void try_deduplicate(XMarkContext* context, oop obj) { - if (!StringDedup::is_enabled()) { - // Not enabled - return; - } - - if (!java_lang_String::is_instance(obj)) { - // Not a String object - return; - } - - if (java_lang_String::test_and_set_deduplication_requested(obj)) { - // Already requested deduplication - return; - } - - // Request deduplication - context->string_dedup_requests()->add(obj); -} - -void XMark::mark_and_follow(XMarkContext* context, XMarkStackEntry entry) { - // Decode flags - const bool finalizable = entry.finalizable(); - const bool partial_array = entry.partial_array(); - - if (partial_array) { - follow_partial_array(entry, finalizable); - return; - } - - // Decode object address and additional flags - const uintptr_t addr = entry.object_address(); - const bool mark = entry.mark(); - bool inc_live = entry.inc_live(); - const bool follow = entry.follow(); - - XPage* const page = _page_table->get(addr); - assert(page->is_relocatable(), "Invalid page state"); - - // Mark - if (mark && !page->mark_object(addr, finalizable, inc_live)) { - // Already marked - return; - } - - // Increment live - if (inc_live) { - // Update live objects/bytes for page. We use the aligned object - // size since that is the actual number of bytes used on the page - // and alignment paddings can never be reclaimed. - const size_t size = XUtils::object_size(addr); - const size_t aligned_size = align_up(size, page->object_alignment()); - context->cache()->inc_live(page, aligned_size); - } - - // Follow - if (follow) { - if (is_array(addr)) { - follow_array_object(objArrayOop(XOop::from_address(addr)), finalizable); - } else { - const oop obj = XOop::from_address(addr); - follow_object(obj, finalizable); - - if (!finalizable) { - // Try deduplicate - try_deduplicate(context, obj); - } - } - } -} - -template -bool XMark::drain(XMarkContext* context, T* timeout) { - XMarkStripe* const stripe = context->stripe(); - XMarkThreadLocalStacks* const stacks = context->stacks(); - XMarkStackEntry entry; - - // Drain stripe stacks - while (stacks->pop(&_allocator, &_stripes, stripe, entry)) { - mark_and_follow(context, entry); - - // Check timeout - if (timeout->has_expired()) { - // Timeout - return false; - } - } - - // Success - return !timeout->has_expired(); -} - -bool XMark::try_steal_local(XMarkContext* context) { - XMarkStripe* const stripe = context->stripe(); - XMarkThreadLocalStacks* const stacks = context->stacks(); - - // Try to steal a local stack from another stripe - for (XMarkStripe* victim_stripe = _stripes.stripe_next(stripe); - victim_stripe != stripe; - victim_stripe = _stripes.stripe_next(victim_stripe)) { - XMarkStack* const stack = stacks->steal(&_stripes, victim_stripe); - if (stack != nullptr) { - // Success, install the stolen stack - stacks->install(&_stripes, stripe, stack); - return true; - } - } - - // Nothing to steal - return false; -} - -bool XMark::try_steal_global(XMarkContext* context) { - XMarkStripe* const stripe = context->stripe(); - XMarkThreadLocalStacks* const stacks = context->stacks(); - - // Try to steal a stack from another stripe - for (XMarkStripe* victim_stripe = _stripes.stripe_next(stripe); - victim_stripe != stripe; - victim_stripe = _stripes.stripe_next(victim_stripe)) { - XMarkStack* const stack = victim_stripe->steal_stack(); - if (stack != nullptr) { - // Success, install the stolen stack - stacks->install(&_stripes, stripe, stack); - return true; - } - } - - // Nothing to steal - return false; -} - -bool XMark::try_steal(XMarkContext* context) { - return try_steal_local(context) || try_steal_global(context); -} - -void XMark::idle() const { - os::naked_short_sleep(1); -} - -class XMarkFlushAndFreeStacksClosure : public HandshakeClosure { -private: - XMark* const _mark; - bool _flushed; - -public: - XMarkFlushAndFreeStacksClosure(XMark* mark) : - HandshakeClosure("XMarkFlushAndFreeStacks"), - _mark(mark), - _flushed(false) {} - - void do_thread(Thread* thread) { - if (_mark->flush_and_free(thread)) { - _flushed = true; - } - } - - bool flushed() const { - return _flushed; - } -}; - -bool XMark::flush(bool at_safepoint) { - XMarkFlushAndFreeStacksClosure cl(this); - if (at_safepoint) { - Threads::threads_do(&cl); - } else { - Handshake::execute(&cl); - } - - // Returns true if more work is available - return cl.flushed() || !_stripes.is_empty(); -} - -bool XMark::try_flush(volatile size_t* nflush) { - Atomic::inc(nflush); - - XStatTimer timer(XSubPhaseConcurrentMarkTryFlush); - return flush(false /* at_safepoint */); -} - -bool XMark::try_proactive_flush() { - // Only do proactive flushes from worker 0 - if (XThread::worker_id() != 0) { - return false; - } - - if (Atomic::load(&_work_nproactiveflush) == XMarkProactiveFlushMax || - Atomic::load(&_work_nterminateflush) != 0) { - // Limit reached or we're trying to terminate - return false; - } - - return try_flush(&_work_nproactiveflush); -} - -bool XMark::try_terminate() { - XStatTimer timer(XSubPhaseConcurrentMarkTryTerminate); - - if (_terminate.enter_stage0()) { - // Last thread entered stage 0, flush - if (Atomic::load(&_work_terminateflush) && - Atomic::load(&_work_nterminateflush) != XMarkTerminateFlushMax) { - // Exit stage 0 to allow other threads to continue marking - _terminate.exit_stage0(); - - // Flush before termination - if (!try_flush(&_work_nterminateflush)) { - // No more work available, skip further flush attempts - Atomic::store(&_work_terminateflush, false); - } - - // Don't terminate, regardless of whether we successfully - // flushed out more work or not. We've already exited - // termination stage 0, to allow other threads to continue - // marking, so this thread has to return false and also - // make another round of attempted marking. - return false; - } - } - - for (;;) { - if (_terminate.enter_stage1()) { - // Last thread entered stage 1, terminate - return true; - } - - // Idle to give the other threads - // a chance to enter termination. - idle(); - - if (!_terminate.try_exit_stage1()) { - // All workers in stage 1, terminate - return true; - } - - if (_terminate.try_exit_stage0()) { - // More work available, don't terminate - return false; - } - } -} - -class XMarkNoTimeout : public StackObj { -public: - bool has_expired() { - // No timeout, but check for signal to abort - return XAbort::should_abort(); - } -}; - -void XMark::work_without_timeout(XMarkContext* context) { - XStatTimer timer(XSubPhaseConcurrentMark); - XMarkNoTimeout no_timeout; - - for (;;) { - if (!drain(context, &no_timeout)) { - // Abort - break; - } - - if (try_steal(context)) { - // Stole work - continue; - } - - if (try_proactive_flush()) { - // Work available - continue; - } - - if (try_terminate()) { - // Terminate - break; - } - } -} - -class XMarkTimeout : public StackObj { -private: - const Ticks _start; - const uint64_t _timeout; - const uint64_t _check_interval; - uint64_t _check_at; - uint64_t _check_count; - bool _expired; - -public: - XMarkTimeout(uint64_t timeout_in_micros) : - _start(Ticks::now()), - _timeout(_start.value() + TimeHelper::micros_to_counter(timeout_in_micros)), - _check_interval(200), - _check_at(_check_interval), - _check_count(0), - _expired(false) {} - - ~XMarkTimeout() { - const Tickspan duration = Ticks::now() - _start; - log_debug(gc, marking)("Mark With Timeout (%s): %s, " UINT64_FORMAT " oops, %.3fms", - XThread::name(), _expired ? "Expired" : "Completed", - _check_count, TimeHelper::counter_to_millis(duration.value())); - } - - bool has_expired() { - if (++_check_count == _check_at) { - _check_at += _check_interval; - if ((uint64_t)Ticks::now().value() >= _timeout) { - // Timeout - _expired = true; - } - } - - return _expired; - } -}; - -void XMark::work_with_timeout(XMarkContext* context, uint64_t timeout_in_micros) { - XStatTimer timer(XSubPhaseMarkTryComplete); - XMarkTimeout timeout(timeout_in_micros); - - for (;;) { - if (!drain(context, &timeout)) { - // Timed out - break; - } - - if (try_steal(context)) { - // Stole work - continue; - } - - // Terminate - break; - } -} - -void XMark::work(uint64_t timeout_in_micros) { - XMarkStripe* const stripe = _stripes.stripe_for_worker(_nworkers, XThread::worker_id()); - XMarkThreadLocalStacks* const stacks = XThreadLocalData::stacks(Thread::current()); - XMarkContext context(_stripes.nstripes(), stripe, stacks); - - if (timeout_in_micros == 0) { - work_without_timeout(&context); - } else { - work_with_timeout(&context, timeout_in_micros); - } - - // Flush and publish stacks - stacks->flush(&_allocator, &_stripes); - - // Free remaining stacks - stacks->free(&_allocator); -} - -class XMarkOopClosure : public OopClosure { - virtual void do_oop(oop* p) { - XBarrier::mark_barrier_on_oop_field(p, false /* finalizable */); - } - - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } -}; - -class XMarkThreadClosure : public ThreadClosure { -private: - OopClosure* const _cl; - -public: - XMarkThreadClosure(OopClosure* cl) : - _cl(cl) { - XThreadLocalAllocBuffer::reset_statistics(); - } - ~XMarkThreadClosure() { - XThreadLocalAllocBuffer::publish_statistics(); - } - virtual void do_thread(Thread* thread) { - JavaThread* const jt = JavaThread::cast(thread); - StackWatermarkSet::finish_processing(jt, _cl, StackWatermarkKind::gc); - XThreadLocalAllocBuffer::update_stats(jt); - } -}; - -class XMarkNMethodClosure : public NMethodClosure { -private: - OopClosure* const _cl; - -public: - XMarkNMethodClosure(OopClosure* cl) : - _cl(cl) {} - - virtual void do_nmethod(nmethod* nm) { - XLocker locker(XNMethod::lock_for_nmethod(nm)); - if (XNMethod::is_armed(nm)) { - XNMethod::nmethod_oops_do_inner(nm, _cl); - - // CodeCache unloading support - nm->mark_as_maybe_on_stack(); - - XNMethod::disarm(nm); - } - } -}; - -typedef ClaimingCLDToOopClosure XMarkCLDClosure; - -class XMarkRootsTask : public XTask { -private: - XMark* const _mark; - SuspendibleThreadSetJoiner _sts_joiner; - XRootsIterator _roots; - - XMarkOopClosure _cl; - XMarkCLDClosure _cld_cl; - XMarkThreadClosure _thread_cl; - XMarkNMethodClosure _nm_cl; - -public: - XMarkRootsTask(XMark* mark) : - XTask("XMarkRootsTask"), - _mark(mark), - _sts_joiner(), - _roots(ClassLoaderData::_claim_strong), - _cl(), - _cld_cl(&_cl), - _thread_cl(&_cl), - _nm_cl(&_cl) { - ClassLoaderDataGraph_lock->lock(); - } - - ~XMarkRootsTask() { - ClassLoaderDataGraph_lock->unlock(); - } - - virtual void work() { - _roots.apply(&_cl, - &_cld_cl, - &_thread_cl, - &_nm_cl); - - // Flush and free worker stacks. Needed here since - // the set of workers executing during root scanning - // can be different from the set of workers executing - // during mark. - _mark->flush_and_free(); - } -}; - -class XMarkTask : public XTask { -private: - XMark* const _mark; - const uint64_t _timeout_in_micros; - -public: - XMarkTask(XMark* mark, uint64_t timeout_in_micros = 0) : - XTask("XMarkTask"), - _mark(mark), - _timeout_in_micros(timeout_in_micros) { - _mark->prepare_work(); - } - - ~XMarkTask() { - _mark->finish_work(); - } - - virtual void work() { - _mark->work(_timeout_in_micros); - } -}; - -void XMark::mark(bool initial) { - if (initial) { - XMarkRootsTask task(this); - _workers->run(&task); - } - - XMarkTask task(this); - _workers->run(&task); -} - -bool XMark::try_complete() { - _ntrycomplete++; - - // Use nconcurrent number of worker threads to maintain the - // worker/stripe distribution used during concurrent mark. - XMarkTask task(this, XMarkCompleteTimeout); - _workers->run(&task); - - // Successful if all stripes are empty - return _stripes.is_empty(); -} - -bool XMark::try_end() { - // Flush all mark stacks - if (!flush(true /* at_safepoint */)) { - // Mark completed - return true; - } - - // Try complete marking by doing a limited - // amount of mark work in this phase. - return try_complete(); -} - -bool XMark::end() { - // Try end marking - if (!try_end()) { - // Mark not completed - _ncontinue++; - return false; - } - - // Verification - if (ZVerifyMarking) { - verify_all_stacks_empty(); - } - - // Update statistics - XStatMark::set_at_mark_end(_nproactiveflush, _nterminateflush, _ntrycomplete, _ncontinue); - - // Note that we finished a marking cycle. - // Unlike other GCs, we do not arm the nmethods - // when marking terminates. - CodeCache::on_gc_marking_cycle_finish(); - - // Mark completed - return true; -} - -void XMark::free() { - // Free any unused mark stack space - _allocator.free(); - - // Update statistics - XStatMark::set_at_mark_free(_allocator.size()); -} - -void XMark::flush_and_free() { - Thread* const thread = Thread::current(); - flush_and_free(thread); -} - -bool XMark::flush_and_free(Thread* thread) { - XMarkThreadLocalStacks* const stacks = XThreadLocalData::stacks(thread); - const bool flushed = stacks->flush(&_allocator, &_stripes); - stacks->free(&_allocator); - return flushed; -} - -class XVerifyMarkStacksEmptyClosure : public ThreadClosure { -private: - const XMarkStripeSet* const _stripes; - -public: - XVerifyMarkStacksEmptyClosure(const XMarkStripeSet* stripes) : - _stripes(stripes) {} - - void do_thread(Thread* thread) { - XMarkThreadLocalStacks* const stacks = XThreadLocalData::stacks(thread); - guarantee(stacks->is_empty(_stripes), "Should be empty"); - } -}; - -void XMark::verify_all_stacks_empty() const { - // Verify thread stacks - XVerifyMarkStacksEmptyClosure cl(&_stripes); - Threads::threads_do(&cl); - - // Verify stripe stacks - guarantee(_stripes.is_empty(), "Should be empty"); -} diff --git a/src/hotspot/share/gc/x/xMark.hpp b/src/hotspot/share/gc/x/xMark.hpp deleted file mode 100644 index 5e40b79f02e3e..0000000000000 --- a/src/hotspot/share/gc/x/xMark.hpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XMARK_HPP -#define SHARE_GC_X_XMARK_HPP - -#include "gc/x/xMarkStack.hpp" -#include "gc/x/xMarkStackAllocator.hpp" -#include "gc/x/xMarkStackEntry.hpp" -#include "gc/x/xMarkTerminate.hpp" -#include "oops/oopsHierarchy.hpp" -#include "utilities/globalDefinitions.hpp" - -class Thread; -class XMarkContext; -class XPageTable; -class XWorkers; - -class XMark { - friend class XMarkTask; - -private: - XWorkers* const _workers; - XPageTable* const _page_table; - XMarkStackAllocator _allocator; - XMarkStripeSet _stripes; - XMarkTerminate _terminate; - volatile bool _work_terminateflush; - volatile size_t _work_nproactiveflush; - volatile size_t _work_nterminateflush; - size_t _nproactiveflush; - size_t _nterminateflush; - size_t _ntrycomplete; - size_t _ncontinue; - uint _nworkers; - - size_t calculate_nstripes(uint nworkers) const; - - bool is_array(uintptr_t addr) const; - void push_partial_array(uintptr_t addr, size_t size, bool finalizable); - void follow_small_array(uintptr_t addr, size_t size, bool finalizable); - void follow_large_array(uintptr_t addr, size_t size, bool finalizable); - void follow_array(uintptr_t addr, size_t size, bool finalizable); - void follow_partial_array(XMarkStackEntry entry, bool finalizable); - void follow_array_object(objArrayOop obj, bool finalizable); - void follow_object(oop obj, bool finalizable); - void mark_and_follow(XMarkContext* context, XMarkStackEntry entry); - - template bool drain(XMarkContext* context, T* timeout); - bool try_steal_local(XMarkContext* context); - bool try_steal_global(XMarkContext* context); - bool try_steal(XMarkContext* context); - void idle() const; - bool flush(bool at_safepoint); - bool try_proactive_flush(); - bool try_flush(volatile size_t* nflush); - bool try_terminate(); - bool try_complete(); - bool try_end(); - - void prepare_work(); - void finish_work(); - - void work_without_timeout(XMarkContext* context); - void work_with_timeout(XMarkContext* context, uint64_t timeout_in_micros); - void work(uint64_t timeout_in_micros); - - void verify_all_stacks_empty() const; - -public: - XMark(XWorkers* workers, XPageTable* page_table); - - bool is_initialized() const; - - template void mark_object(uintptr_t addr); - - void start(); - void mark(bool initial); - bool end(); - void free(); - - void flush_and_free(); - bool flush_and_free(Thread* thread); -}; - -#endif // SHARE_GC_X_XMARK_HPP diff --git a/src/hotspot/share/gc/x/xMark.inline.hpp b/src/hotspot/share/gc/x/xMark.inline.hpp deleted file mode 100644 index 1f8fc81f525c3..0000000000000 --- a/src/hotspot/share/gc/x/xMark.inline.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XMARK_INLINE_HPP -#define SHARE_GC_X_XMARK_INLINE_HPP - -#include "gc/x/xMark.hpp" - -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xMarkStack.inline.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xPageTable.inline.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "runtime/javaThread.hpp" -#include "utilities/debug.hpp" - -// Marking before pushing helps reduce mark stack memory usage. However, -// we only mark before pushing in GC threads to avoid burdening Java threads -// with writing to, and potentially first having to clear, mark bitmaps. -// -// It's also worth noting that while marking an object can be done at any -// time in the marking phase, following an object can only be done after -// root processing has called ClassLoaderDataGraph::clear_claimed_marks(), -// since it otherwise would interact badly with claiming of CLDs. - -template -inline void XMark::mark_object(uintptr_t addr) { - assert(XAddress::is_marked(addr), "Should be marked"); - - XPage* const page = _page_table->get(addr); - if (page->is_allocating()) { - // Already implicitly marked - return; - } - - const bool mark_before_push = gc_thread; - bool inc_live = false; - - if (mark_before_push) { - // Try mark object - if (!page->mark_object(addr, finalizable, inc_live)) { - // Already marked - return; - } - } else { - // Don't push if already marked - if (page->is_object_marked(addr)) { - // Already marked - return; - } - } - - // Push - XMarkThreadLocalStacks* const stacks = XThreadLocalData::stacks(Thread::current()); - XMarkStripe* const stripe = _stripes.stripe_for_addr(addr); - XMarkStackEntry entry(addr, !mark_before_push, inc_live, follow, finalizable); - stacks->push(&_allocator, &_stripes, stripe, entry, publish); -} - -#endif // SHARE_GC_X_XMARK_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xMarkCache.cpp b/src/hotspot/share/gc/x/xMarkCache.cpp deleted file mode 100644 index c7e580ed88334..0000000000000 --- a/src/hotspot/share/gc/x/xMarkCache.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xMarkCache.inline.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/powerOfTwo.hpp" - -XMarkCacheEntry::XMarkCacheEntry() : - _page(nullptr), - _objects(0), - _bytes(0) {} - -XMarkCache::XMarkCache(size_t nstripes) : - _shift(XMarkStripeShift + exact_log2(nstripes)) {} - -XMarkCache::~XMarkCache() { - // Evict all entries - for (size_t i = 0; i < XMarkCacheSize; i++) { - _cache[i].evict(); - } -} diff --git a/src/hotspot/share/gc/x/xMarkCache.hpp b/src/hotspot/share/gc/x/xMarkCache.hpp deleted file mode 100644 index 8fbdc87352237..0000000000000 --- a/src/hotspot/share/gc/x/xMarkCache.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XMARKCACHE_HPP -#define SHARE_GC_X_XMARKCACHE_HPP - -#include "gc/x/xGlobals.hpp" -#include "memory/allocation.hpp" - -class XPage; - -class XMarkCacheEntry { -private: - XPage* _page; - uint32_t _objects; - size_t _bytes; - -public: - XMarkCacheEntry(); - - void inc_live(XPage* page, size_t bytes); - void evict(); -}; - -class XMarkCache : public StackObj { -private: - const size_t _shift; - XMarkCacheEntry _cache[XMarkCacheSize]; - -public: - XMarkCache(size_t nstripes); - ~XMarkCache(); - - void inc_live(XPage* page, size_t bytes); -}; - -#endif // SHARE_GC_X_XMARKCACHE_HPP diff --git a/src/hotspot/share/gc/x/xMarkCache.inline.hpp b/src/hotspot/share/gc/x/xMarkCache.inline.hpp deleted file mode 100644 index 27dd1b9333986..0000000000000 --- a/src/hotspot/share/gc/x/xMarkCache.inline.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XMARKCACHE_INLINE_HPP -#define SHARE_GC_X_XMARKCACHE_INLINE_HPP - -#include "gc/x/xMarkCache.hpp" - -#include "gc/x/xPage.inline.hpp" - -inline void XMarkCacheEntry::inc_live(XPage* page, size_t bytes) { - if (_page == page) { - // Cache hit - _objects++; - _bytes += bytes; - } else { - // Cache miss - evict(); - _page = page; - _objects = 1; - _bytes = bytes; - } -} - -inline void XMarkCacheEntry::evict() { - if (_page != nullptr) { - // Write cached data out to page - _page->inc_live(_objects, _bytes); - _page = nullptr; - } -} - -inline void XMarkCache::inc_live(XPage* page, size_t bytes) { - const size_t mask = XMarkCacheSize - 1; - const size_t index = (page->start() >> _shift) & mask; - _cache[index].inc_live(page, bytes); -} - -#endif // SHARE_GC_X_XMARKCACHE_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xMarkContext.hpp b/src/hotspot/share/gc/x/xMarkContext.hpp deleted file mode 100644 index 246822931b7b1..0000000000000 --- a/src/hotspot/share/gc/x/xMarkContext.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XMARKCONTEXT_HPP -#define SHARE_GC_X_XMARKCONTEXT_HPP - -#include "gc/x/xMarkCache.hpp" -#include "gc/shared/stringdedup/stringDedup.hpp" -#include "memory/allocation.hpp" - -class XMarkStripe; -class XMarkThreadLocalStacks; - -class XMarkContext : public StackObj { -private: - XMarkCache _cache; - XMarkStripe* const _stripe; - XMarkThreadLocalStacks* const _stacks; - StringDedup::Requests _string_dedup_requests; - -public: - XMarkContext(size_t nstripes, - XMarkStripe* stripe, - XMarkThreadLocalStacks* stacks); - - XMarkCache* cache(); - XMarkStripe* stripe(); - XMarkThreadLocalStacks* stacks(); - StringDedup::Requests* string_dedup_requests(); -}; - -#endif // SHARE_GC_X_XMARKCONTEXT_HPP diff --git a/src/hotspot/share/gc/x/xMarkContext.inline.hpp b/src/hotspot/share/gc/x/xMarkContext.inline.hpp deleted file mode 100644 index 74a182b67c33a..0000000000000 --- a/src/hotspot/share/gc/x/xMarkContext.inline.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XMARKCONTEXT_INLINE_HPP -#define SHARE_GC_X_XMARKCONTEXT_INLINE_HPP - -#include "gc/x/xMarkContext.hpp" - -inline XMarkContext::XMarkContext(size_t nstripes, - XMarkStripe* stripe, - XMarkThreadLocalStacks* stacks) : - _cache(nstripes), - _stripe(stripe), - _stacks(stacks), - _string_dedup_requests() {} - -inline XMarkCache* XMarkContext::cache() { - return &_cache; -} - -inline XMarkStripe* XMarkContext::stripe() { - return _stripe; -} - -inline XMarkThreadLocalStacks* XMarkContext::stacks() { - return _stacks; -} - -inline StringDedup::Requests* XMarkContext::string_dedup_requests() { - return &_string_dedup_requests; -} - -#endif // SHARE_GC_X_XMARKCACHE_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xMarkStack.cpp b/src/hotspot/share/gc/x/xMarkStack.cpp deleted file mode 100644 index 6f7619c9a3572..0000000000000 --- a/src/hotspot/share/gc/x/xMarkStack.cpp +++ /dev/null @@ -1,226 +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. - */ - -#include "precompiled.hpp" -#include "gc/x/xMarkStack.inline.hpp" -#include "gc/x/xMarkStackAllocator.hpp" -#include "logging/log.hpp" -#include "utilities/debug.hpp" -#include "utilities/powerOfTwo.hpp" - -XMarkStripe::XMarkStripe() : - _published(), - _overflowed() {} - -XMarkStripeSet::XMarkStripeSet() : - _nstripes(0), - _nstripes_mask(0), - _stripes() {} - -void XMarkStripeSet::set_nstripes(size_t nstripes) { - assert(is_power_of_2(nstripes), "Must be a power of two"); - assert(is_power_of_2(XMarkStripesMax), "Must be a power of two"); - assert(nstripes >= 1, "Invalid number of stripes"); - assert(nstripes <= XMarkStripesMax, "Invalid number of stripes"); - - _nstripes = nstripes; - _nstripes_mask = nstripes - 1; - - log_debug(gc, marking)("Using " SIZE_FORMAT " mark stripes", _nstripes); -} - -bool XMarkStripeSet::is_empty() const { - for (size_t i = 0; i < _nstripes; i++) { - if (!_stripes[i].is_empty()) { - return false; - } - } - - return true; -} - -XMarkStripe* XMarkStripeSet::stripe_for_worker(uint nworkers, uint worker_id) { - const size_t spillover_limit = (nworkers / _nstripes) * _nstripes; - size_t index; - - if (worker_id < spillover_limit) { - // Not a spillover worker, use natural stripe - index = worker_id & _nstripes_mask; - } else { - // Distribute spillover workers evenly across stripes - const size_t spillover_nworkers = nworkers - spillover_limit; - const size_t spillover_worker_id = worker_id - spillover_limit; - const double spillover_chunk = (double)_nstripes / (double)spillover_nworkers; - index = spillover_worker_id * spillover_chunk; - } - - assert(index < _nstripes, "Invalid index"); - return &_stripes[index]; -} - -XMarkThreadLocalStacks::XMarkThreadLocalStacks() : - _magazine(nullptr) { - for (size_t i = 0; i < XMarkStripesMax; i++) { - _stacks[i] = nullptr; - } -} - -bool XMarkThreadLocalStacks::is_empty(const XMarkStripeSet* stripes) const { - for (size_t i = 0; i < stripes->nstripes(); i++) { - XMarkStack* const stack = _stacks[i]; - if (stack != nullptr) { - return false; - } - } - - return true; -} - -XMarkStack* XMarkThreadLocalStacks::allocate_stack(XMarkStackAllocator* allocator) { - if (_magazine == nullptr) { - // Allocate new magazine - _magazine = allocator->alloc_magazine(); - if (_magazine == nullptr) { - return nullptr; - } - } - - XMarkStack* stack = nullptr; - - if (!_magazine->pop(stack)) { - // Magazine is empty, convert magazine into a new stack - _magazine->~XMarkStackMagazine(); - stack = new ((void*)_magazine) XMarkStack(); - _magazine = nullptr; - } - - return stack; -} - -void XMarkThreadLocalStacks::free_stack(XMarkStackAllocator* allocator, XMarkStack* stack) { - for (;;) { - if (_magazine == nullptr) { - // Convert stack into a new magazine - stack->~XMarkStack(); - _magazine = new ((void*)stack) XMarkStackMagazine(); - return; - } - - if (_magazine->push(stack)) { - // Success - return; - } - - // Free and uninstall full magazine - allocator->free_magazine(_magazine); - _magazine = nullptr; - } -} - -bool XMarkThreadLocalStacks::push_slow(XMarkStackAllocator* allocator, - XMarkStripe* stripe, - XMarkStack** stackp, - XMarkStackEntry entry, - bool publish) { - XMarkStack* stack = *stackp; - - for (;;) { - if (stack == nullptr) { - // Allocate and install new stack - *stackp = stack = allocate_stack(allocator); - if (stack == nullptr) { - // Out of mark stack memory - return false; - } - } - - if (stack->push(entry)) { - // Success - return true; - } - - // Publish/Overflow and uninstall stack - stripe->publish_stack(stack, publish); - *stackp = stack = nullptr; - } -} - -bool XMarkThreadLocalStacks::pop_slow(XMarkStackAllocator* allocator, - XMarkStripe* stripe, - XMarkStack** stackp, - XMarkStackEntry& entry) { - XMarkStack* stack = *stackp; - - for (;;) { - if (stack == nullptr) { - // Try steal and install stack - *stackp = stack = stripe->steal_stack(); - if (stack == nullptr) { - // Nothing to steal - return false; - } - } - - if (stack->pop(entry)) { - // Success - return true; - } - - // Free and uninstall stack - free_stack(allocator, stack); - *stackp = stack = nullptr; - } -} - -bool XMarkThreadLocalStacks::flush(XMarkStackAllocator* allocator, XMarkStripeSet* stripes) { - bool flushed = false; - - // Flush all stacks - for (size_t i = 0; i < stripes->nstripes(); i++) { - XMarkStripe* const stripe = stripes->stripe_at(i); - XMarkStack** const stackp = &_stacks[i]; - XMarkStack* const stack = *stackp; - if (stack == nullptr) { - continue; - } - - // Free/Publish and uninstall stack - if (stack->is_empty()) { - free_stack(allocator, stack); - } else { - stripe->publish_stack(stack); - flushed = true; - } - *stackp = nullptr; - } - - return flushed; -} - -void XMarkThreadLocalStacks::free(XMarkStackAllocator* allocator) { - // Free and uninstall magazine - if (_magazine != nullptr) { - allocator->free_magazine(_magazine); - _magazine = nullptr; - } -} diff --git a/src/hotspot/share/gc/x/xMarkStack.hpp b/src/hotspot/share/gc/x/xMarkStack.hpp deleted file mode 100644 index e012b89749d6a..0000000000000 --- a/src/hotspot/share/gc/x/xMarkStack.hpp +++ /dev/null @@ -1,164 +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. - */ - -#ifndef SHARE_GC_X_XMARKSTACK_HPP -#define SHARE_GC_X_XMARKSTACK_HPP - -#include "gc/x/xGlobals.hpp" -#include "gc/x/xMarkStackEntry.hpp" -#include "utilities/globalDefinitions.hpp" - -template -class XStack { -private: - size_t _top; - XStack* _next; - T _slots[S]; - - bool is_full() const; - -public: - XStack(); - - bool is_empty() const; - - bool push(T value); - bool pop(T& value); - - XStack* next() const; - XStack** next_addr(); -}; - -template -class XStackList { -private: - T* volatile _head; - - T* encode_versioned_pointer(const T* stack, uint32_t version) const; - void decode_versioned_pointer(const T* vstack, T** stack, uint32_t* version) const; - -public: - XStackList(); - - bool is_empty() const; - - void push(T* stack); - T* pop(); - - void clear(); -}; - -using XMarkStack = XStack; -using XMarkStackList = XStackList; -using XMarkStackMagazine = XStack; -using XMarkStackMagazineList = XStackList; - -static_assert(sizeof(XMarkStack) == XMarkStackSize, "XMarkStack size mismatch"); -static_assert(sizeof(XMarkStackMagazine) <= XMarkStackSize, "XMarkStackMagazine size too large"); - -class XMarkStripe { -private: - XCACHE_ALIGNED XMarkStackList _published; - XCACHE_ALIGNED XMarkStackList _overflowed; - -public: - XMarkStripe(); - - bool is_empty() const; - - void publish_stack(XMarkStack* stack, bool publish = true); - XMarkStack* steal_stack(); -}; - -class XMarkStripeSet { -private: - size_t _nstripes; - size_t _nstripes_mask; - XMarkStripe _stripes[XMarkStripesMax]; - -public: - XMarkStripeSet(); - - size_t nstripes() const; - void set_nstripes(size_t nstripes); - - bool is_empty() const; - - size_t stripe_id(const XMarkStripe* stripe) const; - XMarkStripe* stripe_at(size_t index); - XMarkStripe* stripe_next(XMarkStripe* stripe); - XMarkStripe* stripe_for_worker(uint nworkers, uint worker_id); - XMarkStripe* stripe_for_addr(uintptr_t addr); -}; - -class XMarkStackAllocator; - -class XMarkThreadLocalStacks { -private: - XMarkStackMagazine* _magazine; - XMarkStack* _stacks[XMarkStripesMax]; - - XMarkStack* allocate_stack(XMarkStackAllocator* allocator); - void free_stack(XMarkStackAllocator* allocator, XMarkStack* stack); - - bool push_slow(XMarkStackAllocator* allocator, - XMarkStripe* stripe, - XMarkStack** stackp, - XMarkStackEntry entry, - bool publish); - - bool pop_slow(XMarkStackAllocator* allocator, - XMarkStripe* stripe, - XMarkStack** stackp, - XMarkStackEntry& entry); - -public: - XMarkThreadLocalStacks(); - - bool is_empty(const XMarkStripeSet* stripes) const; - - void install(XMarkStripeSet* stripes, - XMarkStripe* stripe, - XMarkStack* stack); - - XMarkStack* steal(XMarkStripeSet* stripes, - XMarkStripe* stripe); - - bool push(XMarkStackAllocator* allocator, - XMarkStripeSet* stripes, - XMarkStripe* stripe, - XMarkStackEntry entry, - bool publish); - - bool pop(XMarkStackAllocator* allocator, - XMarkStripeSet* stripes, - XMarkStripe* stripe, - XMarkStackEntry& entry); - - bool flush(XMarkStackAllocator* allocator, - XMarkStripeSet* stripes); - - void free(XMarkStackAllocator* allocator); -}; - -#endif // SHARE_GC_X_XMARKSTACK_HPP diff --git a/src/hotspot/share/gc/x/xMarkStack.inline.hpp b/src/hotspot/share/gc/x/xMarkStack.inline.hpp deleted file mode 100644 index e643c1e32243a..0000000000000 --- a/src/hotspot/share/gc/x/xMarkStack.inline.hpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XMARKSTACK_INLINE_HPP -#define SHARE_GC_X_XMARKSTACK_INLINE_HPP - -#include "gc/x/xMarkStack.hpp" - -#include "utilities/debug.hpp" -#include "runtime/atomic.hpp" - -template -inline XStack::XStack() : - _top(0), - _next(nullptr) {} - -template -inline bool XStack::is_empty() const { - return _top == 0; -} - -template -inline bool XStack::is_full() const { - return _top == S; -} - -template -inline bool XStack::push(T value) { - if (is_full()) { - return false; - } - - _slots[_top++] = value; - return true; -} - -template -inline bool XStack::pop(T& value) { - if (is_empty()) { - return false; - } - - value = _slots[--_top]; - return true; -} - -template -inline XStack* XStack::next() const { - return _next; -} - -template -inline XStack** XStack::next_addr() { - return &_next; -} - -template -inline XStackList::XStackList() : - _head(encode_versioned_pointer(nullptr, 0)) {} - -template -inline T* XStackList::encode_versioned_pointer(const T* stack, uint32_t version) const { - uint64_t addr; - - if (stack == nullptr) { - addr = (uint32_t)-1; - } else { - addr = ((uint64_t)stack - XMarkStackSpaceStart) >> XMarkStackSizeShift; - } - - return (T*)((addr << 32) | (uint64_t)version); -} - -template -inline void XStackList::decode_versioned_pointer(const T* vstack, T** stack, uint32_t* version) const { - const uint64_t addr = (uint64_t)vstack >> 32; - - if (addr == (uint32_t)-1) { - *stack = nullptr; - } else { - *stack = (T*)((addr << XMarkStackSizeShift) + XMarkStackSpaceStart); - } - - *version = (uint32_t)(uint64_t)vstack; -} - -template -inline bool XStackList::is_empty() const { - const T* vstack = _head; - T* stack = nullptr; - uint32_t version = 0; - - decode_versioned_pointer(vstack, &stack, &version); - return stack == nullptr; -} - -template -inline void XStackList::push(T* stack) { - T* vstack = _head; - uint32_t version = 0; - - for (;;) { - decode_versioned_pointer(vstack, stack->next_addr(), &version); - T* const new_vstack = encode_versioned_pointer(stack, version + 1); - T* const prev_vstack = Atomic::cmpxchg(&_head, vstack, new_vstack); - if (prev_vstack == vstack) { - // Success - break; - } - - // Retry - vstack = prev_vstack; - } -} - -template -inline T* XStackList::pop() { - T* vstack = _head; - T* stack = nullptr; - uint32_t version = 0; - - for (;;) { - decode_versioned_pointer(vstack, &stack, &version); - if (stack == nullptr) { - return nullptr; - } - - T* const new_vstack = encode_versioned_pointer(stack->next(), version + 1); - T* const prev_vstack = Atomic::cmpxchg(&_head, vstack, new_vstack); - if (prev_vstack == vstack) { - // Success - return stack; - } - - // Retry - vstack = prev_vstack; - } -} - -template -inline void XStackList::clear() { - _head = encode_versioned_pointer(nullptr, 0); -} - -inline bool XMarkStripe::is_empty() const { - return _published.is_empty() && _overflowed.is_empty(); -} - -inline void XMarkStripe::publish_stack(XMarkStack* stack, bool publish) { - // A stack is published either on the published list or the overflowed - // list. The published list is used by mutators publishing stacks for GC - // workers to work on, while the overflowed list is used by GC workers - // to publish stacks that overflowed. The intention here is to avoid - // contention between mutators and GC workers as much as possible, while - // still allowing GC workers to help out and steal work from each other. - if (publish) { - _published.push(stack); - } else { - _overflowed.push(stack); - } -} - -inline XMarkStack* XMarkStripe::steal_stack() { - // Steal overflowed stacks first, then published stacks - XMarkStack* const stack = _overflowed.pop(); - if (stack != nullptr) { - return stack; - } - - return _published.pop(); -} - -inline size_t XMarkStripeSet::nstripes() const { - return _nstripes; -} - -inline size_t XMarkStripeSet::stripe_id(const XMarkStripe* stripe) const { - const size_t index = ((uintptr_t)stripe - (uintptr_t)_stripes) / sizeof(XMarkStripe); - assert(index < _nstripes, "Invalid index"); - return index; -} - -inline XMarkStripe* XMarkStripeSet::stripe_at(size_t index) { - assert(index < _nstripes, "Invalid index"); - return &_stripes[index]; -} - -inline XMarkStripe* XMarkStripeSet::stripe_next(XMarkStripe* stripe) { - const size_t index = (stripe_id(stripe) + 1) & _nstripes_mask; - assert(index < _nstripes, "Invalid index"); - return &_stripes[index]; -} - -inline XMarkStripe* XMarkStripeSet::stripe_for_addr(uintptr_t addr) { - const size_t index = (addr >> XMarkStripeShift) & _nstripes_mask; - assert(index < _nstripes, "Invalid index"); - return &_stripes[index]; -} - -inline void XMarkThreadLocalStacks::install(XMarkStripeSet* stripes, - XMarkStripe* stripe, - XMarkStack* stack) { - XMarkStack** const stackp = &_stacks[stripes->stripe_id(stripe)]; - assert(*stackp == nullptr, "Should be empty"); - *stackp = stack; -} - -inline XMarkStack* XMarkThreadLocalStacks::steal(XMarkStripeSet* stripes, - XMarkStripe* stripe) { - XMarkStack** const stackp = &_stacks[stripes->stripe_id(stripe)]; - XMarkStack* const stack = *stackp; - if (stack != nullptr) { - *stackp = nullptr; - } - - return stack; -} - -inline bool XMarkThreadLocalStacks::push(XMarkStackAllocator* allocator, - XMarkStripeSet* stripes, - XMarkStripe* stripe, - XMarkStackEntry entry, - bool publish) { - XMarkStack** const stackp = &_stacks[stripes->stripe_id(stripe)]; - XMarkStack* const stack = *stackp; - if (stack != nullptr && stack->push(entry)) { - return true; - } - - return push_slow(allocator, stripe, stackp, entry, publish); -} - -inline bool XMarkThreadLocalStacks::pop(XMarkStackAllocator* allocator, - XMarkStripeSet* stripes, - XMarkStripe* stripe, - XMarkStackEntry& entry) { - XMarkStack** const stackp = &_stacks[stripes->stripe_id(stripe)]; - XMarkStack* const stack = *stackp; - if (stack != nullptr && stack->pop(entry)) { - return true; - } - - return pop_slow(allocator, stripe, stackp, entry); -} - -#endif // SHARE_GC_X_XMARKSTACK_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xMarkStackAllocator.cpp b/src/hotspot/share/gc/x/xMarkStackAllocator.cpp deleted file mode 100644 index b5cc3ad641aff..0000000000000 --- a/src/hotspot/share/gc/x/xMarkStackAllocator.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xMarkStack.inline.hpp" -#include "gc/x/xMarkStackAllocator.hpp" -#include "logging/log.hpp" -#include "runtime/atomic.hpp" -#include "runtime/os.hpp" -#include "utilities/debug.hpp" - -uintptr_t XMarkStackSpaceStart; - -XMarkStackSpace::XMarkStackSpace() : - _expand_lock(), - _start(0), - _top(0), - _end(0) { - assert(ZMarkStackSpaceLimit >= XMarkStackSpaceExpandSize, "ZMarkStackSpaceLimit too small"); - - // Reserve address space - const size_t size = ZMarkStackSpaceLimit; - const uintptr_t addr = (uintptr_t)os::reserve_memory(size, !ExecMem, mtGC); - if (addr == 0) { - log_error_pd(gc, marking)("Failed to reserve address space for mark stacks"); - return; - } - - // Successfully initialized - _start = _top = _end = addr; - - // Register mark stack space start - XMarkStackSpaceStart = _start; - - // Prime space - _end += expand_space(); -} - -bool XMarkStackSpace::is_initialized() const { - return _start != 0; -} - -size_t XMarkStackSpace::size() const { - return _end - _start; -} - -size_t XMarkStackSpace::used() const { - return _top - _start; -} - -size_t XMarkStackSpace::expand_space() { - const size_t expand_size = XMarkStackSpaceExpandSize; - const size_t old_size = size(); - const size_t new_size = old_size + expand_size; - - if (new_size > ZMarkStackSpaceLimit) { - // Expansion limit reached. This is a fatal error since we - // currently can't recover from running out of mark stack space. - fatal("Mark stack space exhausted. Use -XX:ZMarkStackSpaceLimit= to increase the " - "maximum number of bytes allocated for mark stacks. Current limit is " SIZE_FORMAT "M.", - ZMarkStackSpaceLimit / M); - } - - log_debug(gc, marking)("Expanding mark stack space: " SIZE_FORMAT "M->" SIZE_FORMAT "M", - old_size / M, new_size / M); - - // Expand - os::commit_memory_or_exit((char*)_end, expand_size, false /* executable */, "Mark stack space"); - - return expand_size; -} - -size_t XMarkStackSpace::shrink_space() { - // Shrink to what is currently used - const size_t old_size = size(); - const size_t new_size = align_up(used(), XMarkStackSpaceExpandSize); - const size_t shrink_size = old_size - new_size; - - if (shrink_size > 0) { - // Shrink - log_debug(gc, marking)("Shrinking mark stack space: " SIZE_FORMAT "M->" SIZE_FORMAT "M", - old_size / M, new_size / M); - - const uintptr_t shrink_start = _end - shrink_size; - os::uncommit_memory((char*)shrink_start, shrink_size, false /* executable */); - } - - return shrink_size; -} - -uintptr_t XMarkStackSpace::alloc_space(size_t size) { - uintptr_t top = Atomic::load(&_top); - - for (;;) { - const uintptr_t end = Atomic::load(&_end); - const uintptr_t new_top = top + size; - if (new_top > end) { - // Not enough space left - return 0; - } - - const uintptr_t prev_top = Atomic::cmpxchg(&_top, top, new_top); - if (prev_top == top) { - // Success - return top; - } - - // Retry - top = prev_top; - } -} - -uintptr_t XMarkStackSpace::expand_and_alloc_space(size_t size) { - XLocker locker(&_expand_lock); - - // Retry allocation before expanding - uintptr_t addr = alloc_space(size); - if (addr != 0) { - return addr; - } - - // Expand - const size_t expand_size = expand_space(); - - // Increment top before end to make sure another - // thread can't steal out newly expanded space. - addr = Atomic::fetch_then_add(&_top, size); - Atomic::add(&_end, expand_size); - - return addr; -} - -uintptr_t XMarkStackSpace::alloc(size_t size) { - assert(size <= XMarkStackSpaceExpandSize, "Invalid size"); - - const uintptr_t addr = alloc_space(size); - if (addr != 0) { - return addr; - } - - return expand_and_alloc_space(size); -} - -void XMarkStackSpace::free() { - _end -= shrink_space(); - _top = _start; -} - -XMarkStackAllocator::XMarkStackAllocator() : - _freelist(), - _space() {} - -bool XMarkStackAllocator::is_initialized() const { - return _space.is_initialized(); -} - -size_t XMarkStackAllocator::size() const { - return _space.size(); -} - -XMarkStackMagazine* XMarkStackAllocator::create_magazine_from_space(uintptr_t addr, size_t size) { - assert(is_aligned(size, XMarkStackSize), "Invalid size"); - - // Use first stack as magazine - XMarkStackMagazine* const magazine = new ((void*)addr) XMarkStackMagazine(); - for (size_t i = XMarkStackSize; i < size; i += XMarkStackSize) { - XMarkStack* const stack = new ((void*)(addr + i)) XMarkStack(); - const bool success = magazine->push(stack); - assert(success, "Magazine should never get full"); - } - - return magazine; -} - -XMarkStackMagazine* XMarkStackAllocator::alloc_magazine() { - // Try allocating from the free list first - XMarkStackMagazine* const magazine = _freelist.pop(); - if (magazine != nullptr) { - return magazine; - } - - // Allocate new magazine - const uintptr_t addr = _space.alloc(XMarkStackMagazineSize); - if (addr == 0) { - return nullptr; - } - - return create_magazine_from_space(addr, XMarkStackMagazineSize); -} - -void XMarkStackAllocator::free_magazine(XMarkStackMagazine* magazine) { - _freelist.push(magazine); -} - -void XMarkStackAllocator::free() { - _freelist.clear(); - _space.free(); -} diff --git a/src/hotspot/share/gc/x/xMarkStackAllocator.hpp b/src/hotspot/share/gc/x/xMarkStackAllocator.hpp deleted file mode 100644 index 5e81ae284cf50..0000000000000 --- a/src/hotspot/share/gc/x/xMarkStackAllocator.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XMARKSTACKALLOCATOR_HPP -#define SHARE_GC_X_XMARKSTACKALLOCATOR_HPP - -#include "gc/x/xGlobals.hpp" -#include "gc/x/xLock.hpp" -#include "utilities/globalDefinitions.hpp" - -class XMarkStackSpace { -private: - XLock _expand_lock; - uintptr_t _start; - volatile uintptr_t _top; - volatile uintptr_t _end; - - size_t used() const; - - size_t expand_space(); - size_t shrink_space(); - - uintptr_t alloc_space(size_t size); - uintptr_t expand_and_alloc_space(size_t size); - -public: - XMarkStackSpace(); - - bool is_initialized() const; - - size_t size() const; - - uintptr_t alloc(size_t size); - void free(); -}; - -class XMarkStackAllocator { -private: - XCACHE_ALIGNED XMarkStackMagazineList _freelist; - XCACHE_ALIGNED XMarkStackSpace _space; - - XMarkStackMagazine* create_magazine_from_space(uintptr_t addr, size_t size); - -public: - XMarkStackAllocator(); - - bool is_initialized() const; - - size_t size() const; - - XMarkStackMagazine* alloc_magazine(); - void free_magazine(XMarkStackMagazine* magazine); - - void free(); -}; - -#endif // SHARE_GC_X_XMARKSTACKALLOCATOR_HPP diff --git a/src/hotspot/share/gc/x/xMarkStackEntry.hpp b/src/hotspot/share/gc/x/xMarkStackEntry.hpp deleted file mode 100644 index 61df1798df2a0..0000000000000 --- a/src/hotspot/share/gc/x/xMarkStackEntry.hpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XMARKSTACKENTRY_HPP -#define SHARE_GC_X_XMARKSTACKENTRY_HPP - -#include "gc/x/xBitField.hpp" -#include "memory/allocation.hpp" - -// -// Mark stack entry layout -// ----------------------- -// -// Object entry -// ------------ -// -// 6 -// 3 5 4 3 2 1 0 -// +------------------------------------------------------------------+-+-+-+-+-+ -// |11111111 11111111 11111111 11111111 11111111 11111111 11111111 111|1|1|1|1|1| -// +------------------------------------------------------------------+-+-+-+-+-+ -// | | | | | | -// | 4-4 Mark Flag (1-bit) * | | | | -// | | | | | -// | 3-3 Increment Live Flag (1-bit) * | | | -// | | | | -// | 2-2 Follow Flag (1-bit) * | | -// | | | -// | 1-1 Partial Array Flag (1-bit) * | -// | | -// | 0-0 Final Flag (1-bit) * -// | -// * 63-5 Object Address (59-bits) -// -// -// Partial array entry -// ------------------- -// -// 6 3 3 -// 3 2 1 2 1 0 -// +------------------------------------+---------------------------------+-+-+ -// |11111111 11111111 11111111 11111111 |11111111 11111111 11111111 111111|1|1| -// +------------------------------------+---------------------------------+-+-+ -// | | | | -// | | 1-1 Partial Array Flag (1-bit) * | -// | | | -// | | 0-0 Final Flag (1-bit) * -// | | -// | * 31-2 Partial Array Length (30-bits) -// | -// * 63-32 Partial Array Address Offset (32-bits) -// - -class XMarkStackEntry { -private: - typedef XBitField field_finalizable; - typedef XBitField field_partial_array; - typedef XBitField field_follow; - typedef XBitField field_inc_live; - typedef XBitField field_mark; - typedef XBitField field_object_address; - typedef XBitField field_partial_array_length; - typedef XBitField field_partial_array_offset; - - uint64_t _entry; - -public: - XMarkStackEntry() { - // This constructor is intentionally left empty and does not initialize - // _entry to allow it to be optimized out when instantiating XMarkStack, - // which has a long array of XMarkStackEntry elements, but doesn't care - // what _entry is initialized to. - } - - XMarkStackEntry(uintptr_t object_address, bool mark, bool inc_live, bool follow, bool finalizable) : - _entry(field_object_address::encode(object_address) | - field_mark::encode(mark) | - field_inc_live::encode(inc_live) | - field_follow::encode(follow) | - field_partial_array::encode(false) | - field_finalizable::encode(finalizable)) {} - - XMarkStackEntry(size_t partial_array_offset, size_t partial_array_length, bool finalizable) : - _entry(field_partial_array_offset::encode(partial_array_offset) | - field_partial_array_length::encode(partial_array_length) | - field_partial_array::encode(true) | - field_finalizable::encode(finalizable)) {} - - bool finalizable() const { - return field_finalizable::decode(_entry); - } - - bool partial_array() const { - return field_partial_array::decode(_entry); - } - - size_t partial_array_offset() const { - return field_partial_array_offset::decode(_entry); - } - - size_t partial_array_length() const { - return field_partial_array_length::decode(_entry); - } - - bool follow() const { - return field_follow::decode(_entry); - } - - bool inc_live() const { - return field_inc_live::decode(_entry); - } - - bool mark() const { - return field_mark::decode(_entry); - } - - uintptr_t object_address() const { - return field_object_address::decode(_entry); - } -}; - -#endif // SHARE_GC_X_XMARKSTACKENTRY_HPP diff --git a/src/hotspot/share/gc/x/xMarkTerminate.hpp b/src/hotspot/share/gc/x/xMarkTerminate.hpp deleted file mode 100644 index 28f18f6e1cbc7..0000000000000 --- a/src/hotspot/share/gc/x/xMarkTerminate.hpp +++ /dev/null @@ -1,54 +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. - */ - -#ifndef SHARE_GC_X_XMARKTERMINATE_HPP -#define SHARE_GC_X_XMARKTERMINATE_HPP - -#include "gc/x/xGlobals.hpp" -#include "memory/allocation.hpp" -#include "utilities/globalDefinitions.hpp" - -class XMarkTerminate { -private: - uint _nworkers; - XCACHE_ALIGNED volatile uint _nworking_stage0; - volatile uint _nworking_stage1; - - bool enter_stage(volatile uint* nworking_stage); - void exit_stage(volatile uint* nworking_stage); - bool try_exit_stage(volatile uint* nworking_stage); - -public: - XMarkTerminate(); - - void reset(uint nworkers); - - bool enter_stage0(); - void exit_stage0(); - bool try_exit_stage0(); - - bool enter_stage1(); - bool try_exit_stage1(); -}; - -#endif // SHARE_GC_X_XMARKTERMINATE_HPP diff --git a/src/hotspot/share/gc/x/xMarkTerminate.inline.hpp b/src/hotspot/share/gc/x/xMarkTerminate.inline.hpp deleted file mode 100644 index e4b9256ba6b7e..0000000000000 --- a/src/hotspot/share/gc/x/xMarkTerminate.inline.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XMARKTERMINATE_INLINE_HPP -#define SHARE_GC_X_XMARKTERMINATE_INLINE_HPP - -#include "gc/x/xMarkTerminate.hpp" - -#include "runtime/atomic.hpp" - -inline XMarkTerminate::XMarkTerminate() : - _nworkers(0), - _nworking_stage0(0), - _nworking_stage1(0) {} - -inline bool XMarkTerminate::enter_stage(volatile uint* nworking_stage) { - return Atomic::sub(nworking_stage, 1u) == 0; -} - -inline void XMarkTerminate::exit_stage(volatile uint* nworking_stage) { - Atomic::add(nworking_stage, 1u); -} - -inline bool XMarkTerminate::try_exit_stage(volatile uint* nworking_stage) { - uint nworking = Atomic::load(nworking_stage); - - for (;;) { - if (nworking == 0) { - return false; - } - - const uint new_nworking = nworking + 1; - const uint prev_nworking = Atomic::cmpxchg(nworking_stage, nworking, new_nworking); - if (prev_nworking == nworking) { - // Success - return true; - } - - // Retry - nworking = prev_nworking; - } -} - -inline void XMarkTerminate::reset(uint nworkers) { - _nworkers = _nworking_stage0 = _nworking_stage1 = nworkers; -} - -inline bool XMarkTerminate::enter_stage0() { - return enter_stage(&_nworking_stage0); -} - -inline void XMarkTerminate::exit_stage0() { - exit_stage(&_nworking_stage0); -} - -inline bool XMarkTerminate::try_exit_stage0() { - return try_exit_stage(&_nworking_stage0); -} - -inline bool XMarkTerminate::enter_stage1() { - return enter_stage(&_nworking_stage1); -} - -inline bool XMarkTerminate::try_exit_stage1() { - return try_exit_stage(&_nworking_stage1); -} - -#endif // SHARE_GC_X_XMARKTERMINATE_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xMemory.cpp b/src/hotspot/share/gc/x/xMemory.cpp deleted file mode 100644 index e394f580ab939..0000000000000 --- a/src/hotspot/share/gc/x/xMemory.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -#include "precompiled.hpp" -#include "gc/x/xList.inline.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xMemory.inline.hpp" - -XMemory* XMemoryManager::create(uintptr_t start, size_t size) { - XMemory* const area = new XMemory(start, size); - if (_callbacks._create != nullptr) { - _callbacks._create(area); - } - return area; -} - -void XMemoryManager::destroy(XMemory* area) { - if (_callbacks._destroy != nullptr) { - _callbacks._destroy(area); - } - delete area; -} - -void XMemoryManager::shrink_from_front(XMemory* area, size_t size) { - if (_callbacks._shrink_from_front != nullptr) { - _callbacks._shrink_from_front(area, size); - } - area->shrink_from_front(size); -} - -void XMemoryManager::shrink_from_back(XMemory* area, size_t size) { - if (_callbacks._shrink_from_back != nullptr) { - _callbacks._shrink_from_back(area, size); - } - area->shrink_from_back(size); -} - -void XMemoryManager::grow_from_front(XMemory* area, size_t size) { - if (_callbacks._grow_from_front != nullptr) { - _callbacks._grow_from_front(area, size); - } - area->grow_from_front(size); -} - -void XMemoryManager::grow_from_back(XMemory* area, size_t size) { - if (_callbacks._grow_from_back != nullptr) { - _callbacks._grow_from_back(area, size); - } - area->grow_from_back(size); -} - -XMemoryManager::Callbacks::Callbacks() : - _create(nullptr), - _destroy(nullptr), - _shrink_from_front(nullptr), - _shrink_from_back(nullptr), - _grow_from_front(nullptr), - _grow_from_back(nullptr) {} - -XMemoryManager::XMemoryManager() : - _freelist(), - _callbacks() {} - -void XMemoryManager::register_callbacks(const Callbacks& callbacks) { - _callbacks = callbacks; -} - -uintptr_t XMemoryManager::peek_low_address() const { - XLocker locker(&_lock); - - const XMemory* const area = _freelist.first(); - if (area != nullptr) { - return area->start(); - } - - // Out of memory - return UINTPTR_MAX; -} - -uintptr_t XMemoryManager::alloc_low_address(size_t size) { - XLocker locker(&_lock); - - XListIterator iter(&_freelist); - for (XMemory* area; iter.next(&area);) { - if (area->size() >= size) { - if (area->size() == size) { - // Exact match, remove area - const uintptr_t start = area->start(); - _freelist.remove(area); - destroy(area); - return start; - } else { - // Larger than requested, shrink area - const uintptr_t start = area->start(); - shrink_from_front(area, size); - return start; - } - } - } - - // Out of memory - return UINTPTR_MAX; -} - -uintptr_t XMemoryManager::alloc_low_address_at_most(size_t size, size_t* allocated) { - XLocker locker(&_lock); - - XMemory* area = _freelist.first(); - if (area != nullptr) { - if (area->size() <= size) { - // Smaller than or equal to requested, remove area - const uintptr_t start = area->start(); - *allocated = area->size(); - _freelist.remove(area); - destroy(area); - return start; - } else { - // Larger than requested, shrink area - const uintptr_t start = area->start(); - shrink_from_front(area, size); - *allocated = size; - return start; - } - } - - // Out of memory - *allocated = 0; - return UINTPTR_MAX; -} - -uintptr_t XMemoryManager::alloc_high_address(size_t size) { - XLocker locker(&_lock); - - XListReverseIterator iter(&_freelist); - for (XMemory* area; iter.next(&area);) { - if (area->size() >= size) { - if (area->size() == size) { - // Exact match, remove area - const uintptr_t start = area->start(); - _freelist.remove(area); - destroy(area); - return start; - } else { - // Larger than requested, shrink area - shrink_from_back(area, size); - return area->end(); - } - } - } - - // Out of memory - return UINTPTR_MAX; -} - -void XMemoryManager::free(uintptr_t start, size_t size) { - assert(start != UINTPTR_MAX, "Invalid address"); - const uintptr_t end = start + size; - - XLocker locker(&_lock); - - XListIterator iter(&_freelist); - for (XMemory* area; iter.next(&area);) { - if (start < area->start()) { - XMemory* const prev = _freelist.prev(area); - if (prev != nullptr && start == prev->end()) { - if (end == area->start()) { - // Merge with prev and current area - grow_from_back(prev, size + area->size()); - _freelist.remove(area); - delete area; - } else { - // Merge with prev area - grow_from_back(prev, size); - } - } else if (end == area->start()) { - // Merge with current area - grow_from_front(area, size); - } else { - // Insert new area before current area - assert(end < area->start(), "Areas must not overlap"); - XMemory* const new_area = create(start, size); - _freelist.insert_before(area, new_area); - } - - // Done - return; - } - } - - // Insert last - XMemory* const last = _freelist.last(); - if (last != nullptr && start == last->end()) { - // Merge with last area - grow_from_back(last, size); - } else { - // Insert new area last - XMemory* const new_area = create(start, size); - _freelist.insert_last(new_area); - } -} diff --git a/src/hotspot/share/gc/x/xMemory.hpp b/src/hotspot/share/gc/x/xMemory.hpp deleted file mode 100644 index 2c3739cb44a58..0000000000000 --- a/src/hotspot/share/gc/x/xMemory.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XMEMORY_HPP -#define SHARE_GC_X_XMEMORY_HPP - -#include "gc/x/xList.hpp" -#include "gc/x/xLock.hpp" -#include "memory/allocation.hpp" - -class XMemory : public CHeapObj { - friend class XList; - -private: - uintptr_t _start; - uintptr_t _end; - XListNode _node; - -public: - XMemory(uintptr_t start, size_t size); - - uintptr_t start() const; - uintptr_t end() const; - size_t size() const; - - void shrink_from_front(size_t size); - void shrink_from_back(size_t size); - void grow_from_front(size_t size); - void grow_from_back(size_t size); -}; - -class XMemoryManager { -public: - typedef void (*CreateDestroyCallback)(const XMemory* area); - typedef void (*ResizeCallback)(const XMemory* area, size_t size); - - struct Callbacks { - CreateDestroyCallback _create; - CreateDestroyCallback _destroy; - ResizeCallback _shrink_from_front; - ResizeCallback _shrink_from_back; - ResizeCallback _grow_from_front; - ResizeCallback _grow_from_back; - - Callbacks(); - }; - -private: - mutable XLock _lock; - XList _freelist; - Callbacks _callbacks; - - XMemory* create(uintptr_t start, size_t size); - void destroy(XMemory* area); - void shrink_from_front(XMemory* area, size_t size); - void shrink_from_back(XMemory* area, size_t size); - void grow_from_front(XMemory* area, size_t size); - void grow_from_back(XMemory* area, size_t size); - -public: - XMemoryManager(); - - void register_callbacks(const Callbacks& callbacks); - - uintptr_t peek_low_address() const; - uintptr_t alloc_low_address(size_t size); - uintptr_t alloc_low_address_at_most(size_t size, size_t* allocated); - uintptr_t alloc_high_address(size_t size); - - void free(uintptr_t start, size_t size); -}; - -#endif // SHARE_GC_X_XMEMORY_HPP diff --git a/src/hotspot/share/gc/x/xMemory.inline.hpp b/src/hotspot/share/gc/x/xMemory.inline.hpp deleted file mode 100644 index 332cdae9160ed..0000000000000 --- a/src/hotspot/share/gc/x/xMemory.inline.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XMEMORY_INLINE_HPP -#define SHARE_GC_X_XMEMORY_INLINE_HPP - -#include "gc/x/xMemory.hpp" - -#include "gc/x/xList.inline.hpp" -#include "utilities/debug.hpp" - -inline XMemory::XMemory(uintptr_t start, size_t size) : - _start(start), - _end(start + size) {} - -inline uintptr_t XMemory::start() const { - return _start; -} - -inline uintptr_t XMemory::end() const { - return _end; -} - -inline size_t XMemory::size() const { - return end() - start(); -} - -inline void XMemory::shrink_from_front(size_t size) { - assert(this->size() > size, "Too small"); - _start += size; -} - -inline void XMemory::shrink_from_back(size_t size) { - assert(this->size() > size, "Too small"); - _end -= size; -} - -inline void XMemory::grow_from_front(size_t size) { - assert(start() >= size, "Too big"); - _start -= size; -} - -inline void XMemory::grow_from_back(size_t size) { - _end += size; -} - -#endif // SHARE_GC_X_XMEMORY_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xMessagePort.hpp b/src/hotspot/share/gc/x/xMessagePort.hpp deleted file mode 100644 index 205652537968c..0000000000000 --- a/src/hotspot/share/gc/x/xMessagePort.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XMESSAGEPORT_HPP -#define SHARE_GC_X_XMESSAGEPORT_HPP - -#include "gc/x/xFuture.hpp" -#include "gc/x/xList.hpp" -#include "runtime/mutex.hpp" - -template class XMessageRequest; - -template -class XMessagePort { -private: - typedef XMessageRequest Request; - - mutable Monitor _monitor; - bool _has_message; - T _message; - uint64_t _seqnum; - XList _queue; - -public: - XMessagePort(); - - bool is_busy() const; - - void send_sync(const T& message); - void send_async(const T& message); - - T receive(); - void ack(); -}; - -class XRendezvousPort { -private: - XMessagePort _port; - -public: - void signal(); - void wait(); - void ack(); -}; - -#endif // SHARE_GC_X_XMESSAGEPORT_HPP diff --git a/src/hotspot/share/gc/x/xMessagePort.inline.hpp b/src/hotspot/share/gc/x/xMessagePort.inline.hpp deleted file mode 100644 index 8007a80eacdf0..0000000000000 --- a/src/hotspot/share/gc/x/xMessagePort.inline.hpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XMESSAGEPORT_INLINE_HPP -#define SHARE_GC_X_XMESSAGEPORT_INLINE_HPP - -#include "gc/x/xMessagePort.hpp" - -#include "gc/x/xFuture.inline.hpp" -#include "gc/x/xList.inline.hpp" -#include "runtime/mutexLocker.hpp" - -template -class XMessageRequest : public StackObj { - friend class XList; - -private: - T _message; - uint64_t _seqnum; - XFuture _result; - XListNode _node; - -public: - void initialize(T message, uint64_t seqnum) { - _message = message; - _seqnum = seqnum; - } - - T message() const { - return _message; - } - - uint64_t seqnum() const { - return _seqnum; - } - - void wait() { - const T message = _result.get(); - assert(message == _message, "Message mismatch"); - } - - void satisfy(T message) { - _result.set(message); - } -}; - -template -inline XMessagePort::XMessagePort() : - _monitor(Monitor::nosafepoint, "XMessagePort_lock"), - _has_message(false), - _seqnum(0), - _queue() {} - -template -inline bool XMessagePort::is_busy() const { - MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag); - return _has_message; -} - -template -inline void XMessagePort::send_sync(const T& message) { - Request request; - - { - // Enqueue message - MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag); - request.initialize(message, _seqnum); - _queue.insert_last(&request); - ml.notify(); - } - - // Wait for completion - request.wait(); - - { - // Guard deletion of underlying semaphore. This is a workaround for a - // bug in sem_post() in glibc < 2.21, where it's not safe to destroy - // the semaphore immediately after returning from sem_wait(). The - // reason is that sem_post() can touch the semaphore after a waiting - // thread have returned from sem_wait(). To avoid this race we are - // forcing the waiting thread to acquire/release the lock held by the - // posting thread. https://sourceware.org/bugzilla/show_bug.cgi?id=12674 - MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag); - } -} - -template -inline void XMessagePort::send_async(const T& message) { - MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag); - if (!_has_message) { - // Post message - _message = message; - _has_message = true; - ml.notify(); - } -} - -template -inline T XMessagePort::receive() { - MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag); - - // Wait for message - while (!_has_message && _queue.is_empty()) { - ml.wait(); - } - - // Increment request sequence number - _seqnum++; - - if (!_has_message) { - // Message available in the queue - _message = _queue.first()->message(); - _has_message = true; - } - - return _message; -} - -template -inline void XMessagePort::ack() { - MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag); - - if (!_has_message) { - // Nothing to ack - return; - } - - // Satisfy requests (and duplicates) in queue - XListIterator iter(&_queue); - for (Request* request; iter.next(&request);) { - if (request->message() == _message && request->seqnum() < _seqnum) { - // Dequeue and satisfy request. Note that the dequeue operation must - // happen first, since the request will immediately be deallocated - // once it has been satisfied. - _queue.remove(request); - request->satisfy(_message); - } - } - - if (_queue.is_empty()) { - // Queue is empty - _has_message = false; - } else { - // Post first message in queue - _message = _queue.first()->message(); - } -} - -inline void XRendezvousPort::signal() { - _port.send_sync(true /* ignored */); -} - -inline void XRendezvousPort::wait() { - _port.receive(); -} - -inline void XRendezvousPort::ack() { - _port.ack(); -} - -#endif // SHARE_GC_X_XMESSAGEPORT_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xMetronome.cpp b/src/hotspot/share/gc/x/xMetronome.cpp deleted file mode 100644 index 7f0b649deb467..0000000000000 --- a/src/hotspot/share/gc/x/xMetronome.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xMetronome.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/timer.hpp" -#include "utilities/ticks.hpp" - -XMetronome::XMetronome(uint64_t hz) : - _monitor(Monitor::nosafepoint, "XMetronome_lock"), - _interval_ms(MILLIUNITS / hz), - _start_ms(0), - _nticks(0), - _stopped(false) {} - -bool XMetronome::wait_for_tick() { - if (_nticks++ == 0) { - // First tick, set start time - const Ticks now = Ticks::now(); - _start_ms = TimeHelper::counter_to_millis(now.value()); - } - - MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag); - - while (!_stopped) { - // We might wake up spuriously from wait, so always recalculate - // the timeout after a wakeup to see if we need to wait again. - const Ticks now = Ticks::now(); - const uint64_t now_ms = TimeHelper::counter_to_millis(now.value()); - const uint64_t next_ms = _start_ms + (_interval_ms * _nticks); - const int64_t timeout_ms = next_ms - now_ms; - - if (timeout_ms > 0) { - // Wait - ml.wait(timeout_ms); - } else { - // Tick - if (timeout_ms < 0) { - const uint64_t overslept = -timeout_ms; - if (overslept > _interval_ms) { - // Missed one or more ticks. Bump _nticks accordingly to - // avoid firing a string of immediate ticks to make up - // for the ones we missed. - _nticks += overslept / _interval_ms; - } - } - - return true; - } - } - - // Stopped - return false; -} - -void XMetronome::stop() { - MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag); - _stopped = true; - ml.notify(); -} diff --git a/src/hotspot/share/gc/x/xMetronome.hpp b/src/hotspot/share/gc/x/xMetronome.hpp deleted file mode 100644 index 8a0f27061c33c..0000000000000 --- a/src/hotspot/share/gc/x/xMetronome.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XMETRONOME_HPP -#define SHARE_GC_X_XMETRONOME_HPP - -#include "memory/allocation.hpp" -#include "runtime/mutex.hpp" - -class XMetronome : public StackObj { -private: - Monitor _monitor; - const uint64_t _interval_ms; - uint64_t _start_ms; - uint64_t _nticks; - bool _stopped; - -public: - XMetronome(uint64_t hz); - - bool wait_for_tick(); - void stop(); -}; - -#endif // SHARE_GC_X_XMETRONOME_HPP diff --git a/src/hotspot/share/gc/x/xNMethod.cpp b/src/hotspot/share/gc/x/xNMethod.cpp deleted file mode 100644 index 24b02b8328004..0000000000000 --- a/src/hotspot/share/gc/x/xNMethod.cpp +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "code/relocInfo.hpp" -#include "code/nmethod.hpp" -#include "gc/shared/barrierSet.hpp" -#include "gc/shared/barrierSetNMethod.hpp" -#include "gc/shared/classUnloadingContext.hpp" -#include "gc/shared/suspendibleThreadSet.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xNMethod.hpp" -#include "gc/x/xNMethodData.hpp" -#include "gc/x/xNMethodTable.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xWorkers.hpp" -#include "logging/log.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/iterator.hpp" -#include "memory/resourceArea.hpp" -#include "memory/universe.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/atomic.hpp" -#include "runtime/continuation.hpp" -#include "utilities/debug.hpp" - -static XNMethodData* gc_data(const nmethod* nm) { - return nm->gc_data(); -} - -static void set_gc_data(nmethod* nm, XNMethodData* data) { - return nm->set_gc_data(data); -} - -void XNMethod::attach_gc_data(nmethod* nm) { - GrowableArray immediate_oops; - bool non_immediate_oops = false; - - // Find all oop relocations - RelocIterator iter(nm); - while (iter.next()) { - if (iter.type() != relocInfo::oop_type) { - // Not an oop - continue; - } - - oop_Relocation* r = iter.oop_reloc(); - - if (!r->oop_is_immediate()) { - // Non-immediate oop found - non_immediate_oops = true; - continue; - } - - if (r->oop_value() != nullptr) { - // Non-null immediate oop found. Null oops can safely be - // ignored since the method will be re-registered if they - // are later patched to be non-null. - immediate_oops.push(r->oop_addr()); - } - } - - // Attach GC data to nmethod - XNMethodData* data = gc_data(nm); - if (data == nullptr) { - data = new XNMethodData(); - set_gc_data(nm, data); - } - - // Attach oops in GC data - XNMethodDataOops* const new_oops = XNMethodDataOops::create(immediate_oops, non_immediate_oops); - XNMethodDataOops* const old_oops = data->swap_oops(new_oops); - XNMethodDataOops::destroy(old_oops); -} - -XReentrantLock* XNMethod::lock_for_nmethod(nmethod* nm) { - return gc_data(nm)->lock(); -} - -XReentrantLock* XNMethod::ic_lock_for_nmethod(nmethod* nm) { - return gc_data(nm)->ic_lock(); -} - -void XNMethod::log_register(const nmethod* nm) { - LogTarget(Trace, gc, nmethod) log; - if (!log.is_enabled()) { - return; - } - - const XNMethodDataOops* const oops = gc_data(nm)->oops(); - - log.print("Register NMethod: %s.%s (" PTR_FORMAT "), " - "Compiler: %s, Oops: %d, ImmediateOops: " SIZE_FORMAT ", NonImmediateOops: %s", - nm->method()->method_holder()->external_name(), - nm->method()->name()->as_C_string(), - p2i(nm), - nm->compiler_name(), - nm->oops_count() - 1, - oops->immediates_count(), - oops->has_non_immediates() ? "Yes" : "No"); - - LogTarget(Trace, gc, nmethod, oops) log_oops; - if (!log_oops.is_enabled()) { - return; - } - - // Print nmethod oops table - { - oop* const begin = nm->oops_begin(); - oop* const end = nm->oops_end(); - for (oop* p = begin; p < end; p++) { - const oop o = Atomic::load(p); // C1 PatchingStub may replace it concurrently. - const char* external_name = (o == nullptr) ? "N/A" : o->klass()->external_name(); - log_oops.print(" Oop[" SIZE_FORMAT "] " PTR_FORMAT " (%s)", - (p - begin), p2i(o), external_name); - } - } - - // Print nmethod immediate oops - { - oop** const begin = oops->immediates_begin(); - oop** const end = oops->immediates_end(); - for (oop** p = begin; p < end; p++) { - log_oops.print(" ImmediateOop[" SIZE_FORMAT "] " PTR_FORMAT " @ " PTR_FORMAT " (%s)", - (p - begin), p2i(**p), p2i(*p), (**p)->klass()->external_name()); - } - } -} - -void XNMethod::log_unregister(const nmethod* nm) { - LogTarget(Debug, gc, nmethod) log; - if (!log.is_enabled()) { - return; - } - - log.print("Unregister NMethod: %s.%s (" PTR_FORMAT ")", - nm->method()->method_holder()->external_name(), - nm->method()->name()->as_C_string(), - p2i(nm)); -} - -void XNMethod::register_nmethod(nmethod* nm) { - ResourceMark rm; - - // Create and attach gc data - attach_gc_data(nm); - - log_register(nm); - - XNMethodTable::register_nmethod(nm); - - // Disarm nmethod entry barrier - disarm(nm); -} - -void XNMethod::unregister_nmethod(nmethod* nm) { - ResourceMark rm; - - log_unregister(nm); - - XNMethodTable::unregister_nmethod(nm); - - // Destroy GC data - delete gc_data(nm); -} - -bool XNMethod::supports_entry_barrier(nmethod* nm) { - BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod(); - return bs->supports_entry_barrier(nm); -} - -bool XNMethod::is_armed(nmethod* nm) { - BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod(); - return bs->is_armed(nm); -} - -void XNMethod::disarm(nmethod* nm) { - BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod(); - bs->disarm(nm); -} - -void XNMethod::set_guard_value(nmethod* nm, int value) { - BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod(); - bs->set_guard_value(nm, value); -} - -void XNMethod::nmethod_oops_do(nmethod* nm, OopClosure* cl) { - XLocker locker(XNMethod::lock_for_nmethod(nm)); - XNMethod::nmethod_oops_do_inner(nm, cl); -} - -void XNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl) { - // Process oops table - { - oop* const begin = nm->oops_begin(); - oop* const end = nm->oops_end(); - for (oop* p = begin; p < end; p++) { - if (!Universe::contains_non_oop_word(p)) { - cl->do_oop(p); - } - } - } - - XNMethodDataOops* const oops = gc_data(nm)->oops(); - - // Process immediate oops - { - oop** const begin = oops->immediates_begin(); - oop** const end = oops->immediates_end(); - for (oop** p = begin; p < end; p++) { - if (*p != Universe::non_oop_word()) { - cl->do_oop(*p); - } - } - } - - // Process non-immediate oops - if (oops->has_non_immediates()) { - nm->fix_oop_relocations(); - } -} - -class XNMethodOopClosure : public OopClosure { -public: - virtual void do_oop(oop* p) { - if (XResurrection::is_blocked()) { - XBarrier::keep_alive_barrier_on_phantom_root_oop_field(p); - } else { - XBarrier::load_barrier_on_root_oop_field(p); - } - } - - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } -}; - -void XNMethod::nmethod_oops_barrier(nmethod* nm) { - XNMethodOopClosure cl; - nmethod_oops_do_inner(nm, &cl); -} - -void XNMethod::nmethods_do_begin() { - XNMethodTable::nmethods_do_begin(); -} - -void XNMethod::nmethods_do_end() { - XNMethodTable::nmethods_do_end(); -} - -void XNMethod::nmethods_do(NMethodClosure* cl) { - XNMethodTable::nmethods_do(cl); -} - -class XNMethodUnlinkClosure : public NMethodClosure { -private: - bool _unloading_occurred; - volatile bool _failed; - - void set_failed() { - Atomic::store(&_failed, true); - } - -public: - XNMethodUnlinkClosure(bool unloading_occurred) : - _unloading_occurred(unloading_occurred), - _failed(false) {} - - virtual void do_nmethod(nmethod* nm) { - if (failed()) { - return; - } - - if (nm->is_unloading()) { - XLocker locker(XNMethod::lock_for_nmethod(nm)); - nm->unlink(); - return; - } - - { - XLocker locker(XNMethod::lock_for_nmethod(nm)); - - if (XNMethod::is_armed(nm)) { - // Heal oops and arm phase invariantly - XNMethod::nmethod_oops_barrier(nm); - XNMethod::set_guard_value(nm, 0); - } - } - - // Clear compiled ICs and exception caches - XLocker locker(XNMethod::ic_lock_for_nmethod(nm)); - nm->unload_nmethod_caches(_unloading_occurred); - } - - bool failed() const { - return Atomic::load(&_failed); - } -}; - -class XNMethodUnlinkTask : public XTask { -private: - XNMethodUnlinkClosure _cl; - -public: - XNMethodUnlinkTask(bool unloading_occurred) : - XTask("XNMethodUnlinkTask"), - _cl(unloading_occurred) { - XNMethodTable::nmethods_do_begin(); - } - - ~XNMethodUnlinkTask() { - XNMethodTable::nmethods_do_end(); - } - - virtual void work() { - XNMethodTable::nmethods_do(&_cl); - } -}; - -void XNMethod::unlink(XWorkers* workers, bool unloading_occurred) { - XNMethodUnlinkTask task(unloading_occurred); - workers->run(&task); -} - -void XNMethod::purge() { - ClassUnloadingContext::context()->purge_and_free_nmethods(); -} diff --git a/src/hotspot/share/gc/x/xNMethod.hpp b/src/hotspot/share/gc/x/xNMethod.hpp deleted file mode 100644 index 49fdecf584df3..0000000000000 --- a/src/hotspot/share/gc/x/xNMethod.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XNMETHOD_HPP -#define SHARE_GC_X_XNMETHOD_HPP - -#include "memory/allStatic.hpp" - -class nmethod; -class NMethodClosure; -class XReentrantLock; -class XWorkers; - -class XNMethod : public AllStatic { -private: - static void attach_gc_data(nmethod* nm); - - static void log_register(const nmethod* nm); - static void log_unregister(const nmethod* nm); - -public: - static void register_nmethod(nmethod* nm); - static void unregister_nmethod(nmethod* nm); - - static bool supports_entry_barrier(nmethod* nm); - - static bool is_armed(nmethod* nm); - static void disarm(nmethod* nm); - static void set_guard_value(nmethod* nm, int value); - - static void nmethod_oops_do(nmethod* nm, OopClosure* cl); - static void nmethod_oops_do_inner(nmethod* nm, OopClosure* cl); - - static void nmethod_oops_barrier(nmethod* nm); - - static void nmethods_do_begin(); - static void nmethods_do_end(); - static void nmethods_do(NMethodClosure* cl); - - static XReentrantLock* lock_for_nmethod(nmethod* nm); - static XReentrantLock* ic_lock_for_nmethod(nmethod* nm); - - static void unlink(XWorkers* workers, bool unloading_occurred); - static void purge(); -}; - -#endif // SHARE_GC_X_XNMETHOD_HPP diff --git a/src/hotspot/share/gc/x/xNMethodData.cpp b/src/hotspot/share/gc/x/xNMethodData.cpp deleted file mode 100644 index 63fbfda99e29b..0000000000000 --- a/src/hotspot/share/gc/x/xNMethodData.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2017, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xAttachedArray.inline.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xNMethodData.hpp" -#include "memory/allocation.hpp" -#include "runtime/atomic.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" -#include "utilities/growableArray.hpp" - -XNMethodDataOops* XNMethodDataOops::create(const GrowableArray& immediates, bool has_non_immediates) { - return ::new (AttachedArray::alloc(immediates.length())) XNMethodDataOops(immediates, has_non_immediates); -} - -void XNMethodDataOops::destroy(XNMethodDataOops* oops) { - AttachedArray::free(oops); -} - -XNMethodDataOops::XNMethodDataOops(const GrowableArray& immediates, bool has_non_immediates) : - _immediates(immediates.length()), - _has_non_immediates(has_non_immediates) { - // Save all immediate oops - for (size_t i = 0; i < immediates_count(); i++) { - immediates_begin()[i] = immediates.at(int(i)); - } -} - -size_t XNMethodDataOops::immediates_count() const { - return _immediates.length(); -} - -oop** XNMethodDataOops::immediates_begin() const { - return _immediates(this); -} - -oop** XNMethodDataOops::immediates_end() const { - return immediates_begin() + immediates_count(); -} - -bool XNMethodDataOops::has_non_immediates() const { - return _has_non_immediates; -} - -XNMethodData::XNMethodData() : - _lock(), - _ic_lock(), - _oops(nullptr) {} - -XNMethodData::~XNMethodData() { - XNMethodDataOops::destroy(_oops); -} - -XReentrantLock* XNMethodData::lock() { - return &_lock; -} - -XReentrantLock* XNMethodData::ic_lock() { - return &_ic_lock; -} - -XNMethodDataOops* XNMethodData::oops() const { - return Atomic::load_acquire(&_oops); -} - -XNMethodDataOops* XNMethodData::swap_oops(XNMethodDataOops* new_oops) { - XLocker locker(&_lock); - XNMethodDataOops* const old_oops = _oops; - _oops = new_oops; - return old_oops; -} diff --git a/src/hotspot/share/gc/x/xNMethodData.hpp b/src/hotspot/share/gc/x/xNMethodData.hpp deleted file mode 100644 index 14549f41342ee..0000000000000 --- a/src/hotspot/share/gc/x/xNMethodData.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2017, 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 - * 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_GC_X_XNMETHODDATA_HPP -#define SHARE_GC_X_XNMETHODDATA_HPP - -#include "gc/x/xAttachedArray.hpp" -#include "gc/x/xLock.hpp" -#include "memory/allocation.hpp" -#include "oops/oopsHierarchy.hpp" -#include "utilities/globalDefinitions.hpp" - -class nmethod; -template class GrowableArray; - -class XNMethodDataOops { -private: - typedef XAttachedArray AttachedArray; - - const AttachedArray _immediates; - const bool _has_non_immediates; - - XNMethodDataOops(const GrowableArray& immediates, bool has_non_immediates); - -public: - static XNMethodDataOops* create(const GrowableArray& immediates, bool has_non_immediates); - static void destroy(XNMethodDataOops* oops); - - size_t immediates_count() const; - oop** immediates_begin() const; - oop** immediates_end() const; - - bool has_non_immediates() const; -}; - -class XNMethodData : public CHeapObj { -private: - XReentrantLock _lock; - XReentrantLock _ic_lock; - XNMethodDataOops* volatile _oops; - -public: - XNMethodData(); - ~XNMethodData(); - - XReentrantLock* lock(); - XReentrantLock* ic_lock(); - - XNMethodDataOops* oops() const; - XNMethodDataOops* swap_oops(XNMethodDataOops* oops); -}; - -#endif // SHARE_GC_X_XNMETHODDATA_HPP diff --git a/src/hotspot/share/gc/x/xNMethodTable.cpp b/src/hotspot/share/gc/x/xNMethodTable.cpp deleted file mode 100644 index 52fcba755a70b..0000000000000 --- a/src/hotspot/share/gc/x/xNMethodTable.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2017, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "code/relocInfo.hpp" -#include "code/nmethod.hpp" -#include "gc/shared/barrierSet.hpp" -#include "gc/shared/barrierSetNMethod.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xHash.inline.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xNMethodData.hpp" -#include "gc/x/xNMethodTable.hpp" -#include "gc/x/xNMethodTableEntry.hpp" -#include "gc/x/xNMethodTableIteration.hpp" -#include "gc/x/xSafeDelete.inline.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xWorkers.hpp" -#include "logging/log.hpp" -#include "memory/allocation.hpp" -#include "memory/iterator.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/mutexLocker.hpp" -#include "utilities/debug.hpp" -#include "utilities/powerOfTwo.hpp" - -XNMethodTableEntry* XNMethodTable::_table = nullptr; -size_t XNMethodTable::_size = 0; -size_t XNMethodTable::_nregistered = 0; -size_t XNMethodTable::_nunregistered = 0; -XNMethodTableIteration XNMethodTable::_iteration; -XSafeDeleteNoLock XNMethodTable::_safe_delete; - -size_t XNMethodTable::first_index(const nmethod* nm, size_t size) { - assert(is_power_of_2(size), "Invalid size"); - const size_t mask = size - 1; - const size_t hash = XHash::address_to_uint32((uintptr_t)nm); - return hash & mask; -} - -size_t XNMethodTable::next_index(size_t prev_index, size_t size) { - assert(is_power_of_2(size), "Invalid size"); - const size_t mask = size - 1; - return (prev_index + 1) & mask; -} - -bool XNMethodTable::register_entry(XNMethodTableEntry* table, size_t size, nmethod* nm) { - const XNMethodTableEntry entry(nm); - size_t index = first_index(nm, size); - - for (;;) { - const XNMethodTableEntry table_entry = table[index]; - - if (!table_entry.registered() && !table_entry.unregistered()) { - // Insert new entry - table[index] = entry; - return true; - } - - if (table_entry.registered() && table_entry.method() == nm) { - // Replace existing entry - table[index] = entry; - return false; - } - - index = next_index(index, size); - } -} - -void XNMethodTable::unregister_entry(XNMethodTableEntry* table, size_t size, nmethod* nm) { - size_t index = first_index(nm, size); - - for (;;) { - const XNMethodTableEntry table_entry = table[index]; - assert(table_entry.registered() || table_entry.unregistered(), "Entry not found"); - - if (table_entry.registered() && table_entry.method() == nm) { - // Remove entry - table[index] = XNMethodTableEntry(true /* unregistered */); - return; - } - - index = next_index(index, size); - } -} - -void XNMethodTable::rebuild(size_t new_size) { - assert(CodeCache_lock->owned_by_self(), "Lock must be held"); - - assert(is_power_of_2(new_size), "Invalid size"); - - log_debug(gc, nmethod)("Rebuilding NMethod Table: " - SIZE_FORMAT "->" SIZE_FORMAT " entries, " - SIZE_FORMAT "(%.0f%%->%.0f%%) registered, " - SIZE_FORMAT "(%.0f%%->%.0f%%) unregistered", - _size, new_size, - _nregistered, percent_of(_nregistered, _size), percent_of(_nregistered, new_size), - _nunregistered, percent_of(_nunregistered, _size), 0.0); - - // Allocate new table - XNMethodTableEntry* const new_table = new XNMethodTableEntry[new_size]; - - // Transfer all registered entries - for (size_t i = 0; i < _size; i++) { - const XNMethodTableEntry entry = _table[i]; - if (entry.registered()) { - register_entry(new_table, new_size, entry.method()); - } - } - - // Free old table - _safe_delete(_table); - - // Install new table - _table = new_table; - _size = new_size; - _nunregistered = 0; -} - -void XNMethodTable::rebuild_if_needed() { - // The hash table uses linear probing. To avoid wasting memory while - // at the same time maintaining good hash collision behavior we want - // to keep the table occupancy between 30% and 70%. The table always - // grows/shrinks by doubling/halving its size. Pruning of unregistered - // entries is done by rebuilding the table with or without resizing it. - const size_t min_size = 1024; - const size_t shrink_threshold = _size * 0.30; - const size_t prune_threshold = _size * 0.65; - const size_t grow_threshold = _size * 0.70; - - if (_size == 0) { - // Initialize table - rebuild(min_size); - } else if (_nregistered < shrink_threshold && _size > min_size) { - // Shrink table - rebuild(_size / 2); - } else if (_nregistered + _nunregistered > grow_threshold) { - // Prune or grow table - if (_nregistered < prune_threshold) { - // Prune table - rebuild(_size); - } else { - // Grow table - rebuild(_size * 2); - } - } -} - -size_t XNMethodTable::registered_nmethods() { - return _nregistered; -} - -size_t XNMethodTable::unregistered_nmethods() { - return _nunregistered; -} - -void XNMethodTable::register_nmethod(nmethod* nm) { - assert(CodeCache_lock->owned_by_self(), "Lock must be held"); - - // Grow/Shrink/Prune table if needed - rebuild_if_needed(); - - // Insert new entry - if (register_entry(_table, _size, nm)) { - // New entry registered. When register_entry() instead returns - // false the nmethod was already in the table so we do not want - // to increase number of registered entries in that case. - _nregistered++; - } -} - -void XNMethodTable::wait_until_iteration_done() { - assert(CodeCache_lock->owned_by_self(), "Lock must be held"); - - while (_iteration.in_progress()) { - CodeCache_lock->wait_without_safepoint_check(); - } -} - -void XNMethodTable::unregister_nmethod(nmethod* nm) { - assert(CodeCache_lock->owned_by_self(), "Lock must be held"); - - // Remove entry - unregister_entry(_table, _size, nm); - _nunregistered++; - _nregistered--; -} - -void XNMethodTable::nmethods_do_begin() { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - - // Do not allow the table to be deleted while iterating - _safe_delete.enable_deferred_delete(); - - // Prepare iteration - _iteration.nmethods_do_begin(_table, _size); -} - -void XNMethodTable::nmethods_do_end() { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - - // Finish iteration - _iteration.nmethods_do_end(); - - // Allow the table to be deleted - _safe_delete.disable_deferred_delete(); - - // Notify iteration done - CodeCache_lock->notify_all(); -} - -void XNMethodTable::nmethods_do(NMethodClosure* cl) { - _iteration.nmethods_do(cl); -} diff --git a/src/hotspot/share/gc/x/xNMethodTable.hpp b/src/hotspot/share/gc/x/xNMethodTable.hpp deleted file mode 100644 index ebb7803a08376..0000000000000 --- a/src/hotspot/share/gc/x/xNMethodTable.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XNMETHODTABLE_HPP -#define SHARE_GC_X_XNMETHODTABLE_HPP - -#include "gc/x/xNMethodTableIteration.hpp" -#include "gc/x/xSafeDelete.hpp" -#include "memory/allStatic.hpp" - -class nmethod; -class NMethodClosure; -class XNMethodTableEntry; -class XWorkers; - -class XNMethodTable : public AllStatic { -private: - static XNMethodTableEntry* _table; - static size_t _size; - static size_t _nregistered; - static size_t _nunregistered; - static XNMethodTableIteration _iteration; - static XSafeDeleteNoLock _safe_delete; - - static XNMethodTableEntry* create(size_t size); - static void destroy(XNMethodTableEntry* table); - - static size_t first_index(const nmethod* nm, size_t size); - static size_t next_index(size_t prev_index, size_t size); - - static bool register_entry(XNMethodTableEntry* table, size_t size, nmethod* nm); - static void unregister_entry(XNMethodTableEntry* table, size_t size, nmethod* nm); - - static void rebuild(size_t new_size); - static void rebuild_if_needed(); - -public: - static size_t registered_nmethods(); - static size_t unregistered_nmethods(); - - static void register_nmethod(nmethod* nm); - static void unregister_nmethod(nmethod* nm); - - static void wait_until_iteration_done(); - - static void nmethods_do_begin(); - static void nmethods_do_end(); - static void nmethods_do(NMethodClosure* cl); - - static void unlink(XWorkers* workers, bool unloading_occurred); - static void purge(XWorkers* workers); -}; - -#endif // SHARE_GC_X_XNMETHODTABLE_HPP diff --git a/src/hotspot/share/gc/x/xNMethodTableEntry.hpp b/src/hotspot/share/gc/x/xNMethodTableEntry.hpp deleted file mode 100644 index 9f06abb0bdbf6..0000000000000 --- a/src/hotspot/share/gc/x/xNMethodTableEntry.hpp +++ /dev/null @@ -1,81 +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. - */ - -#ifndef SHARE_GC_X_XNMETHODTABLEENTRY_HPP -#define SHARE_GC_X_XNMETHODTABLEENTRY_HPP - -#include "gc/x/xBitField.hpp" -#include "memory/allocation.hpp" - -class nmethod; - -// -// NMethod table entry layout -// -------------------------- -// -// 6 -// 3 2 1 0 -// +---------------------------------------------------------------------+-+-+ -// |11111111 11111111 11111111 11111111 11111111 11111111 11111111 111111|1|1| -// +---------------------------------------------------------------------+-+-+ -// | | | -// | 1-1 Unregistered Flag (1-bits) * | -// | | -// | 0-0 Registered Flag (1-bits) * -// | -// * 63-2 NMethod Address (62-bits) -// - -class XNMethodTableEntry : public CHeapObj { -private: - typedef XBitField field_registered; - typedef XBitField field_unregistered; - typedef XBitField field_method; - - uint64_t _entry; - -public: - explicit XNMethodTableEntry(bool unregistered = false) : - _entry(field_registered::encode(false) | - field_unregistered::encode(unregistered) | - field_method::encode(nullptr)) {} - - explicit XNMethodTableEntry(nmethod* method) : - _entry(field_registered::encode(true) | - field_unregistered::encode(false) | - field_method::encode(method)) {} - - bool registered() const { - return field_registered::decode(_entry); - } - - bool unregistered() const { - return field_unregistered::decode(_entry); - } - - nmethod* method() const { - return field_method::decode(_entry); - } -}; - -#endif // SHARE_GC_X_XNMETHODTABLEENTRY_HPP diff --git a/src/hotspot/share/gc/x/xNMethodTableIteration.cpp b/src/hotspot/share/gc/x/xNMethodTableIteration.cpp deleted file mode 100644 index c9248e6342021..0000000000000 --- a/src/hotspot/share/gc/x/xNMethodTableIteration.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2017, 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. - */ - -#include "precompiled.hpp" -#include "gc/x/xNMethodTableEntry.hpp" -#include "gc/x/xNMethodTableIteration.hpp" -#include "memory/iterator.hpp" -#include "runtime/atomic.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" - -XNMethodTableIteration::XNMethodTableIteration() : - _table(nullptr), - _size(0), - _claimed(0) {} - -bool XNMethodTableIteration::in_progress() const { - return _table != nullptr; -} - -void XNMethodTableIteration::nmethods_do_begin(XNMethodTableEntry* table, size_t size) { - assert(!in_progress(), "precondition"); - - _table = table; - _size = size; - _claimed = 0; -} - -void XNMethodTableIteration::nmethods_do_end() { - assert(_claimed >= _size, "Failed to claim all table entries"); - - // Finish iteration - _table = nullptr; -} - -void XNMethodTableIteration::nmethods_do(NMethodClosure* cl) { - for (;;) { - // Claim table partition. Each partition is currently sized to span - // two cache lines. This number is just a guess, but seems to work well. - const size_t partition_size = (XCacheLineSize * 2) / sizeof(XNMethodTableEntry); - const size_t partition_start = MIN2(Atomic::fetch_then_add(&_claimed, partition_size), _size); - const size_t partition_end = MIN2(partition_start + partition_size, _size); - if (partition_start == partition_end) { - // End of table - break; - } - - // Process table partition - for (size_t i = partition_start; i < partition_end; i++) { - const XNMethodTableEntry entry = _table[i]; - if (entry.registered()) { - cl->do_nmethod(entry.method()); - } - } - } -} diff --git a/src/hotspot/share/gc/x/xNMethodTableIteration.hpp b/src/hotspot/share/gc/x/xNMethodTableIteration.hpp deleted file mode 100644 index 1677b334490fc..0000000000000 --- a/src/hotspot/share/gc/x/xNMethodTableIteration.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 - * 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_GC_X_XNMETHODTABLEITERATION_HPP -#define SHARE_GC_X_XNMETHODTABLEITERATION_HPP - -#include "gc/x/xGlobals.hpp" - -class NMethodClosure; -class XNMethodTableEntry; - -class XNMethodTableIteration { -private: - XNMethodTableEntry* _table; - size_t _size; - XCACHE_ALIGNED volatile size_t _claimed; - -public: - XNMethodTableIteration(); - - bool in_progress() const; - - void nmethods_do_begin(XNMethodTableEntry* table, size_t size); - void nmethods_do_end(); - void nmethods_do(NMethodClosure* cl); -}; - -#endif // SHARE_GC_X_XNMETHODTABLEITERATION_HPP diff --git a/src/hotspot/share/gc/x/xNUMA.cpp b/src/hotspot/share/gc/x/xNUMA.cpp deleted file mode 100644 index fb99878b200d2..0000000000000 --- a/src/hotspot/share/gc/x/xNUMA.cpp +++ /dev/null @@ -1,41 +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. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xNUMA.hpp" - -bool XNUMA::_enabled; - -void XNUMA::initialize() { - pd_initialize(); - - log_info_p(gc, init)("NUMA Support: %s", to_string()); - if (_enabled) { - log_info_p(gc, init)("NUMA Nodes: %u", count()); - } -} - -const char* XNUMA::to_string() { - return _enabled ? "Enabled" : "Disabled"; -} diff --git a/src/hotspot/share/gc/x/xNUMA.inline.hpp b/src/hotspot/share/gc/x/xNUMA.inline.hpp deleted file mode 100644 index 17f5b831a31e8..0000000000000 --- a/src/hotspot/share/gc/x/xNUMA.inline.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XNUMA_INLINE_HPP -#define SHARE_GC_X_XNUMA_INLINE_HPP - -#include "gc/x/xNUMA.hpp" - -inline bool XNUMA::is_enabled() { - return _enabled; -} - -#endif // SHARE_GC_X_XNUMA_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xObjArrayAllocator.cpp b/src/hotspot/share/gc/x/xObjArrayAllocator.cpp deleted file mode 100644 index 0950b886a9b7b..0000000000000 --- a/src/hotspot/share/gc/x/xObjArrayAllocator.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "gc/x/xObjArrayAllocator.hpp" -#include "gc/x/xUtils.inline.hpp" -#include "oops/arrayKlass.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "utilities/debug.hpp" - -XObjArrayAllocator::XObjArrayAllocator(Klass* klass, size_t word_size, int length, bool do_zero, Thread* thread) : - ObjArrayAllocator(klass, word_size, length, do_zero, thread) {} - -void XObjArrayAllocator::yield_for_safepoint() const { - ThreadBlockInVM tbivm(JavaThread::cast(_thread)); -} - -oop XObjArrayAllocator::initialize(HeapWord* mem) const { - // ZGC specializes the initialization by performing segmented clearing - // to allow shorter time-to-safepoints. - - if (!_do_zero) { - // No need for ZGC specialization - return ObjArrayAllocator::initialize(mem); - } - - // A max segment size of 64K was chosen because microbenchmarking - // suggested that it offered a good trade-off between allocation - // time and time-to-safepoint - const size_t segment_max = XUtils::bytes_to_words(64 * K); - const BasicType element_type = ArrayKlass::cast(_klass)->element_type(); - - // Clear leading 32 bits, if necessary. - int base_offset = arrayOopDesc::base_offset_in_bytes(element_type); - if (!is_aligned(base_offset, HeapWordSize)) { - assert(is_aligned(base_offset, BytesPerInt), "array base must be 32 bit aligned"); - *reinterpret_cast(reinterpret_cast(mem) + base_offset) = 0; - base_offset += BytesPerInt; - } - assert(is_aligned(base_offset, HeapWordSize), "remaining array base must be 64 bit aligned"); - - const size_t header = heap_word_size(base_offset); - const size_t payload_size = _word_size - header; - - if (payload_size <= segment_max) { - // To small to use segmented clearing - return ObjArrayAllocator::initialize(mem); - } - - // Segmented clearing - - // The array is going to be exposed before it has been completely - // cleared, therefore we can't expose the header at the end of this - // function. Instead explicitly initialize it according to our needs. - arrayOopDesc::set_mark(mem, markWord::prototype()); - arrayOopDesc::release_set_klass(mem, _klass); - assert(_length >= 0, "length should be non-negative"); - arrayOopDesc::set_length(mem, _length); - - // Keep the array alive across safepoints through an invisible - // root. Invisible roots are not visited by the heap itarator - // and the marking logic will not attempt to follow its elements. - // Relocation knows how to dodge iterating over such objects. - XThreadLocalData::set_invisible_root(_thread, (oop*)&mem); - - for (size_t processed = 0; processed < payload_size; processed += segment_max) { - // Calculate segment - HeapWord* const start = (HeapWord*)(mem + header + processed); - const size_t remaining = payload_size - processed; - const size_t segment_size = MIN2(remaining, segment_max); - - // Clear segment - Copy::zero_to_words(start, segment_size); - - // Safepoint - yield_for_safepoint(); - } - - XThreadLocalData::clear_invisible_root(_thread); - - return cast_to_oop(mem); -} diff --git a/src/hotspot/share/gc/x/xObjArrayAllocator.hpp b/src/hotspot/share/gc/x/xObjArrayAllocator.hpp deleted file mode 100644 index 4a084da3279b3..0000000000000 --- a/src/hotspot/share/gc/x/xObjArrayAllocator.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 - * 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_GC_X_XOBJARRAYALLOCATOR_HPP -#define SHARE_GC_X_XOBJARRAYALLOCATOR_HPP - -#include "gc/shared/memAllocator.hpp" - -class XObjArrayAllocator : public ObjArrayAllocator { -private: - virtual oop initialize(HeapWord* mem) const override; - - void yield_for_safepoint() const; - -public: - XObjArrayAllocator(Klass* klass, size_t word_size, int length, bool do_zero, Thread* thread); -}; - -#endif // SHARE_GC_X_XOBJARRAYALLOCATOR_HPP diff --git a/src/hotspot/share/gc/x/xObjectAllocator.cpp b/src/hotspot/share/gc/x/xObjectAllocator.cpp deleted file mode 100644 index 26981ce913175..0000000000000 --- a/src/hotspot/share/gc/x/xObjectAllocator.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xHeuristics.hpp" -#include "gc/x/xObjectAllocator.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xPageTable.inline.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xThread.inline.hpp" -#include "gc/x/xValue.inline.hpp" -#include "logging/log.hpp" -#include "runtime/atomic.hpp" -#include "runtime/safepoint.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" - -static const XStatCounter XCounterUndoObjectAllocationSucceeded("Memory", "Undo Object Allocation Succeeded", XStatUnitOpsPerSecond); -static const XStatCounter XCounterUndoObjectAllocationFailed("Memory", "Undo Object Allocation Failed", XStatUnitOpsPerSecond); - -XObjectAllocator::XObjectAllocator() : - _use_per_cpu_shared_small_pages(XHeuristics::use_per_cpu_shared_small_pages()), - _used(0), - _undone(0), - _alloc_for_relocation(0), - _undo_alloc_for_relocation(0), - _shared_medium_page(nullptr), - _shared_small_page(nullptr) {} - -XPage** XObjectAllocator::shared_small_page_addr() { - return _use_per_cpu_shared_small_pages ? _shared_small_page.addr() : _shared_small_page.addr(0); -} - -XPage* const* XObjectAllocator::shared_small_page_addr() const { - return _use_per_cpu_shared_small_pages ? _shared_small_page.addr() : _shared_small_page.addr(0); -} - -void XObjectAllocator::register_alloc_for_relocation(const XPageTable* page_table, uintptr_t addr, size_t size) { - const XPage* const page = page_table->get(addr); - const size_t aligned_size = align_up(size, page->object_alignment()); - Atomic::add(_alloc_for_relocation.addr(), aligned_size); -} - -void XObjectAllocator::register_undo_alloc_for_relocation(const XPage* page, size_t size) { - const size_t aligned_size = align_up(size, page->object_alignment()); - Atomic::add(_undo_alloc_for_relocation.addr(), aligned_size); -} - -XPage* XObjectAllocator::alloc_page(uint8_t type, size_t size, XAllocationFlags flags) { - XPage* const page = XHeap::heap()->alloc_page(type, size, flags); - if (page != nullptr) { - // Increment used bytes - Atomic::add(_used.addr(), size); - } - - return page; -} - -void XObjectAllocator::undo_alloc_page(XPage* page) { - // Increment undone bytes - Atomic::add(_undone.addr(), page->size()); - - XHeap::heap()->undo_alloc_page(page); -} - -uintptr_t XObjectAllocator::alloc_object_in_shared_page(XPage** shared_page, - uint8_t page_type, - size_t page_size, - size_t size, - XAllocationFlags flags) { - uintptr_t addr = 0; - XPage* page = Atomic::load_acquire(shared_page); - - if (page != nullptr) { - addr = page->alloc_object_atomic(size); - } - - if (addr == 0) { - // Allocate new page - XPage* const new_page = alloc_page(page_type, page_size, flags); - if (new_page != nullptr) { - // Allocate object before installing the new page - addr = new_page->alloc_object(size); - - retry: - // Install new page - XPage* const prev_page = Atomic::cmpxchg(shared_page, page, new_page); - if (prev_page != page) { - if (prev_page == nullptr) { - // Previous page was retired, retry installing the new page - page = prev_page; - goto retry; - } - - // Another page already installed, try allocation there first - const uintptr_t prev_addr = prev_page->alloc_object_atomic(size); - if (prev_addr == 0) { - // Allocation failed, retry installing the new page - page = prev_page; - goto retry; - } - - // Allocation succeeded in already installed page - addr = prev_addr; - - // Undo new page allocation - undo_alloc_page(new_page); - } - } - } - - return addr; -} - -uintptr_t XObjectAllocator::alloc_large_object(size_t size, XAllocationFlags flags) { - uintptr_t addr = 0; - - // Allocate new large page - const size_t page_size = align_up(size, XGranuleSize); - XPage* const page = alloc_page(XPageTypeLarge, page_size, flags); - if (page != nullptr) { - // Allocate the object - addr = page->alloc_object(size); - } - - return addr; -} - -uintptr_t XObjectAllocator::alloc_medium_object(size_t size, XAllocationFlags flags) { - return alloc_object_in_shared_page(_shared_medium_page.addr(), XPageTypeMedium, XPageSizeMedium, size, flags); -} - -uintptr_t XObjectAllocator::alloc_small_object(size_t size, XAllocationFlags flags) { - return alloc_object_in_shared_page(shared_small_page_addr(), XPageTypeSmall, XPageSizeSmall, size, flags); -} - -uintptr_t XObjectAllocator::alloc_object(size_t size, XAllocationFlags flags) { - if (size <= XObjectSizeLimitSmall) { - // Small - return alloc_small_object(size, flags); - } else if (size <= XObjectSizeLimitMedium) { - // Medium - return alloc_medium_object(size, flags); - } else { - // Large - return alloc_large_object(size, flags); - } -} - -uintptr_t XObjectAllocator::alloc_object(size_t size) { - XAllocationFlags flags; - return alloc_object(size, flags); -} - -uintptr_t XObjectAllocator::alloc_object_for_relocation(const XPageTable* page_table, size_t size) { - XAllocationFlags flags; - flags.set_non_blocking(); - - const uintptr_t addr = alloc_object(size, flags); - if (addr != 0) { - register_alloc_for_relocation(page_table, addr, size); - } - - return addr; -} - -void XObjectAllocator::undo_alloc_object_for_relocation(XPage* page, uintptr_t addr, size_t size) { - const uint8_t type = page->type(); - - if (type == XPageTypeLarge) { - register_undo_alloc_for_relocation(page, size); - undo_alloc_page(page); - XStatInc(XCounterUndoObjectAllocationSucceeded); - } else { - if (page->undo_alloc_object_atomic(addr, size)) { - register_undo_alloc_for_relocation(page, size); - XStatInc(XCounterUndoObjectAllocationSucceeded); - } else { - XStatInc(XCounterUndoObjectAllocationFailed); - } - } -} - -size_t XObjectAllocator::used() const { - size_t total_used = 0; - size_t total_undone = 0; - - XPerCPUConstIterator iter_used(&_used); - for (const size_t* cpu_used; iter_used.next(&cpu_used);) { - total_used += *cpu_used; - } - - XPerCPUConstIterator iter_undone(&_undone); - for (const size_t* cpu_undone; iter_undone.next(&cpu_undone);) { - total_undone += *cpu_undone; - } - - return total_used - total_undone; -} - -size_t XObjectAllocator::remaining() const { - assert(XThread::is_java(), "Should be a Java thread"); - - const XPage* const page = Atomic::load_acquire(shared_small_page_addr()); - if (page != nullptr) { - return page->remaining(); - } - - return 0; -} - -size_t XObjectAllocator::relocated() const { - size_t total_alloc = 0; - size_t total_undo_alloc = 0; - - XPerCPUConstIterator iter_alloc(&_alloc_for_relocation); - for (const size_t* alloc; iter_alloc.next(&alloc);) { - total_alloc += Atomic::load(alloc); - } - - XPerCPUConstIterator iter_undo_alloc(&_undo_alloc_for_relocation); - for (const size_t* undo_alloc; iter_undo_alloc.next(&undo_alloc);) { - total_undo_alloc += Atomic::load(undo_alloc); - } - - assert(total_alloc >= total_undo_alloc, "Mismatch"); - - return total_alloc - total_undo_alloc; -} - -void XObjectAllocator::retire_pages() { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - - // Reset used and undone bytes - _used.set_all(0); - _undone.set_all(0); - - // Reset relocated bytes - _alloc_for_relocation.set_all(0); - _undo_alloc_for_relocation.set_all(0); - - // Reset allocation pages - _shared_medium_page.set(nullptr); - _shared_small_page.set_all(nullptr); -} diff --git a/src/hotspot/share/gc/x/xObjectAllocator.hpp b/src/hotspot/share/gc/x/xObjectAllocator.hpp deleted file mode 100644 index 8880c41f3d598..0000000000000 --- a/src/hotspot/share/gc/x/xObjectAllocator.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XOBJECTALLOCATOR_HPP -#define SHARE_GC_X_XOBJECTALLOCATOR_HPP - -#include "gc/x/xAllocationFlags.hpp" -#include "gc/x/xValue.hpp" - -class XPage; -class XPageTable; - -class XObjectAllocator { -private: - const bool _use_per_cpu_shared_small_pages; - XPerCPU _used; - XPerCPU _undone; - XPerCPU _alloc_for_relocation; - XPerCPU _undo_alloc_for_relocation; - XContended _shared_medium_page; - XPerCPU _shared_small_page; - - XPage** shared_small_page_addr(); - XPage* const* shared_small_page_addr() const; - - void register_alloc_for_relocation(const XPageTable* page_table, uintptr_t addr, size_t size); - void register_undo_alloc_for_relocation(const XPage* page, size_t size); - - XPage* alloc_page(uint8_t type, size_t size, XAllocationFlags flags); - void undo_alloc_page(XPage* page); - - // Allocate an object in a shared page. Allocate and - // atomically install a new page if necessary. - uintptr_t alloc_object_in_shared_page(XPage** shared_page, - uint8_t page_type, - size_t page_size, - size_t size, - XAllocationFlags flags); - - uintptr_t alloc_large_object(size_t size, XAllocationFlags flags); - uintptr_t alloc_medium_object(size_t size, XAllocationFlags flags); - uintptr_t alloc_small_object(size_t size, XAllocationFlags flags); - uintptr_t alloc_object(size_t size, XAllocationFlags flags); - -public: - XObjectAllocator(); - - uintptr_t alloc_object(size_t size); - uintptr_t alloc_object_for_relocation(const XPageTable* page_table, size_t size); - void undo_alloc_object_for_relocation(XPage* page, uintptr_t addr, size_t size); - - size_t used() const; - size_t remaining() const; - size_t relocated() const; - - void retire_pages(); -}; - -#endif // SHARE_GC_X_XOBJECTALLOCATOR_HPP diff --git a/src/hotspot/share/gc/x/xOop.hpp b/src/hotspot/share/gc/x/xOop.hpp deleted file mode 100644 index 92cc7a225fe6b..0000000000000 --- a/src/hotspot/share/gc/x/xOop.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XOOP_HPP -#define SHARE_GC_X_XOOP_HPP - -#include "memory/allStatic.hpp" -#include "oops/oopsHierarchy.hpp" - -class XOop : public AllStatic { -public: - static oop from_address(uintptr_t addr); - static uintptr_t to_address(oop o); -}; - -#endif // SHARE_GC_X_XOOP_HPP diff --git a/src/hotspot/share/gc/x/xOop.inline.hpp b/src/hotspot/share/gc/x/xOop.inline.hpp deleted file mode 100644 index 933987577d113..0000000000000 --- a/src/hotspot/share/gc/x/xOop.inline.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2016, 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 - * 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_GC_X_XOOP_INLINE_HPP -#define SHARE_GC_X_XOOP_INLINE_HPP - -#include "gc/x/xOop.hpp" - -inline oop XOop::from_address(uintptr_t addr) { - return cast_to_oop(addr); -} - -inline uintptr_t XOop::to_address(oop o) { - return cast_from_oop(o); -} - -#endif // SHARE_GC_X_XOOP_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xPage.cpp b/src/hotspot/share/gc/x/xPage.cpp deleted file mode 100644 index b48500ab96e38..0000000000000 --- a/src/hotspot/share/gc/x/xPage.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -#include "precompiled.hpp" -#include "gc/x/xList.inline.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xPhysicalMemory.inline.hpp" -#include "gc/x/xVirtualMemory.inline.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" - -XPage::XPage(const XVirtualMemory& vmem, const XPhysicalMemory& pmem) : - XPage(type_from_size(vmem.size()), vmem, pmem) {} - -XPage::XPage(uint8_t type, const XVirtualMemory& vmem, const XPhysicalMemory& pmem) : - _type(type), - _numa_id((uint8_t)-1), - _seqnum(0), - _virtual(vmem), - _top(start()), - _livemap(object_max_count()), - _last_used(0), - _physical(pmem), - _node() { - assert_initialized(); -} - -XPage::~XPage() {} - -void XPage::assert_initialized() const { - assert(!_virtual.is_null(), "Should not be null"); - assert(!_physical.is_null(), "Should not be null"); - assert(_virtual.size() == _physical.size(), "Virtual/Physical size mismatch"); - assert((_type == XPageTypeSmall && size() == XPageSizeSmall) || - (_type == XPageTypeMedium && size() == XPageSizeMedium) || - (_type == XPageTypeLarge && is_aligned(size(), XGranuleSize)), - "Page type/size mismatch"); -} - -void XPage::reset() { - _seqnum = XGlobalSeqNum; - _top = start(); - _livemap.reset(); - _last_used = 0; -} - -void XPage::reset_for_in_place_relocation() { - _seqnum = XGlobalSeqNum; - _top = start(); -} - -XPage* XPage::retype(uint8_t type) { - assert(_type != type, "Invalid retype"); - _type = type; - _livemap.resize(object_max_count()); - return this; -} - -XPage* XPage::split(size_t size) { - return split(type_from_size(size), size); -} - -XPage* XPage::split(uint8_t type, size_t size) { - assert(_virtual.size() > size, "Invalid split"); - - // Resize this page, keep _numa_id, _seqnum, and _last_used - const XVirtualMemory vmem = _virtual.split(size); - const XPhysicalMemory pmem = _physical.split(size); - _type = type_from_size(_virtual.size()); - _top = start(); - _livemap.resize(object_max_count()); - - // Create new page, inherit _seqnum and _last_used - XPage* const page = new XPage(type, vmem, pmem); - page->_seqnum = _seqnum; - page->_last_used = _last_used; - return page; -} - -XPage* XPage::split_committed() { - // Split any committed part of this page into a separate page, - // leaving this page with only uncommitted physical memory. - const XPhysicalMemory pmem = _physical.split_committed(); - if (pmem.is_null()) { - // Nothing committed - return nullptr; - } - - assert(!_physical.is_null(), "Should not be null"); - - // Resize this page - const XVirtualMemory vmem = _virtual.split(pmem.size()); - _type = type_from_size(_virtual.size()); - _top = start(); - _livemap.resize(object_max_count()); - - // Create new page - return new XPage(vmem, pmem); -} - -void XPage::print_on(outputStream* out) const { - out->print_cr(" %-6s " PTR_FORMAT " " PTR_FORMAT " " PTR_FORMAT " %s%s", - type_to_string(), start(), top(), end(), - is_allocating() ? " Allocating" : "", - is_relocatable() ? " Relocatable" : ""); -} - -void XPage::print() const { - print_on(tty); -} - -void XPage::verify_live(uint32_t live_objects, size_t live_bytes) const { - guarantee(live_objects == _livemap.live_objects(), "Invalid number of live objects"); - guarantee(live_bytes == _livemap.live_bytes(), "Invalid number of live bytes"); -} diff --git a/src/hotspot/share/gc/x/xPage.hpp b/src/hotspot/share/gc/x/xPage.hpp deleted file mode 100644 index c1040e034bd1c..0000000000000 --- a/src/hotspot/share/gc/x/xPage.hpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XPAGE_HPP -#define SHARE_GC_X_XPAGE_HPP - -#include "gc/x/xList.hpp" -#include "gc/x/xLiveMap.hpp" -#include "gc/x/xPhysicalMemory.hpp" -#include "gc/x/xVirtualMemory.hpp" -#include "memory/allocation.hpp" - -class VMStructs; - -class XPage : public CHeapObj { - friend class ::VMStructs; - friend class XList; - -private: - uint8_t _type; - uint8_t _numa_id; - uint32_t _seqnum; - XVirtualMemory _virtual; - volatile uintptr_t _top; - XLiveMap _livemap; - uint64_t _last_used; - XPhysicalMemory _physical; - XListNode _node; - - void assert_initialized() const; - - uint8_t type_from_size(size_t size) const; - const char* type_to_string() const; - - bool is_object_marked(uintptr_t addr) const; - bool is_object_strongly_marked(uintptr_t addr) const; - -public: - XPage(const XVirtualMemory& vmem, const XPhysicalMemory& pmem); - XPage(uint8_t type, const XVirtualMemory& vmem, const XPhysicalMemory& pmem); - ~XPage(); - - uint32_t object_max_count() const; - size_t object_alignment_shift() const; - size_t object_alignment() const; - - uint8_t type() const; - uintptr_t start() const; - uintptr_t end() const; - size_t size() const; - uintptr_t top() const; - size_t remaining() const; - - const XVirtualMemory& virtual_memory() const; - const XPhysicalMemory& physical_memory() const; - XPhysicalMemory& physical_memory(); - - uint8_t numa_id(); - - bool is_allocating() const; - bool is_relocatable() const; - - uint64_t last_used() const; - void set_last_used(); - - void reset(); - void reset_for_in_place_relocation(); - - XPage* retype(uint8_t type); - XPage* split(size_t size); - XPage* split(uint8_t type, size_t size); - XPage* split_committed(); - - bool is_in(uintptr_t addr) const; - - bool is_marked() const; - template bool is_object_marked(uintptr_t addr) const; - bool is_object_live(uintptr_t addr) const; - bool is_object_strongly_live(uintptr_t addr) const; - bool mark_object(uintptr_t addr, bool finalizable, bool& inc_live); - - void inc_live(uint32_t objects, size_t bytes); - uint32_t live_objects() const; - size_t live_bytes() const; - - void object_iterate(ObjectClosure* cl); - - uintptr_t alloc_object(size_t size); - uintptr_t alloc_object_atomic(size_t size); - - bool undo_alloc_object(uintptr_t addr, size_t size); - bool undo_alloc_object_atomic(uintptr_t addr, size_t size); - - void print_on(outputStream* out) const; - void print() const; - - void verify_live(uint32_t live_objects, size_t live_bytes) const; -}; - -class XPageClosure { -public: - virtual void do_page(const XPage* page) = 0; -}; - -#endif // SHARE_GC_X_XPAGE_HPP diff --git a/src/hotspot/share/gc/x/xPage.inline.hpp b/src/hotspot/share/gc/x/xPage.inline.hpp deleted file mode 100644 index d9b0fd2039dc1..0000000000000 --- a/src/hotspot/share/gc/x/xPage.inline.hpp +++ /dev/null @@ -1,313 +0,0 @@ -/* - * 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 - * 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_GC_X_XPAGE_INLINE_HPP -#define SHARE_GC_X_XPAGE_INLINE_HPP - -#include "gc/x/xPage.hpp" - -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xLiveMap.inline.hpp" -#include "gc/x/xNUMA.hpp" -#include "gc/x/xPhysicalMemory.inline.hpp" -#include "gc/x/xVirtualMemory.inline.hpp" -#include "runtime/atomic.hpp" -#include "runtime/os.hpp" -#include "utilities/align.hpp" -#include "utilities/checkedCast.hpp" -#include "utilities/debug.hpp" - -inline uint8_t XPage::type_from_size(size_t size) const { - if (size == XPageSizeSmall) { - return XPageTypeSmall; - } else if (size == XPageSizeMedium) { - return XPageTypeMedium; - } else { - return XPageTypeLarge; - } -} - -inline const char* XPage::type_to_string() const { - switch (type()) { - case XPageTypeSmall: - return "Small"; - - case XPageTypeMedium: - return "Medium"; - - default: - assert(type() == XPageTypeLarge, "Invalid page type"); - return "Large"; - } -} - -inline uint32_t XPage::object_max_count() const { - switch (type()) { - case XPageTypeLarge: - // A large page can only contain a single - // object aligned to the start of the page. - return 1; - - default: - return (uint32_t)(size() >> object_alignment_shift()); - } -} - -inline size_t XPage::object_alignment_shift() const { - switch (type()) { - case XPageTypeSmall: - return XObjectAlignmentSmallShift; - - case XPageTypeMedium: - return XObjectAlignmentMediumShift; - - default: - assert(type() == XPageTypeLarge, "Invalid page type"); - return XObjectAlignmentLargeShift; - } -} - -inline size_t XPage::object_alignment() const { - switch (type()) { - case XPageTypeSmall: - return XObjectAlignmentSmall; - - case XPageTypeMedium: - return XObjectAlignmentMedium; - - default: - assert(type() == XPageTypeLarge, "Invalid page type"); - return XObjectAlignmentLarge; - } -} - -inline uint8_t XPage::type() const { - return _type; -} - -inline uintptr_t XPage::start() const { - return _virtual.start(); -} - -inline uintptr_t XPage::end() const { - return _virtual.end(); -} - -inline size_t XPage::size() const { - return _virtual.size(); -} - -inline uintptr_t XPage::top() const { - return _top; -} - -inline size_t XPage::remaining() const { - return end() - top(); -} - -inline const XVirtualMemory& XPage::virtual_memory() const { - return _virtual; -} - -inline const XPhysicalMemory& XPage::physical_memory() const { - return _physical; -} - -inline XPhysicalMemory& XPage::physical_memory() { - return _physical; -} - -inline uint8_t XPage::numa_id() { - if (_numa_id == (uint8_t)-1) { - _numa_id = checked_cast(XNUMA::memory_id(XAddress::good(start()))); - } - - return _numa_id; -} - -inline bool XPage::is_allocating() const { - return _seqnum == XGlobalSeqNum; -} - -inline bool XPage::is_relocatable() const { - return _seqnum < XGlobalSeqNum; -} - -inline uint64_t XPage::last_used() const { - return _last_used; -} - -inline void XPage::set_last_used() { - _last_used = (uint64_t)ceil(os::elapsedTime()); -} - -inline bool XPage::is_in(uintptr_t addr) const { - const uintptr_t offset = XAddress::offset(addr); - return offset >= start() && offset < top(); -} - -inline bool XPage::is_marked() const { - assert(is_relocatable(), "Invalid page state"); - return _livemap.is_marked(); -} - -inline bool XPage::is_object_marked(uintptr_t addr) const { - assert(is_relocatable(), "Invalid page state"); - const size_t index = ((XAddress::offset(addr) - start()) >> object_alignment_shift()) * 2; - return _livemap.get(index); -} - -inline bool XPage::is_object_strongly_marked(uintptr_t addr) const { - assert(is_relocatable(), "Invalid page state"); - const size_t index = ((XAddress::offset(addr) - start()) >> object_alignment_shift()) * 2; - return _livemap.get(index + 1); -} - -template -inline bool XPage::is_object_marked(uintptr_t addr) const { - return finalizable ? is_object_marked(addr) : is_object_strongly_marked(addr); -} - -inline bool XPage::is_object_live(uintptr_t addr) const { - return is_allocating() || is_object_marked(addr); -} - -inline bool XPage::is_object_strongly_live(uintptr_t addr) const { - return is_allocating() || is_object_strongly_marked(addr); -} - -inline bool XPage::mark_object(uintptr_t addr, bool finalizable, bool& inc_live) { - assert(XAddress::is_marked(addr), "Invalid address"); - assert(is_relocatable(), "Invalid page state"); - assert(is_in(addr), "Invalid address"); - - // Set mark bit - const size_t index = ((XAddress::offset(addr) - start()) >> object_alignment_shift()) * 2; - return _livemap.set(index, finalizable, inc_live); -} - -inline void XPage::inc_live(uint32_t objects, size_t bytes) { - _livemap.inc_live(objects, bytes); -} - -inline uint32_t XPage::live_objects() const { - assert(is_marked(), "Should be marked"); - return _livemap.live_objects(); -} - -inline size_t XPage::live_bytes() const { - assert(is_marked(), "Should be marked"); - return _livemap.live_bytes(); -} - -inline void XPage::object_iterate(ObjectClosure* cl) { - _livemap.iterate(cl, XAddress::good(start()), object_alignment_shift()); -} - -inline uintptr_t XPage::alloc_object(size_t size) { - assert(is_allocating(), "Invalid state"); - - const size_t aligned_size = align_up(size, object_alignment()); - const uintptr_t addr = top(); - const uintptr_t new_top = addr + aligned_size; - - if (new_top > end()) { - // Not enough space left - return 0; - } - - _top = new_top; - - return XAddress::good(addr); -} - -inline uintptr_t XPage::alloc_object_atomic(size_t size) { - assert(is_allocating(), "Invalid state"); - - const size_t aligned_size = align_up(size, object_alignment()); - uintptr_t addr = top(); - - for (;;) { - const uintptr_t new_top = addr + aligned_size; - if (new_top > end()) { - // Not enough space left - return 0; - } - - const uintptr_t prev_top = Atomic::cmpxchg(&_top, addr, new_top); - if (prev_top == addr) { - // Success - return XAddress::good(addr); - } - - // Retry - addr = prev_top; - } -} - -inline bool XPage::undo_alloc_object(uintptr_t addr, size_t size) { - assert(is_allocating(), "Invalid state"); - - const uintptr_t offset = XAddress::offset(addr); - const size_t aligned_size = align_up(size, object_alignment()); - const uintptr_t old_top = top(); - const uintptr_t new_top = old_top - aligned_size; - - if (new_top != offset) { - // Failed to undo allocation, not the last allocated object - return false; - } - - _top = new_top; - - // Success - return true; -} - -inline bool XPage::undo_alloc_object_atomic(uintptr_t addr, size_t size) { - assert(is_allocating(), "Invalid state"); - - const uintptr_t offset = XAddress::offset(addr); - const size_t aligned_size = align_up(size, object_alignment()); - uintptr_t old_top = top(); - - for (;;) { - const uintptr_t new_top = old_top - aligned_size; - if (new_top != offset) { - // Failed to undo allocation, not the last allocated object - return false; - } - - const uintptr_t prev_top = Atomic::cmpxchg(&_top, old_top, new_top); - if (prev_top == old_top) { - // Success - return true; - } - - // Retry - old_top = prev_top; - } -} - -#endif // SHARE_GC_X_XPAGE_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xPageAllocator.cpp b/src/hotspot/share/gc/x/xPageAllocator.cpp deleted file mode 100644 index ccc715682c0cb..0000000000000 --- a/src/hotspot/share/gc/x/xPageAllocator.cpp +++ /dev/null @@ -1,870 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/shared/suspendibleThreadSet.hpp" -#include "gc/x/xArray.inline.hpp" -#include "gc/x/xCollectedHeap.hpp" -#include "gc/x/xFuture.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xPageAllocator.inline.hpp" -#include "gc/x/xPageCache.hpp" -#include "gc/x/xSafeDelete.inline.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xUncommitter.hpp" -#include "gc/x/xUnmapper.hpp" -#include "gc/x/xWorkers.hpp" -#include "jfr/jfrEvents.hpp" -#include "logging/log.hpp" -#include "runtime/globals.hpp" -#include "runtime/init.hpp" -#include "runtime/java.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" - -static const XStatCounter XCounterAllocationRate("Memory", "Allocation Rate", XStatUnitBytesPerSecond); -static const XStatCounter XCounterPageCacheFlush("Memory", "Page Cache Flush", XStatUnitBytesPerSecond); -static const XStatCounter XCounterDefragment("Memory", "Defragment", XStatUnitOpsPerSecond); -static const XStatCriticalPhase XCriticalPhaseAllocationStall("Allocation Stall"); - -enum XPageAllocationStall { - XPageAllocationStallSuccess, - XPageAllocationStallFailed, - XPageAllocationStallStartGC -}; - -class XPageAllocation : public StackObj { - friend class XList; - -private: - const uint8_t _type; - const size_t _size; - const XAllocationFlags _flags; - const uint32_t _seqnum; - size_t _flushed; - size_t _committed; - XList _pages; - XListNode _node; - XFuture _stall_result; - -public: - XPageAllocation(uint8_t type, size_t size, XAllocationFlags flags) : - _type(type), - _size(size), - _flags(flags), - _seqnum(XGlobalSeqNum), - _flushed(0), - _committed(0), - _pages(), - _node(), - _stall_result() {} - - uint8_t type() const { - return _type; - } - - size_t size() const { - return _size; - } - - XAllocationFlags flags() const { - return _flags; - } - - uint32_t seqnum() const { - return _seqnum; - } - - size_t flushed() const { - return _flushed; - } - - void set_flushed(size_t flushed) { - _flushed = flushed; - } - - size_t committed() const { - return _committed; - } - - void set_committed(size_t committed) { - _committed = committed; - } - - XPageAllocationStall wait() { - return _stall_result.get(); - } - - XList* pages() { - return &_pages; - } - - void satisfy(XPageAllocationStall result) { - _stall_result.set(result); - } -}; - -XPageAllocator::XPageAllocator(XWorkers* workers, - size_t min_capacity, - size_t initial_capacity, - size_t max_capacity) : - _lock(), - _cache(), - _virtual(max_capacity), - _physical(max_capacity), - _min_capacity(min_capacity), - _max_capacity(max_capacity), - _current_max_capacity(max_capacity), - _capacity(0), - _claimed(0), - _used(0), - _used_high(0), - _used_low(0), - _reclaimed(0), - _stalled(), - _nstalled(0), - _satisfied(), - _unmapper(new XUnmapper(this)), - _uncommitter(new XUncommitter(this)), - _safe_delete(), - _initialized(false) { - - if (!_virtual.is_initialized() || !_physical.is_initialized()) { - return; - } - - log_info_p(gc, init)("Min Capacity: " SIZE_FORMAT "M", min_capacity / M); - log_info_p(gc, init)("Initial Capacity: " SIZE_FORMAT "M", initial_capacity / M); - log_info_p(gc, init)("Max Capacity: " SIZE_FORMAT "M", max_capacity / M); - if (XPageSizeMedium > 0) { - log_info_p(gc, init)("Medium Page Size: " SIZE_FORMAT "M", XPageSizeMedium / M); - } else { - log_info_p(gc, init)("Medium Page Size: N/A"); - } - log_info_p(gc, init)("Pre-touch: %s", AlwaysPreTouch ? "Enabled" : "Disabled"); - - // Warn if system limits could stop us from reaching max capacity - _physical.warn_commit_limits(max_capacity); - - // Check if uncommit should and can be enabled - _physical.try_enable_uncommit(min_capacity, max_capacity); - - // Pre-map initial capacity - if (!prime_cache(workers, initial_capacity)) { - log_error_p(gc)("Failed to allocate initial Java heap (" SIZE_FORMAT "M)", initial_capacity / M); - return; - } - - // Successfully initialized - _initialized = true; -} - -class XPreTouchTask : public XTask { -private: - const XPhysicalMemoryManager* const _physical; - volatile uintptr_t _start; - const uintptr_t _end; - -public: - XPreTouchTask(const XPhysicalMemoryManager* physical, uintptr_t start, uintptr_t end) : - XTask("XPreTouchTask"), - _physical(physical), - _start(start), - _end(end) {} - - virtual void work() { - for (;;) { - // Get granule offset - const size_t size = XGranuleSize; - const uintptr_t offset = Atomic::fetch_then_add(&_start, size); - if (offset >= _end) { - // Done - break; - } - - // Pre-touch granule - _physical->pretouch(offset, size); - } - } -}; - -bool XPageAllocator::prime_cache(XWorkers* workers, size_t size) { - XAllocationFlags flags; - - flags.set_non_blocking(); - flags.set_low_address(); - - XPage* const page = alloc_page(XPageTypeLarge, size, flags); - if (page == nullptr) { - return false; - } - - if (AlwaysPreTouch) { - // Pre-touch page - XPreTouchTask task(&_physical, page->start(), page->end()); - workers->run_all(&task); - } - - free_page(page, false /* reclaimed */); - - return true; -} - -bool XPageAllocator::is_initialized() const { - return _initialized; -} - -size_t XPageAllocator::min_capacity() const { - return _min_capacity; -} - -size_t XPageAllocator::max_capacity() const { - return _max_capacity; -} - -size_t XPageAllocator::soft_max_capacity() const { - // Note that SoftMaxHeapSize is a manageable flag - const size_t soft_max_capacity = Atomic::load(&SoftMaxHeapSize); - const size_t current_max_capacity = Atomic::load(&_current_max_capacity); - return MIN2(soft_max_capacity, current_max_capacity); -} - -size_t XPageAllocator::capacity() const { - return Atomic::load(&_capacity); -} - -size_t XPageAllocator::used() const { - return Atomic::load(&_used); -} - -size_t XPageAllocator::unused() const { - const ssize_t capacity = (ssize_t)Atomic::load(&_capacity); - const ssize_t used = (ssize_t)Atomic::load(&_used); - const ssize_t claimed = (ssize_t)Atomic::load(&_claimed); - const ssize_t unused = capacity - used - claimed; - return unused > 0 ? (size_t)unused : 0; -} - -XPageAllocatorStats XPageAllocator::stats() const { - XLocker locker(&_lock); - return XPageAllocatorStats(_min_capacity, - _max_capacity, - soft_max_capacity(), - _capacity, - _used, - _used_high, - _used_low, - _reclaimed); -} - -void XPageAllocator::reset_statistics() { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - _reclaimed = 0; - _used_high = _used_low = _used; - _nstalled = 0; -} - -size_t XPageAllocator::increase_capacity(size_t size) { - const size_t increased = MIN2(size, _current_max_capacity - _capacity); - - if (increased > 0) { - // Update atomically since we have concurrent readers - Atomic::add(&_capacity, increased); - - // Record time of last commit. When allocation, we prefer increasing - // the capacity over flushing the cache. That means there could be - // expired pages in the cache at this time. However, since we are - // increasing the capacity we are obviously in need of committed - // memory and should therefore not be uncommitting memory. - _cache.set_last_commit(); - } - - return increased; -} - -void XPageAllocator::decrease_capacity(size_t size, bool set_max_capacity) { - // Update atomically since we have concurrent readers - Atomic::sub(&_capacity, size); - - if (set_max_capacity) { - // Adjust current max capacity to avoid further attempts to increase capacity - log_error_p(gc)("Forced to lower max Java heap size from " - SIZE_FORMAT "M(%.0f%%) to " SIZE_FORMAT "M(%.0f%%)", - _current_max_capacity / M, percent_of(_current_max_capacity, _max_capacity), - _capacity / M, percent_of(_capacity, _max_capacity)); - - // Update atomically since we have concurrent readers - Atomic::store(&_current_max_capacity, _capacity); - } -} - -void XPageAllocator::increase_used(size_t size, bool worker_relocation) { - if (worker_relocation) { - // Allocating a page for the purpose of worker relocation has - // a negative contribution to the number of reclaimed bytes. - _reclaimed -= size; - } - - // Update atomically since we have concurrent readers - const size_t used = Atomic::add(&_used, size); - if (used > _used_high) { - _used_high = used; - } -} - -void XPageAllocator::decrease_used(size_t size, bool reclaimed) { - // Only pages explicitly released with the reclaimed flag set - // counts as reclaimed bytes. This flag is true when we release - // a page after relocation, and is false when we release a page - // to undo an allocation. - if (reclaimed) { - _reclaimed += size; - } - - // Update atomically since we have concurrent readers - const size_t used = Atomic::sub(&_used, size); - if (used < _used_low) { - _used_low = used; - } -} - -bool XPageAllocator::commit_page(XPage* page) { - // Commit physical memory - return _physical.commit(page->physical_memory()); -} - -void XPageAllocator::uncommit_page(XPage* page) { - if (!ZUncommit) { - return; - } - - // Uncommit physical memory - _physical.uncommit(page->physical_memory()); -} - -void XPageAllocator::map_page(const XPage* page) const { - // Map physical memory - _physical.map(page->start(), page->physical_memory()); -} - -void XPageAllocator::unmap_page(const XPage* page) const { - // Unmap physical memory - _physical.unmap(page->start(), page->size()); -} - -void XPageAllocator::destroy_page(XPage* page) { - // Free virtual memory - _virtual.free(page->virtual_memory()); - - // Free physical memory - _physical.free(page->physical_memory()); - - // Delete page safely - _safe_delete(page); -} - -bool XPageAllocator::is_alloc_allowed(size_t size) const { - const size_t available = _current_max_capacity - _used - _claimed; - return available >= size; -} - -bool XPageAllocator::alloc_page_common_inner(uint8_t type, size_t size, XList* pages) { - if (!is_alloc_allowed(size)) { - // Out of memory - return false; - } - - // Try allocate from the page cache - XPage* const page = _cache.alloc_page(type, size); - if (page != nullptr) { - // Success - pages->insert_last(page); - return true; - } - - // Try increase capacity - const size_t increased = increase_capacity(size); - if (increased < size) { - // Could not increase capacity enough to satisfy the allocation - // completely. Flush the page cache to satisfy the remainder. - const size_t remaining = size - increased; - _cache.flush_for_allocation(remaining, pages); - } - - // Success - return true; -} - -bool XPageAllocator::alloc_page_common(XPageAllocation* allocation) { - const uint8_t type = allocation->type(); - const size_t size = allocation->size(); - const XAllocationFlags flags = allocation->flags(); - XList* const pages = allocation->pages(); - - if (!alloc_page_common_inner(type, size, pages)) { - // Out of memory - return false; - } - - // Updated used statistics - increase_used(size, flags.worker_relocation()); - - // Success - return true; -} - -static void check_out_of_memory_during_initialization() { - if (!is_init_completed()) { - vm_exit_during_initialization("java.lang.OutOfMemoryError", "Java heap too small"); - } -} - -bool XPageAllocator::alloc_page_stall(XPageAllocation* allocation) { - XStatTimer timer(XCriticalPhaseAllocationStall); - EventZAllocationStall event; - XPageAllocationStall result; - - // We can only block if the VM is fully initialized - check_out_of_memory_during_initialization(); - - // Increment stalled counter - Atomic::inc(&_nstalled); - - do { - // Start asynchronous GC - XCollectedHeap::heap()->collect(GCCause::_z_allocation_stall); - - // Wait for allocation to complete, fail or request a GC - result = allocation->wait(); - } while (result == XPageAllocationStallStartGC); - - { - // - // We grab the lock here for two different reasons: - // - // 1) Guard deletion of underlying semaphore. This is a workaround for - // a bug in sem_post() in glibc < 2.21, where it's not safe to destroy - // the semaphore immediately after returning from sem_wait(). The - // reason is that sem_post() can touch the semaphore after a waiting - // thread have returned from sem_wait(). To avoid this race we are - // forcing the waiting thread to acquire/release the lock held by the - // posting thread. https://sourceware.org/bugzilla/show_bug.cgi?id=12674 - // - // 2) Guard the list of satisfied pages. - // - XLocker locker(&_lock); - _satisfied.remove(allocation); - } - - // Send event - event.commit(allocation->type(), allocation->size()); - - return (result == XPageAllocationStallSuccess); -} - -bool XPageAllocator::alloc_page_or_stall(XPageAllocation* allocation) { - { - XLocker locker(&_lock); - - if (alloc_page_common(allocation)) { - // Success - return true; - } - - // Failed - if (allocation->flags().non_blocking()) { - // Don't stall - return false; - } - - // Enqueue allocation request - _stalled.insert_last(allocation); - } - - // Stall - return alloc_page_stall(allocation); -} - -XPage* XPageAllocator::alloc_page_create(XPageAllocation* allocation) { - const size_t size = allocation->size(); - - // Allocate virtual memory. To make error handling a lot more straight - // forward, we allocate virtual memory before destroying flushed pages. - // Flushed pages are also unmapped and destroyed asynchronously, so we - // can't immediately reuse that part of the address space anyway. - const XVirtualMemory vmem = _virtual.alloc(size, allocation->flags().low_address()); - if (vmem.is_null()) { - log_error(gc)("Out of address space"); - return nullptr; - } - - XPhysicalMemory pmem; - size_t flushed = 0; - - // Harvest physical memory from flushed pages - XListRemoveIterator iter(allocation->pages()); - for (XPage* page; iter.next(&page);) { - flushed += page->size(); - - // Harvest flushed physical memory - XPhysicalMemory& fmem = page->physical_memory(); - pmem.add_segments(fmem); - fmem.remove_segments(); - - // Unmap and destroy page - _unmapper->unmap_and_destroy_page(page); - } - - if (flushed > 0) { - allocation->set_flushed(flushed); - - // Update statistics - XStatInc(XCounterPageCacheFlush, flushed); - log_debug(gc, heap)("Page Cache Flushed: " SIZE_FORMAT "M", flushed / M); - } - - // Allocate any remaining physical memory. Capacity and used has - // already been adjusted, we just need to fetch the memory, which - // is guaranteed to succeed. - if (flushed < size) { - const size_t remaining = size - flushed; - allocation->set_committed(remaining); - _physical.alloc(pmem, remaining); - } - - // Create new page - return new XPage(allocation->type(), vmem, pmem); -} - -bool XPageAllocator::should_defragment(const XPage* page) const { - // A small page can end up at a high address (second half of the address space) - // if we've split a larger page or we have a constrained address space. To help - // fight address space fragmentation we remap such pages to a lower address, if - // a lower address is available. - return page->type() == XPageTypeSmall && - page->start() >= _virtual.reserved() / 2 && - page->start() > _virtual.lowest_available_address(); -} - -bool XPageAllocator::is_alloc_satisfied(XPageAllocation* allocation) const { - // The allocation is immediately satisfied if the list of pages contains - // exactly one page, with the type and size that was requested. However, - // even if the allocation is immediately satisfied we might still want to - // return false here to force the page to be remapped to fight address - // space fragmentation. - - if (allocation->pages()->size() != 1) { - // Not a single page - return false; - } - - const XPage* const page = allocation->pages()->first(); - if (page->type() != allocation->type() || - page->size() != allocation->size()) { - // Wrong type or size - return false; - } - - if (should_defragment(page)) { - // Defragment address space - XStatInc(XCounterDefragment); - return false; - } - - // Allocation immediately satisfied - return true; -} - -XPage* XPageAllocator::alloc_page_finalize(XPageAllocation* allocation) { - // Fast path - if (is_alloc_satisfied(allocation)) { - return allocation->pages()->remove_first(); - } - - // Slow path - XPage* const page = alloc_page_create(allocation); - if (page == nullptr) { - // Out of address space - return nullptr; - } - - // Commit page - if (commit_page(page)) { - // Success - map_page(page); - return page; - } - - // Failed or partially failed. Split of any successfully committed - // part of the page into a new page and insert it into list of pages, - // so that it will be re-inserted into the page cache. - XPage* const committed_page = page->split_committed(); - destroy_page(page); - - if (committed_page != nullptr) { - map_page(committed_page); - allocation->pages()->insert_last(committed_page); - } - - return nullptr; -} - -void XPageAllocator::alloc_page_failed(XPageAllocation* allocation) { - XLocker locker(&_lock); - - size_t freed = 0; - - // Free any allocated/flushed pages - XListRemoveIterator iter(allocation->pages()); - for (XPage* page; iter.next(&page);) { - freed += page->size(); - free_page_inner(page, false /* reclaimed */); - } - - // Adjust capacity and used to reflect the failed capacity increase - const size_t remaining = allocation->size() - freed; - decrease_used(remaining, false /* reclaimed */); - decrease_capacity(remaining, true /* set_max_capacity */); - - // Try satisfy stalled allocations - satisfy_stalled(); -} - -XPage* XPageAllocator::alloc_page(uint8_t type, size_t size, XAllocationFlags flags) { - EventZPageAllocation event; - -retry: - XPageAllocation allocation(type, size, flags); - - // Allocate one or more pages from the page cache. If the allocation - // succeeds but the returned pages don't cover the complete allocation, - // then finalize phase is allowed to allocate the remaining memory - // directly from the physical memory manager. Note that this call might - // block in a safepoint if the non-blocking flag is not set. - if (!alloc_page_or_stall(&allocation)) { - // Out of memory - return nullptr; - } - - XPage* const page = alloc_page_finalize(&allocation); - if (page == nullptr) { - // Failed to commit or map. Clean up and retry, in the hope that - // we can still allocate by flushing the page cache (more aggressively). - alloc_page_failed(&allocation); - goto retry; - } - - // Reset page. This updates the page's sequence number and must - // be done after we potentially blocked in a safepoint (stalled) - // where the global sequence number was updated. - page->reset(); - - // Update allocation statistics. Exclude worker relocations to avoid - // artificial inflation of the allocation rate during relocation. - if (!flags.worker_relocation() && is_init_completed()) { - // Note that there are two allocation rate counters, which have - // different purposes and are sampled at different frequencies. - const size_t bytes = page->size(); - XStatInc(XCounterAllocationRate, bytes); - XStatInc(XStatAllocRate::counter(), bytes); - } - - // Send event - event.commit(type, size, allocation.flushed(), allocation.committed(), - page->physical_memory().nsegments(), flags.non_blocking()); - - return page; -} - -void XPageAllocator::satisfy_stalled() { - for (;;) { - XPageAllocation* const allocation = _stalled.first(); - if (allocation == nullptr) { - // Allocation queue is empty - return; - } - - if (!alloc_page_common(allocation)) { - // Allocation could not be satisfied, give up - return; - } - - // Allocation succeeded, dequeue and satisfy allocation request. - // Note that we must dequeue the allocation request first, since - // it will immediately be deallocated once it has been satisfied. - _stalled.remove(allocation); - _satisfied.insert_last(allocation); - allocation->satisfy(XPageAllocationStallSuccess); - } -} - -void XPageAllocator::free_page_inner(XPage* page, bool reclaimed) { - // Update used statistics - decrease_used(page->size(), reclaimed); - - // Set time when last used - page->set_last_used(); - - // Cache page - _cache.free_page(page); -} - -void XPageAllocator::free_page(XPage* page, bool reclaimed) { - XLocker locker(&_lock); - - // Free page - free_page_inner(page, reclaimed); - - // Try satisfy stalled allocations - satisfy_stalled(); -} - -void XPageAllocator::free_pages(const XArray* pages, bool reclaimed) { - XLocker locker(&_lock); - - // Free pages - XArrayIterator iter(pages); - for (XPage* page; iter.next(&page);) { - free_page_inner(page, reclaimed); - } - - // Try satisfy stalled allocations - satisfy_stalled(); -} - -size_t XPageAllocator::uncommit(uint64_t* timeout) { - // We need to join the suspendible thread set while manipulating capacity and - // used, to make sure GC safepoints will have a consistent view. However, when - // ZVerifyViews is enabled we need to join at a broader scope to also make sure - // we don't change the address good mask after pages have been flushed, and - // thereby made invisible to pages_do(), but before they have been unmapped. - SuspendibleThreadSetJoiner joiner(ZVerifyViews); - XList pages; - size_t flushed; - - { - SuspendibleThreadSetJoiner joiner(!ZVerifyViews); - XLocker locker(&_lock); - - // Never uncommit below min capacity. We flush out and uncommit chunks at - // a time (~0.8% of the max capacity, but at least one granule and at most - // 256M), in case demand for memory increases while we are uncommitting. - const size_t retain = MAX2(_used, _min_capacity); - const size_t release = _capacity - retain; - const size_t limit = MIN2(align_up(_current_max_capacity >> 7, XGranuleSize), 256 * M); - const size_t flush = MIN2(release, limit); - - // Flush pages to uncommit - flushed = _cache.flush_for_uncommit(flush, &pages, timeout); - if (flushed == 0) { - // Nothing flushed - return 0; - } - - // Record flushed pages as claimed - Atomic::add(&_claimed, flushed); - } - - // Unmap, uncommit, and destroy flushed pages - XListRemoveIterator iter(&pages); - for (XPage* page; iter.next(&page);) { - unmap_page(page); - uncommit_page(page); - destroy_page(page); - } - - { - SuspendibleThreadSetJoiner joiner(!ZVerifyViews); - XLocker locker(&_lock); - - // Adjust claimed and capacity to reflect the uncommit - Atomic::sub(&_claimed, flushed); - decrease_capacity(flushed, false /* set_max_capacity */); - } - - return flushed; -} - -void XPageAllocator::enable_deferred_delete() const { - _safe_delete.enable_deferred_delete(); -} - -void XPageAllocator::disable_deferred_delete() const { - _safe_delete.disable_deferred_delete(); -} - -void XPageAllocator::debug_map_page(const XPage* page) const { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - _physical.debug_map(page->start(), page->physical_memory()); -} - -void XPageAllocator::debug_unmap_page(const XPage* page) const { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - _physical.debug_unmap(page->start(), page->size()); -} - -void XPageAllocator::pages_do(XPageClosure* cl) const { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - - XListIterator iter_satisfied(&_satisfied); - for (XPageAllocation* allocation; iter_satisfied.next(&allocation);) { - XListIterator iter_pages(allocation->pages()); - for (XPage* page; iter_pages.next(&page);) { - cl->do_page(page); - } - } - - _cache.pages_do(cl); -} - -bool XPageAllocator::has_alloc_stalled() const { - return Atomic::load(&_nstalled) != 0; -} - -void XPageAllocator::check_out_of_memory() { - XLocker locker(&_lock); - - // Fail allocation requests that were enqueued before the - // last GC cycle started, otherwise start a new GC cycle. - for (XPageAllocation* allocation = _stalled.first(); allocation != nullptr; allocation = _stalled.first()) { - if (allocation->seqnum() == XGlobalSeqNum) { - // Start a new GC cycle, keep allocation requests enqueued - allocation->satisfy(XPageAllocationStallStartGC); - return; - } - - // Out of memory, fail allocation request - _stalled.remove(allocation); - _satisfied.insert_last(allocation); - allocation->satisfy(XPageAllocationStallFailed); - } -} - -void XPageAllocator::threads_do(ThreadClosure* tc) const { - tc->do_thread(_unmapper); - tc->do_thread(_uncommitter); -} diff --git a/src/hotspot/share/gc/x/xPageAllocator.hpp b/src/hotspot/share/gc/x/xPageAllocator.hpp deleted file mode 100644 index b907e50043d42..0000000000000 --- a/src/hotspot/share/gc/x/xPageAllocator.hpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XPAGEALLOCATOR_HPP -#define SHARE_GC_X_XPAGEALLOCATOR_HPP - -#include "gc/x/xAllocationFlags.hpp" -#include "gc/x/xArray.hpp" -#include "gc/x/xList.hpp" -#include "gc/x/xLock.hpp" -#include "gc/x/xPageCache.hpp" -#include "gc/x/xPhysicalMemory.hpp" -#include "gc/x/xSafeDelete.hpp" -#include "gc/x/xVirtualMemory.hpp" - -class ThreadClosure; -class VMStructs; -class XPageAllocation; -class XPageAllocatorStats; -class XWorkers; -class XUncommitter; -class XUnmapper; - -class XPageAllocator { - friend class ::VMStructs; - friend class XUnmapper; - friend class XUncommitter; - -private: - mutable XLock _lock; - XPageCache _cache; - XVirtualMemoryManager _virtual; - XPhysicalMemoryManager _physical; - const size_t _min_capacity; - const size_t _max_capacity; - volatile size_t _current_max_capacity; - volatile size_t _capacity; - volatile size_t _claimed; - volatile size_t _used; - size_t _used_high; - size_t _used_low; - ssize_t _reclaimed; - XList _stalled; - volatile uint64_t _nstalled; - XList _satisfied; - XUnmapper* _unmapper; - XUncommitter* _uncommitter; - mutable XSafeDelete _safe_delete; - bool _initialized; - - bool prime_cache(XWorkers* workers, size_t size); - - size_t increase_capacity(size_t size); - void decrease_capacity(size_t size, bool set_max_capacity); - - void increase_used(size_t size, bool relocation); - void decrease_used(size_t size, bool reclaimed); - - bool commit_page(XPage* page); - void uncommit_page(XPage* page); - - void map_page(const XPage* page) const; - void unmap_page(const XPage* page) const; - - void destroy_page(XPage* page); - - bool is_alloc_allowed(size_t size) const; - - bool alloc_page_common_inner(uint8_t type, size_t size, XList* pages); - bool alloc_page_common(XPageAllocation* allocation); - bool alloc_page_stall(XPageAllocation* allocation); - bool alloc_page_or_stall(XPageAllocation* allocation); - bool should_defragment(const XPage* page) const; - bool is_alloc_satisfied(XPageAllocation* allocation) const; - XPage* alloc_page_create(XPageAllocation* allocation); - XPage* alloc_page_finalize(XPageAllocation* allocation); - void alloc_page_failed(XPageAllocation* allocation); - - void satisfy_stalled(); - - void free_page_inner(XPage* page, bool reclaimed); - - size_t uncommit(uint64_t* timeout); - -public: - XPageAllocator(XWorkers* workers, - size_t min_capacity, - size_t initial_capacity, - size_t max_capacity); - - bool is_initialized() const; - - size_t min_capacity() const; - size_t max_capacity() const; - size_t soft_max_capacity() const; - size_t capacity() const; - size_t used() const; - size_t unused() const; - - XPageAllocatorStats stats() const; - - void reset_statistics(); - - XPage* alloc_page(uint8_t type, size_t size, XAllocationFlags flags); - void free_page(XPage* page, bool reclaimed); - void free_pages(const XArray* pages, bool reclaimed); - - void enable_deferred_delete() const; - void disable_deferred_delete() const; - - void debug_map_page(const XPage* page) const; - void debug_unmap_page(const XPage* page) const; - - bool has_alloc_stalled() const; - void check_out_of_memory(); - - void pages_do(XPageClosure* cl) const; - - void threads_do(ThreadClosure* tc) const; -}; - -class XPageAllocatorStats { -private: - size_t _min_capacity; - size_t _max_capacity; - size_t _soft_max_capacity; - size_t _current_max_capacity; - size_t _capacity; - size_t _used; - size_t _used_high; - size_t _used_low; - size_t _reclaimed; - -public: - XPageAllocatorStats(size_t min_capacity, - size_t max_capacity, - size_t soft_max_capacity, - size_t capacity, - size_t used, - size_t used_high, - size_t used_low, - size_t reclaimed); - - size_t min_capacity() const; - size_t max_capacity() const; - size_t soft_max_capacity() const; - size_t capacity() const; - size_t used() const; - size_t used_high() const; - size_t used_low() const; - size_t reclaimed() const; -}; - -#endif // SHARE_GC_X_XPAGEALLOCATOR_HPP diff --git a/src/hotspot/share/gc/x/xPageAllocator.inline.hpp b/src/hotspot/share/gc/x/xPageAllocator.inline.hpp deleted file mode 100644 index dbaf77f56a051..0000000000000 --- a/src/hotspot/share/gc/x/xPageAllocator.inline.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XPAGEALLOCATOR_INLINE_HPP -#define SHARE_GC_X_XPAGEALLOCATOR_INLINE_HPP - -#include "gc/x/xPageAllocator.hpp" - -inline XPageAllocatorStats::XPageAllocatorStats(size_t min_capacity, - size_t max_capacity, - size_t soft_max_capacity, - size_t capacity, - size_t used, - size_t used_high, - size_t used_low, - size_t reclaimed) : - _min_capacity(min_capacity), - _max_capacity(max_capacity), - _soft_max_capacity(soft_max_capacity), - _capacity(capacity), - _used(used), - _used_high(used_high), - _used_low(used_low), - _reclaimed(reclaimed) {} - -inline size_t XPageAllocatorStats::min_capacity() const { - return _min_capacity; -} - -inline size_t XPageAllocatorStats::max_capacity() const { - return _max_capacity; -} - -inline size_t XPageAllocatorStats::soft_max_capacity() const { - return _soft_max_capacity; -} - -inline size_t XPageAllocatorStats::capacity() const { - return _capacity; -} - -inline size_t XPageAllocatorStats::used() const { - return _used; -} - -inline size_t XPageAllocatorStats::used_high() const { - return _used_high; -} - -inline size_t XPageAllocatorStats::used_low() const { - return _used_low; -} - -inline size_t XPageAllocatorStats::reclaimed() const { - return _reclaimed; -} - -#endif // SHARE_GC_X_XPAGEALLOCATOR_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xPageCache.cpp b/src/hotspot/share/gc/x/xPageCache.cpp deleted file mode 100644 index d38b0646a8a41..0000000000000 --- a/src/hotspot/share/gc/x/xPageCache.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -#include "precompiled.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xList.inline.hpp" -#include "gc/x/xNUMA.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xPageCache.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xValue.inline.hpp" -#include "memory/allocation.hpp" -#include "runtime/globals.hpp" -#include "runtime/os.hpp" - -static const XStatCounter XCounterPageCacheHitL1("Memory", "Page Cache Hit L1", XStatUnitOpsPerSecond); -static const XStatCounter XCounterPageCacheHitL2("Memory", "Page Cache Hit L2", XStatUnitOpsPerSecond); -static const XStatCounter XCounterPageCacheHitL3("Memory", "Page Cache Hit L3", XStatUnitOpsPerSecond); -static const XStatCounter XCounterPageCacheMiss("Memory", "Page Cache Miss", XStatUnitOpsPerSecond); - -class XPageCacheFlushClosure : public StackObj { - friend class XPageCache; - -protected: - const size_t _requested; - size_t _flushed; - -public: - XPageCacheFlushClosure(size_t requested); - virtual bool do_page(const XPage* page) = 0; -}; - -XPageCacheFlushClosure::XPageCacheFlushClosure(size_t requested) : - _requested(requested), - _flushed(0) {} - -XPageCache::XPageCache() : - _small(), - _medium(), - _large(), - _last_commit(0) {} - -XPage* XPageCache::alloc_small_page() { - const uint32_t numa_id = XNUMA::id(); - const uint32_t numa_count = XNUMA::count(); - - // Try NUMA local page cache - XPage* const l1_page = _small.get(numa_id).remove_first(); - if (l1_page != nullptr) { - XStatInc(XCounterPageCacheHitL1); - return l1_page; - } - - // Try NUMA remote page cache(s) - uint32_t remote_numa_id = numa_id + 1; - const uint32_t remote_numa_count = numa_count - 1; - for (uint32_t i = 0; i < remote_numa_count; i++) { - if (remote_numa_id == numa_count) { - remote_numa_id = 0; - } - - XPage* const l2_page = _small.get(remote_numa_id).remove_first(); - if (l2_page != nullptr) { - XStatInc(XCounterPageCacheHitL2); - return l2_page; - } - - remote_numa_id++; - } - - return nullptr; -} - -XPage* XPageCache::alloc_medium_page() { - XPage* const page = _medium.remove_first(); - if (page != nullptr) { - XStatInc(XCounterPageCacheHitL1); - return page; - } - - return nullptr; -} - -XPage* XPageCache::alloc_large_page(size_t size) { - // Find a page with the right size - XListIterator iter(&_large); - for (XPage* page; iter.next(&page);) { - if (size == page->size()) { - // Page found - _large.remove(page); - XStatInc(XCounterPageCacheHitL1); - return page; - } - } - - return nullptr; -} - -XPage* XPageCache::alloc_oversized_medium_page(size_t size) { - if (size <= XPageSizeMedium) { - return _medium.remove_first(); - } - - return nullptr; -} - -XPage* XPageCache::alloc_oversized_large_page(size_t size) { - // Find a page that is large enough - XListIterator iter(&_large); - for (XPage* page; iter.next(&page);) { - if (size <= page->size()) { - // Page found - _large.remove(page); - return page; - } - } - - return nullptr; -} - -XPage* XPageCache::alloc_oversized_page(size_t size) { - XPage* page = alloc_oversized_large_page(size); - if (page == nullptr) { - page = alloc_oversized_medium_page(size); - } - - if (page != nullptr) { - XStatInc(XCounterPageCacheHitL3); - } - - return page; -} - -XPage* XPageCache::alloc_page(uint8_t type, size_t size) { - XPage* page; - - // Try allocate exact page - if (type == XPageTypeSmall) { - page = alloc_small_page(); - } else if (type == XPageTypeMedium) { - page = alloc_medium_page(); - } else { - page = alloc_large_page(size); - } - - if (page == nullptr) { - // Try allocate potentially oversized page - XPage* const oversized = alloc_oversized_page(size); - if (oversized != nullptr) { - if (size < oversized->size()) { - // Split oversized page - page = oversized->split(type, size); - - // Cache remainder - free_page(oversized); - } else { - // Re-type correctly sized page - page = oversized->retype(type); - } - } - } - - if (page == nullptr) { - XStatInc(XCounterPageCacheMiss); - } - - return page; -} - -void XPageCache::free_page(XPage* page) { - const uint8_t type = page->type(); - if (type == XPageTypeSmall) { - _small.get(page->numa_id()).insert_first(page); - } else if (type == XPageTypeMedium) { - _medium.insert_first(page); - } else { - _large.insert_first(page); - } -} - -bool XPageCache::flush_list_inner(XPageCacheFlushClosure* cl, XList* from, XList* to) { - XPage* const page = from->last(); - if (page == nullptr || !cl->do_page(page)) { - // Don't flush page - return false; - } - - // Flush page - from->remove(page); - to->insert_last(page); - return true; -} - -void XPageCache::flush_list(XPageCacheFlushClosure* cl, XList* from, XList* to) { - while (flush_list_inner(cl, from, to)); -} - -void XPageCache::flush_per_numa_lists(XPageCacheFlushClosure* cl, XPerNUMA >* from, XList* to) { - const uint32_t numa_count = XNUMA::count(); - uint32_t numa_done = 0; - uint32_t numa_next = 0; - - // Flush lists round-robin - while (numa_done < numa_count) { - XList* numa_list = from->addr(numa_next); - if (++numa_next == numa_count) { - numa_next = 0; - } - - if (flush_list_inner(cl, numa_list, to)) { - // Not done - numa_done = 0; - } else { - // Done - numa_done++; - } - } -} - -void XPageCache::flush(XPageCacheFlushClosure* cl, XList* to) { - // Prefer flushing large, then medium and last small pages - flush_list(cl, &_large, to); - flush_list(cl, &_medium, to); - flush_per_numa_lists(cl, &_small, to); - - if (cl->_flushed > cl->_requested) { - // Overflushed, re-insert part of last page into the cache - const size_t overflushed = cl->_flushed - cl->_requested; - XPage* const reinsert = to->last()->split(overflushed); - free_page(reinsert); - cl->_flushed -= overflushed; - } -} - -class XPageCacheFlushForAllocationClosure : public XPageCacheFlushClosure { -public: - XPageCacheFlushForAllocationClosure(size_t requested) : - XPageCacheFlushClosure(requested) {} - - virtual bool do_page(const XPage* page) { - if (_flushed < _requested) { - // Flush page - _flushed += page->size(); - return true; - } - - // Don't flush page - return false; - } -}; - -void XPageCache::flush_for_allocation(size_t requested, XList* to) { - XPageCacheFlushForAllocationClosure cl(requested); - flush(&cl, to); -} - -class XPageCacheFlushForUncommitClosure : public XPageCacheFlushClosure { -private: - const uint64_t _now; - uint64_t* _timeout; - -public: - XPageCacheFlushForUncommitClosure(size_t requested, uint64_t now, uint64_t* timeout) : - XPageCacheFlushClosure(requested), - _now(now), - _timeout(timeout) { - // Set initial timeout - *_timeout = ZUncommitDelay; - } - - virtual bool do_page(const XPage* page) { - const uint64_t expires = page->last_used() + ZUncommitDelay; - if (expires > _now) { - // Don't flush page, record shortest non-expired timeout - *_timeout = MIN2(*_timeout, expires - _now); - return false; - } - - if (_flushed >= _requested) { - // Don't flush page, requested amount flushed - return false; - } - - // Flush page - _flushed += page->size(); - return true; - } -}; - -size_t XPageCache::flush_for_uncommit(size_t requested, XList* to, uint64_t* timeout) { - const uint64_t now = os::elapsedTime(); - const uint64_t expires = _last_commit + ZUncommitDelay; - if (expires > now) { - // Delay uncommit, set next timeout - *timeout = expires - now; - return 0; - } - - if (requested == 0) { - // Nothing to flush, set next timeout - *timeout = ZUncommitDelay; - return 0; - } - - XPageCacheFlushForUncommitClosure cl(requested, now, timeout); - flush(&cl, to); - - return cl._flushed; -} - -void XPageCache::set_last_commit() { - _last_commit = ceil(os::elapsedTime()); -} - -void XPageCache::pages_do(XPageClosure* cl) const { - // Small - XPerNUMAConstIterator > iter_numa(&_small); - for (const XList* list; iter_numa.next(&list);) { - XListIterator iter_small(list); - for (XPage* page; iter_small.next(&page);) { - cl->do_page(page); - } - } - - // Medium - XListIterator iter_medium(&_medium); - for (XPage* page; iter_medium.next(&page);) { - cl->do_page(page); - } - - // Large - XListIterator iter_large(&_large); - for (XPage* page; iter_large.next(&page);) { - cl->do_page(page); - } -} diff --git a/src/hotspot/share/gc/x/xPageCache.hpp b/src/hotspot/share/gc/x/xPageCache.hpp deleted file mode 100644 index 9ed80a933f43b..0000000000000 --- a/src/hotspot/share/gc/x/xPageCache.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XPAGECACHE_HPP -#define SHARE_GC_X_XPAGECACHE_HPP - -#include "gc/x/xList.hpp" -#include "gc/x/xPage.hpp" -#include "gc/x/xValue.hpp" - -class XPageCacheFlushClosure; - -class XPageCache { -private: - XPerNUMA > _small; - XList _medium; - XList _large; - uint64_t _last_commit; - - XPage* alloc_small_page(); - XPage* alloc_medium_page(); - XPage* alloc_large_page(size_t size); - - XPage* alloc_oversized_medium_page(size_t size); - XPage* alloc_oversized_large_page(size_t size); - XPage* alloc_oversized_page(size_t size); - - bool flush_list_inner(XPageCacheFlushClosure* cl, XList* from, XList* to); - void flush_list(XPageCacheFlushClosure* cl, XList* from, XList* to); - void flush_per_numa_lists(XPageCacheFlushClosure* cl, XPerNUMA >* from, XList* to); - void flush(XPageCacheFlushClosure* cl, XList* to); - -public: - XPageCache(); - - XPage* alloc_page(uint8_t type, size_t size); - void free_page(XPage* page); - - void flush_for_allocation(size_t requested, XList* to); - size_t flush_for_uncommit(size_t requested, XList* to, uint64_t* timeout); - - void set_last_commit(); - - void pages_do(XPageClosure* cl) const; -}; - -#endif // SHARE_GC_X_XPAGECACHE_HPP diff --git a/src/hotspot/share/gc/x/xPageTable.cpp b/src/hotspot/share/gc/x/xPageTable.cpp deleted file mode 100644 index c3103e808ca21..0000000000000 --- a/src/hotspot/share/gc/x/xPageTable.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xGranuleMap.inline.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xPageTable.inline.hpp" -#include "runtime/orderAccess.hpp" -#include "utilities/debug.hpp" - -XPageTable::XPageTable() : - _map(XAddressOffsetMax) {} - -void XPageTable::insert(XPage* page) { - const uintptr_t offset = page->start(); - const size_t size = page->size(); - - // Make sure a newly created page is - // visible before updating the page table. - OrderAccess::storestore(); - - assert(_map.get(offset) == nullptr, "Invalid entry"); - _map.put(offset, size, page); -} - -void XPageTable::remove(XPage* page) { - const uintptr_t offset = page->start(); - const size_t size = page->size(); - - assert(_map.get(offset) == page, "Invalid entry"); - _map.put(offset, size, nullptr); -} diff --git a/src/hotspot/share/gc/x/xPageTable.hpp b/src/hotspot/share/gc/x/xPageTable.hpp deleted file mode 100644 index 958dd73555770..0000000000000 --- a/src/hotspot/share/gc/x/xPageTable.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * 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_GC_X_XPAGETABLE_HPP -#define SHARE_GC_X_XPAGETABLE_HPP - -#include "gc/x/xGranuleMap.hpp" -#include "memory/allocation.hpp" - -class VMStructs; -class XPage; -class XPageTableIterator; - -class XPageTable { - friend class ::VMStructs; - friend class XPageTableIterator; - -private: - XGranuleMap _map; - -public: - XPageTable(); - - XPage* get(uintptr_t addr) const; - - void insert(XPage* page); - void remove(XPage* page); -}; - -class XPageTableIterator : public StackObj { -private: - XGranuleMapIterator _iter; - XPage* _prev; - -public: - XPageTableIterator(const XPageTable* page_table); - - bool next(XPage** page); -}; - -#endif // SHARE_GC_X_XPAGETABLE_HPP diff --git a/src/hotspot/share/gc/x/xPageTable.inline.hpp b/src/hotspot/share/gc/x/xPageTable.inline.hpp deleted file mode 100644 index 65ad223e334f0..0000000000000 --- a/src/hotspot/share/gc/x/xPageTable.inline.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * 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_GC_X_XPAGETABLE_INLINE_HPP -#define SHARE_GC_X_XPAGETABLE_INLINE_HPP - -#include "gc/x/xPageTable.hpp" - -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xGranuleMap.inline.hpp" - -inline XPage* XPageTable::get(uintptr_t addr) const { - assert(!XAddress::is_null(addr), "Invalid address"); - return _map.get(XAddress::offset(addr)); -} - -inline XPageTableIterator::XPageTableIterator(const XPageTable* page_table) : - _iter(&page_table->_map), - _prev(nullptr) {} - -inline bool XPageTableIterator::next(XPage** page) { - for (XPage* entry; _iter.next(&entry);) { - if (entry != nullptr && entry != _prev) { - // Next page found - *page = _prev = entry; - return true; - } - } - - // No more pages - return false; -} - -#endif // SHARE_GC_X_XPAGETABLE_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xPhysicalMemory.cpp b/src/hotspot/share/gc/x/xPhysicalMemory.cpp deleted file mode 100644 index 0269c64f0f1aa..0000000000000 --- a/src/hotspot/share/gc/x/xPhysicalMemory.cpp +++ /dev/null @@ -1,434 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xArray.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xLargePages.inline.hpp" -#include "gc/x/xList.inline.hpp" -#include "gc/x/xNUMA.inline.hpp" -#include "gc/x/xPhysicalMemory.inline.hpp" -#include "logging/log.hpp" -#include "nmt/memTracker.hpp" -#include "runtime/globals.hpp" -#include "runtime/globals_extension.hpp" -#include "runtime/init.hpp" -#include "runtime/os.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/powerOfTwo.hpp" - -XPhysicalMemory::XPhysicalMemory() : - _segments() {} - -XPhysicalMemory::XPhysicalMemory(const XPhysicalMemorySegment& segment) : - _segments() { - add_segment(segment); -} - -XPhysicalMemory::XPhysicalMemory(const XPhysicalMemory& pmem) : - _segments() { - add_segments(pmem); -} - -const XPhysicalMemory& XPhysicalMemory::operator=(const XPhysicalMemory& pmem) { - // Free segments - _segments.clear_and_deallocate(); - - // Copy segments - add_segments(pmem); - - return *this; -} - -size_t XPhysicalMemory::size() const { - size_t size = 0; - - for (int i = 0; i < _segments.length(); i++) { - size += _segments.at(i).size(); - } - - return size; -} - -void XPhysicalMemory::insert_segment(int index, uintptr_t start, size_t size, bool committed) { - _segments.insert_before(index, XPhysicalMemorySegment(start, size, committed)); -} - -void XPhysicalMemory::replace_segment(int index, uintptr_t start, size_t size, bool committed) { - _segments.at_put(index, XPhysicalMemorySegment(start, size, committed)); -} - -void XPhysicalMemory::remove_segment(int index) { - _segments.remove_at(index); -} - -void XPhysicalMemory::add_segments(const XPhysicalMemory& pmem) { - for (int i = 0; i < pmem.nsegments(); i++) { - add_segment(pmem.segment(i)); - } -} - -void XPhysicalMemory::remove_segments() { - _segments.clear_and_deallocate(); -} - -static bool is_mergable(const XPhysicalMemorySegment& before, const XPhysicalMemorySegment& after) { - return before.end() == after.start() && before.is_committed() == after.is_committed(); -} - -void XPhysicalMemory::add_segment(const XPhysicalMemorySegment& segment) { - // Insert segments in address order, merge segments when possible - for (int i = _segments.length(); i > 0; i--) { - const int current = i - 1; - - if (_segments.at(current).end() <= segment.start()) { - if (is_mergable(_segments.at(current), segment)) { - if (current + 1 < _segments.length() && is_mergable(segment, _segments.at(current + 1))) { - // Merge with end of current segment and start of next segment - const size_t start = _segments.at(current).start(); - const size_t size = _segments.at(current).size() + segment.size() + _segments.at(current + 1).size(); - replace_segment(current, start, size, segment.is_committed()); - remove_segment(current + 1); - return; - } - - // Merge with end of current segment - const size_t start = _segments.at(current).start(); - const size_t size = _segments.at(current).size() + segment.size(); - replace_segment(current, start, size, segment.is_committed()); - return; - } else if (current + 1 < _segments.length() && is_mergable(segment, _segments.at(current + 1))) { - // Merge with start of next segment - const size_t start = segment.start(); - const size_t size = segment.size() + _segments.at(current + 1).size(); - replace_segment(current + 1, start, size, segment.is_committed()); - return; - } - - // Insert after current segment - insert_segment(current + 1, segment.start(), segment.size(), segment.is_committed()); - return; - } - } - - if (_segments.length() > 0 && is_mergable(segment, _segments.at(0))) { - // Merge with start of first segment - const size_t start = segment.start(); - const size_t size = segment.size() + _segments.at(0).size(); - replace_segment(0, start, size, segment.is_committed()); - return; - } - - // Insert before first segment - insert_segment(0, segment.start(), segment.size(), segment.is_committed()); -} - -bool XPhysicalMemory::commit_segment(int index, size_t size) { - assert(size <= _segments.at(index).size(), "Invalid size"); - assert(!_segments.at(index).is_committed(), "Invalid state"); - - if (size == _segments.at(index).size()) { - // Completely committed - _segments.at(index).set_committed(true); - return true; - } - - if (size > 0) { - // Partially committed, split segment - insert_segment(index + 1, _segments.at(index).start() + size, _segments.at(index).size() - size, false /* committed */); - replace_segment(index, _segments.at(index).start(), size, true /* committed */); - } - - return false; -} - -bool XPhysicalMemory::uncommit_segment(int index, size_t size) { - assert(size <= _segments.at(index).size(), "Invalid size"); - assert(_segments.at(index).is_committed(), "Invalid state"); - - if (size == _segments.at(index).size()) { - // Completely uncommitted - _segments.at(index).set_committed(false); - return true; - } - - if (size > 0) { - // Partially uncommitted, split segment - insert_segment(index + 1, _segments.at(index).start() + size, _segments.at(index).size() - size, true /* committed */); - replace_segment(index, _segments.at(index).start(), size, false /* committed */); - } - - return false; -} - -XPhysicalMemory XPhysicalMemory::split(size_t size) { - XPhysicalMemory pmem; - int nsegments = 0; - - for (int i = 0; i < _segments.length(); i++) { - const XPhysicalMemorySegment& segment = _segments.at(i); - if (pmem.size() < size) { - if (pmem.size() + segment.size() <= size) { - // Transfer segment - pmem.add_segment(segment); - } else { - // Split segment - const size_t split_size = size - pmem.size(); - pmem.add_segment(XPhysicalMemorySegment(segment.start(), split_size, segment.is_committed())); - _segments.at_put(nsegments++, XPhysicalMemorySegment(segment.start() + split_size, segment.size() - split_size, segment.is_committed())); - } - } else { - // Keep segment - _segments.at_put(nsegments++, segment); - } - } - - _segments.trunc_to(nsegments); - - return pmem; -} - -XPhysicalMemory XPhysicalMemory::split_committed() { - XPhysicalMemory pmem; - int nsegments = 0; - - for (int i = 0; i < _segments.length(); i++) { - const XPhysicalMemorySegment& segment = _segments.at(i); - if (segment.is_committed()) { - // Transfer segment - pmem.add_segment(segment); - } else { - // Keep segment - _segments.at_put(nsegments++, segment); - } - } - - _segments.trunc_to(nsegments); - - return pmem; -} - -XPhysicalMemoryManager::XPhysicalMemoryManager(size_t max_capacity) : - _backing(max_capacity) { - // Make the whole range free - _manager.free(0, max_capacity); -} - -bool XPhysicalMemoryManager::is_initialized() const { - return _backing.is_initialized(); -} - -void XPhysicalMemoryManager::warn_commit_limits(size_t max_capacity) const { - _backing.warn_commit_limits(max_capacity); -} - -void XPhysicalMemoryManager::try_enable_uncommit(size_t min_capacity, size_t max_capacity) { - assert(!is_init_completed(), "Invalid state"); - - // If uncommit is not explicitly disabled, max capacity is greater than - // min capacity, and uncommit is supported by the platform, then uncommit - // will be enabled. - if (!ZUncommit) { - log_info_p(gc, init)("Uncommit: Disabled"); - return; - } - - if (max_capacity == min_capacity) { - log_info_p(gc, init)("Uncommit: Implicitly Disabled (-Xms equals -Xmx)"); - FLAG_SET_ERGO(ZUncommit, false); - return; - } - - // Test if uncommit is supported by the operating system by committing - // and then uncommitting a granule. - XPhysicalMemory pmem(XPhysicalMemorySegment(0, XGranuleSize, false /* committed */)); - if (!commit(pmem) || !uncommit(pmem)) { - log_info_p(gc, init)("Uncommit: Implicitly Disabled (Not supported by operating system)"); - FLAG_SET_ERGO(ZUncommit, false); - return; - } - - log_info_p(gc, init)("Uncommit: Enabled"); - log_info_p(gc, init)("Uncommit Delay: " UINTX_FORMAT "s", ZUncommitDelay); -} - -void XPhysicalMemoryManager::nmt_commit(uintptr_t offset, size_t size) const { - // From an NMT point of view we treat the first heap view (marked0) as committed - const uintptr_t addr = XAddress::marked0(offset); - MemTracker::record_virtual_memory_commit((void*)addr, size, CALLER_PC); -} - -void XPhysicalMemoryManager::nmt_uncommit(uintptr_t offset, size_t size) const { - const uintptr_t addr = XAddress::marked0(offset); - ThreadCritical tc; - MemTracker::record_virtual_memory_uncommit((address)addr, size); -} - -void XPhysicalMemoryManager::alloc(XPhysicalMemory& pmem, size_t size) { - assert(is_aligned(size, XGranuleSize), "Invalid size"); - - // Allocate segments - while (size > 0) { - size_t allocated = 0; - const uintptr_t start = _manager.alloc_low_address_at_most(size, &allocated); - assert(start != UINTPTR_MAX, "Allocation should never fail"); - pmem.add_segment(XPhysicalMemorySegment(start, allocated, false /* committed */)); - size -= allocated; - } -} - -void XPhysicalMemoryManager::free(const XPhysicalMemory& pmem) { - // Free segments - for (int i = 0; i < pmem.nsegments(); i++) { - const XPhysicalMemorySegment& segment = pmem.segment(i); - _manager.free(segment.start(), segment.size()); - } -} - -bool XPhysicalMemoryManager::commit(XPhysicalMemory& pmem) { - // Commit segments - for (int i = 0; i < pmem.nsegments(); i++) { - const XPhysicalMemorySegment& segment = pmem.segment(i); - if (segment.is_committed()) { - // Segment already committed - continue; - } - - // Commit segment - const size_t committed = _backing.commit(segment.start(), segment.size()); - if (!pmem.commit_segment(i, committed)) { - // Failed or partially failed - return false; - } - } - - // Success - return true; -} - -bool XPhysicalMemoryManager::uncommit(XPhysicalMemory& pmem) { - // Commit segments - for (int i = 0; i < pmem.nsegments(); i++) { - const XPhysicalMemorySegment& segment = pmem.segment(i); - if (!segment.is_committed()) { - // Segment already uncommitted - continue; - } - - // Uncommit segment - const size_t uncommitted = _backing.uncommit(segment.start(), segment.size()); - if (!pmem.uncommit_segment(i, uncommitted)) { - // Failed or partially failed - return false; - } - } - - // Success - return true; -} - -void XPhysicalMemoryManager::pretouch_view(uintptr_t addr, size_t size) const { - const size_t page_size = XLargePages::is_explicit() ? XGranuleSize : os::vm_page_size(); - os::pretouch_memory((void*)addr, (void*)(addr + size), page_size); -} - -void XPhysicalMemoryManager::map_view(uintptr_t addr, const XPhysicalMemory& pmem) const { - size_t size = 0; - - // Map segments - for (int i = 0; i < pmem.nsegments(); i++) { - const XPhysicalMemorySegment& segment = pmem.segment(i); - _backing.map(addr + size, segment.size(), segment.start()); - size += segment.size(); - } - - // Setup NUMA interleaving for large pages - if (XNUMA::is_enabled() && XLargePages::is_explicit()) { - // To get granule-level NUMA interleaving when using large pages, - // we simply let the kernel interleave the memory for us at page - // fault time. - os::numa_make_global((char*)addr, size); - } -} - -void XPhysicalMemoryManager::unmap_view(uintptr_t addr, size_t size) const { - _backing.unmap(addr, size); -} - -void XPhysicalMemoryManager::pretouch(uintptr_t offset, size_t size) const { - if (ZVerifyViews) { - // Pre-touch good view - pretouch_view(XAddress::good(offset), size); - } else { - // Pre-touch all views - pretouch_view(XAddress::marked0(offset), size); - pretouch_view(XAddress::marked1(offset), size); - pretouch_view(XAddress::remapped(offset), size); - } -} - -void XPhysicalMemoryManager::map(uintptr_t offset, const XPhysicalMemory& pmem) const { - const size_t size = pmem.size(); - - if (ZVerifyViews) { - // Map good view - map_view(XAddress::good(offset), pmem); - } else { - // Map all views - map_view(XAddress::marked0(offset), pmem); - map_view(XAddress::marked1(offset), pmem); - map_view(XAddress::remapped(offset), pmem); - } - - nmt_commit(offset, size); -} - -void XPhysicalMemoryManager::unmap(uintptr_t offset, size_t size) const { - nmt_uncommit(offset, size); - - if (ZVerifyViews) { - // Unmap good view - unmap_view(XAddress::good(offset), size); - } else { - // Unmap all views - unmap_view(XAddress::marked0(offset), size); - unmap_view(XAddress::marked1(offset), size); - unmap_view(XAddress::remapped(offset), size); - } -} - -void XPhysicalMemoryManager::debug_map(uintptr_t offset, const XPhysicalMemory& pmem) const { - // Map good view - assert(ZVerifyViews, "Should be enabled"); - map_view(XAddress::good(offset), pmem); -} - -void XPhysicalMemoryManager::debug_unmap(uintptr_t offset, size_t size) const { - // Unmap good view - assert(ZVerifyViews, "Should be enabled"); - unmap_view(XAddress::good(offset), size); -} diff --git a/src/hotspot/share/gc/x/xPhysicalMemory.hpp b/src/hotspot/share/gc/x/xPhysicalMemory.hpp deleted file mode 100644 index 26d8ed9bb9641..0000000000000 --- a/src/hotspot/share/gc/x/xPhysicalMemory.hpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XPHYSICALMEMORY_HPP -#define SHARE_GC_X_XPHYSICALMEMORY_HPP - -#include "gc/x/xArray.hpp" -#include "gc/x/xMemory.hpp" -#include "memory/allocation.hpp" -#include OS_HEADER(gc/x/xPhysicalMemoryBacking) - -class XPhysicalMemorySegment : public CHeapObj { -private: - uintptr_t _start; - uintptr_t _end; - bool _committed; - -public: - XPhysicalMemorySegment(); - XPhysicalMemorySegment(uintptr_t start, size_t size, bool committed); - - uintptr_t start() const; - uintptr_t end() const; - size_t size() const; - - bool is_committed() const; - void set_committed(bool committed); -}; - -class XPhysicalMemory { -private: - XArray _segments; - - void insert_segment(int index, uintptr_t start, size_t size, bool committed); - void replace_segment(int index, uintptr_t start, size_t size, bool committed); - void remove_segment(int index); - -public: - XPhysicalMemory(); - XPhysicalMemory(const XPhysicalMemorySegment& segment); - XPhysicalMemory(const XPhysicalMemory& pmem); - const XPhysicalMemory& operator=(const XPhysicalMemory& pmem); - - bool is_null() const; - size_t size() const; - - int nsegments() const; - const XPhysicalMemorySegment& segment(int index) const; - - void add_segments(const XPhysicalMemory& pmem); - void remove_segments(); - - void add_segment(const XPhysicalMemorySegment& segment); - bool commit_segment(int index, size_t size); - bool uncommit_segment(int index, size_t size); - - XPhysicalMemory split(size_t size); - XPhysicalMemory split_committed(); -}; - -class XPhysicalMemoryManager { -private: - XPhysicalMemoryBacking _backing; - XMemoryManager _manager; - - void nmt_commit(uintptr_t offset, size_t size) const; - void nmt_uncommit(uintptr_t offset, size_t size) const; - - void pretouch_view(uintptr_t addr, size_t size) const; - void map_view(uintptr_t addr, const XPhysicalMemory& pmem) const; - void unmap_view(uintptr_t addr, size_t size) const; - -public: - XPhysicalMemoryManager(size_t max_capacity); - - bool is_initialized() const; - - void warn_commit_limits(size_t max_capacity) const; - void try_enable_uncommit(size_t min_capacity, size_t max_capacity); - - void alloc(XPhysicalMemory& pmem, size_t size); - void free(const XPhysicalMemory& pmem); - - bool commit(XPhysicalMemory& pmem); - bool uncommit(XPhysicalMemory& pmem); - - void pretouch(uintptr_t offset, size_t size) const; - - void map(uintptr_t offset, const XPhysicalMemory& pmem) const; - void unmap(uintptr_t offset, size_t size) const; - - void debug_map(uintptr_t offset, const XPhysicalMemory& pmem) const; - void debug_unmap(uintptr_t offset, size_t size) const; -}; - -#endif // SHARE_GC_X_XPHYSICALMEMORY_HPP diff --git a/src/hotspot/share/gc/x/xPhysicalMemory.inline.hpp b/src/hotspot/share/gc/x/xPhysicalMemory.inline.hpp deleted file mode 100644 index 70f38e2abdbbb..0000000000000 --- a/src/hotspot/share/gc/x/xPhysicalMemory.inline.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XPHYSICALMEMORY_INLINE_HPP -#define SHARE_GC_X_XPHYSICALMEMORY_INLINE_HPP - -#include "gc/x/xPhysicalMemory.hpp" - -#include "gc/x/xAddress.inline.hpp" -#include "utilities/debug.hpp" - -inline XPhysicalMemorySegment::XPhysicalMemorySegment() : - _start(UINTPTR_MAX), - _end(UINTPTR_MAX), - _committed(false) {} - -inline XPhysicalMemorySegment::XPhysicalMemorySegment(uintptr_t start, size_t size, bool committed) : - _start(start), - _end(start + size), - _committed(committed) {} - -inline uintptr_t XPhysicalMemorySegment::start() const { - return _start; -} - -inline uintptr_t XPhysicalMemorySegment::end() const { - return _end; -} - -inline size_t XPhysicalMemorySegment::size() const { - return _end - _start; -} - -inline bool XPhysicalMemorySegment::is_committed() const { - return _committed; -} - -inline void XPhysicalMemorySegment::set_committed(bool committed) { - _committed = committed; -} - -inline bool XPhysicalMemory::is_null() const { - return _segments.length() == 0; -} - -inline int XPhysicalMemory::nsegments() const { - return _segments.length(); -} - -inline const XPhysicalMemorySegment& XPhysicalMemory::segment(int index) const { - return _segments.at(index); -} - -#endif // SHARE_GC_X_XPHYSICALMEMORY_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xReferenceProcessor.cpp b/src/hotspot/share/gc/x/xReferenceProcessor.cpp deleted file mode 100644 index acbb96eaf41e2..0000000000000 --- a/src/hotspot/share/gc/x/xReferenceProcessor.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "classfile/javaClasses.inline.hpp" -#include "gc/shared/referencePolicy.hpp" -#include "gc/shared/referenceProcessorStats.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xReferenceProcessor.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xTracer.inline.hpp" -#include "gc/x/xValue.inline.hpp" -#include "memory/universe.hpp" -#include "runtime/atomic.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/os.hpp" - -static const XStatSubPhase XSubPhaseConcurrentReferencesProcess("Concurrent References Process"); -static const XStatSubPhase XSubPhaseConcurrentReferencesEnqueue("Concurrent References Enqueue"); - -static ReferenceType reference_type(oop reference) { - return InstanceKlass::cast(reference->klass())->reference_type(); -} - -static const char* reference_type_name(ReferenceType type) { - switch (type) { - case REF_SOFT: - return "Soft"; - - case REF_WEAK: - return "Weak"; - - case REF_FINAL: - return "Final"; - - case REF_PHANTOM: - return "Phantom"; - - default: - ShouldNotReachHere(); - return "Unknown"; - } -} - -static volatile oop* reference_referent_addr(oop reference) { - return (volatile oop*)java_lang_ref_Reference::referent_addr_raw(reference); -} - -static oop reference_referent(oop reference) { - return Atomic::load(reference_referent_addr(reference)); -} - -static void reference_clear_referent(oop reference) { - java_lang_ref_Reference::clear_referent_raw(reference); -} - -static oop* reference_discovered_addr(oop reference) { - return (oop*)java_lang_ref_Reference::discovered_addr_raw(reference); -} - -static oop reference_discovered(oop reference) { - return *reference_discovered_addr(reference); -} - -static void reference_set_discovered(oop reference, oop discovered) { - java_lang_ref_Reference::set_discovered_raw(reference, discovered); -} - -static oop* reference_next_addr(oop reference) { - return (oop*)java_lang_ref_Reference::next_addr_raw(reference); -} - -static oop reference_next(oop reference) { - return *reference_next_addr(reference); -} - -static void reference_set_next(oop reference, oop next) { - java_lang_ref_Reference::set_next_raw(reference, next); -} - -static void soft_reference_update_clock() { - const jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; - java_lang_ref_SoftReference::set_clock(now); -} - -XReferenceProcessor::XReferenceProcessor(XWorkers* workers) : - _workers(workers), - _soft_reference_policy(nullptr), - _encountered_count(), - _discovered_count(), - _enqueued_count(), - _discovered_list(nullptr), - _pending_list(nullptr), - _pending_list_tail(_pending_list.addr()) {} - -void XReferenceProcessor::set_soft_reference_policy(bool clear) { - static AlwaysClearPolicy always_clear_policy; - static LRUMaxHeapPolicy lru_max_heap_policy; - - if (clear) { - log_info(gc, ref)("Clearing All SoftReferences"); - _soft_reference_policy = &always_clear_policy; - } else { - _soft_reference_policy = &lru_max_heap_policy; - } - - _soft_reference_policy->setup(); -} - -bool XReferenceProcessor::is_inactive(oop reference, oop referent, ReferenceType type) const { - if (type == REF_FINAL) { - // A FinalReference is inactive if its next field is non-null. An application can't - // call enqueue() or clear() on a FinalReference. - return reference_next(reference) != nullptr; - } else { - // A non-FinalReference is inactive if the referent is null. The referent can only - // be null if the application called Reference.enqueue() or Reference.clear(). - return referent == nullptr; - } -} - -bool XReferenceProcessor::is_strongly_live(oop referent) const { - return XHeap::heap()->is_object_strongly_live(XOop::to_address(referent)); -} - -bool XReferenceProcessor::is_softly_live(oop reference, ReferenceType type) const { - if (type != REF_SOFT) { - // Not a SoftReference - return false; - } - - // Ask SoftReference policy - const jlong clock = java_lang_ref_SoftReference::clock(); - assert(clock != 0, "Clock not initialized"); - assert(_soft_reference_policy != nullptr, "Policy not initialized"); - return !_soft_reference_policy->should_clear_reference(reference, clock); -} - -bool XReferenceProcessor::should_discover(oop reference, ReferenceType type) const { - volatile oop* const referent_addr = reference_referent_addr(reference); - const oop referent = XBarrier::weak_load_barrier_on_oop_field(referent_addr); - - if (is_inactive(reference, referent, type)) { - return false; - } - - if (is_strongly_live(referent)) { - return false; - } - - if (is_softly_live(reference, type)) { - return false; - } - - // PhantomReferences with finalizable marked referents should technically not have - // to be discovered. However, InstanceRefKlass::oop_oop_iterate_ref_processing() - // does not know about the finalizable mark concept, and will therefore mark - // referents in non-discovered PhantomReferences as strongly live. To prevent - // this, we always discover PhantomReferences with finalizable marked referents. - // They will automatically be dropped during the reference processing phase. - return true; -} - -bool XReferenceProcessor::should_drop(oop reference, ReferenceType type) const { - const oop referent = reference_referent(reference); - if (referent == nullptr) { - // Reference has been cleared, by a call to Reference.enqueue() - // or Reference.clear() from the application, which means we - // should drop the reference. - return true; - } - - // Check if the referent is still alive, in which case we should - // drop the reference. - if (type == REF_PHANTOM) { - return XBarrier::is_alive_barrier_on_phantom_oop(referent); - } else { - return XBarrier::is_alive_barrier_on_weak_oop(referent); - } -} - -void XReferenceProcessor::keep_alive(oop reference, ReferenceType type) const { - volatile oop* const p = reference_referent_addr(reference); - if (type == REF_PHANTOM) { - XBarrier::keep_alive_barrier_on_phantom_oop_field(p); - } else { - XBarrier::keep_alive_barrier_on_weak_oop_field(p); - } -} - -void XReferenceProcessor::make_inactive(oop reference, ReferenceType type) const { - if (type == REF_FINAL) { - // Don't clear referent. It is needed by the Finalizer thread to make the call - // to finalize(). A FinalReference is instead made inactive by self-looping the - // next field. An application can't call FinalReference.enqueue(), so there is - // no race to worry about when setting the next field. - assert(reference_next(reference) == nullptr, "Already inactive"); - reference_set_next(reference, reference); - } else { - // Clear referent - reference_clear_referent(reference); - } -} - -void XReferenceProcessor::discover(oop reference, ReferenceType type) { - log_trace(gc, ref)("Discovered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type)); - - // Update statistics - _discovered_count.get()[type]++; - - if (type == REF_FINAL) { - // Mark referent (and its reachable subgraph) finalizable. This avoids - // the problem of later having to mark those objects if the referent is - // still final reachable during processing. - volatile oop* const referent_addr = reference_referent_addr(reference); - XBarrier::mark_barrier_on_oop_field(referent_addr, true /* finalizable */); - } - - // Add reference to discovered list - assert(reference_discovered(reference) == nullptr, "Already discovered"); - oop* const list = _discovered_list.addr(); - reference_set_discovered(reference, *list); - *list = reference; -} - -bool XReferenceProcessor::discover_reference(oop reference, ReferenceType type) { - if (!RegisterReferences) { - // Reference processing disabled - return false; - } - - log_trace(gc, ref)("Encountered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type)); - - // Update statistics - _encountered_count.get()[type]++; - - if (!should_discover(reference, type)) { - // Not discovered - return false; - } - - discover(reference, type); - - // Discovered - return true; -} - -oop XReferenceProcessor::drop(oop reference, ReferenceType type) { - log_trace(gc, ref)("Dropped Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type)); - - // Keep referent alive - keep_alive(reference, type); - - // Unlink and return next in list - const oop next = reference_discovered(reference); - reference_set_discovered(reference, nullptr); - return next; -} - -oop* XReferenceProcessor::keep(oop reference, ReferenceType type) { - log_trace(gc, ref)("Enqueued Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type)); - - // Update statistics - _enqueued_count.get()[type]++; - - // Make reference inactive - make_inactive(reference, type); - - // Return next in list - return reference_discovered_addr(reference); -} - -void XReferenceProcessor::work() { - // Process discovered references - oop* const list = _discovered_list.addr(); - oop* p = list; - - while (*p != nullptr) { - const oop reference = *p; - const ReferenceType type = reference_type(reference); - - if (should_drop(reference, type)) { - *p = drop(reference, type); - } else { - p = keep(reference, type); - } - } - - // Prepend discovered references to internal pending list - if (*list != nullptr) { - *p = Atomic::xchg(_pending_list.addr(), *list); - if (*p == nullptr) { - // First to prepend to list, record tail - _pending_list_tail = p; - } - - // Clear discovered list - *list = nullptr; - } -} - -bool XReferenceProcessor::is_empty() const { - XPerWorkerConstIterator iter(&_discovered_list); - for (const oop* list; iter.next(&list);) { - if (*list != nullptr) { - return false; - } - } - - if (_pending_list.get() != nullptr) { - return false; - } - - return true; -} - -void XReferenceProcessor::reset_statistics() { - assert(is_empty(), "Should be empty"); - - // Reset encountered - XPerWorkerIterator iter_encountered(&_encountered_count); - for (Counters* counters; iter_encountered.next(&counters);) { - for (int i = REF_SOFT; i <= REF_PHANTOM; i++) { - (*counters)[i] = 0; - } - } - - // Reset discovered - XPerWorkerIterator iter_discovered(&_discovered_count); - for (Counters* counters; iter_discovered.next(&counters);) { - for (int i = REF_SOFT; i <= REF_PHANTOM; i++) { - (*counters)[i] = 0; - } - } - - // Reset enqueued - XPerWorkerIterator iter_enqueued(&_enqueued_count); - for (Counters* counters; iter_enqueued.next(&counters);) { - for (int i = REF_SOFT; i <= REF_PHANTOM; i++) { - (*counters)[i] = 0; - } - } -} - -void XReferenceProcessor::collect_statistics() { - Counters encountered = {}; - Counters discovered = {}; - Counters enqueued = {}; - - // Sum encountered - XPerWorkerConstIterator iter_encountered(&_encountered_count); - for (const Counters* counters; iter_encountered.next(&counters);) { - for (int i = REF_SOFT; i <= REF_PHANTOM; i++) { - encountered[i] += (*counters)[i]; - } - } - - // Sum discovered - XPerWorkerConstIterator iter_discovered(&_discovered_count); - for (const Counters* counters; iter_discovered.next(&counters);) { - for (int i = REF_SOFT; i <= REF_PHANTOM; i++) { - discovered[i] += (*counters)[i]; - } - } - - // Sum enqueued - XPerWorkerConstIterator iter_enqueued(&_enqueued_count); - for (const Counters* counters; iter_enqueued.next(&counters);) { - for (int i = REF_SOFT; i <= REF_PHANTOM; i++) { - enqueued[i] += (*counters)[i]; - } - } - - // Update statistics - XStatReferences::set_soft(encountered[REF_SOFT], discovered[REF_SOFT], enqueued[REF_SOFT]); - XStatReferences::set_weak(encountered[REF_WEAK], discovered[REF_WEAK], enqueued[REF_WEAK]); - XStatReferences::set_final(encountered[REF_FINAL], discovered[REF_FINAL], enqueued[REF_FINAL]); - XStatReferences::set_phantom(encountered[REF_PHANTOM], discovered[REF_PHANTOM], enqueued[REF_PHANTOM]); - - // Trace statistics - const ReferenceProcessorStats stats(discovered[REF_SOFT], - discovered[REF_WEAK], - discovered[REF_FINAL], - discovered[REF_PHANTOM]); - XTracer::tracer()->report_gc_reference_stats(stats); -} - -class XReferenceProcessorTask : public XTask { -private: - XReferenceProcessor* const _reference_processor; - -public: - XReferenceProcessorTask(XReferenceProcessor* reference_processor) : - XTask("XReferenceProcessorTask"), - _reference_processor(reference_processor) {} - - virtual void work() { - _reference_processor->work(); - } -}; - -void XReferenceProcessor::process_references() { - XStatTimer timer(XSubPhaseConcurrentReferencesProcess); - - // Process discovered lists - XReferenceProcessorTask task(this); - _workers->run(&task); - - // Update SoftReference clock - soft_reference_update_clock(); - - // Collect, log and trace statistics - collect_statistics(); -} - -void XReferenceProcessor::enqueue_references() { - XStatTimer timer(XSubPhaseConcurrentReferencesEnqueue); - - if (_pending_list.get() == nullptr) { - // Nothing to enqueue - return; - } - - { - // Heap_lock protects external pending list - MonitorLocker ml(Heap_lock); - - // Prepend internal pending list to external pending list - *_pending_list_tail = Universe::swap_reference_pending_list(_pending_list.get()); - - // Notify ReferenceHandler thread - ml.notify_all(); - } - - // Reset internal pending list - _pending_list.set(nullptr); - _pending_list_tail = _pending_list.addr(); -} diff --git a/src/hotspot/share/gc/x/xReferenceProcessor.hpp b/src/hotspot/share/gc/x/xReferenceProcessor.hpp deleted file mode 100644 index 1ff7b14e868d6..0000000000000 --- a/src/hotspot/share/gc/x/xReferenceProcessor.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * 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_GC_X_XREFERENCEPROCESSOR_HPP -#define SHARE_GC_X_XREFERENCEPROCESSOR_HPP - -#include "gc/shared/referenceDiscoverer.hpp" -#include "gc/x/xValue.hpp" - -class ReferencePolicy; -class XWorkers; - -class XReferenceProcessor : public ReferenceDiscoverer { - friend class XReferenceProcessorTask; - -private: - static const size_t reference_type_count = REF_PHANTOM + 1; - typedef size_t Counters[reference_type_count]; - - XWorkers* const _workers; - ReferencePolicy* _soft_reference_policy; - XPerWorker _encountered_count; - XPerWorker _discovered_count; - XPerWorker _enqueued_count; - XPerWorker _discovered_list; - XContended _pending_list; - oop* _pending_list_tail; - - bool is_inactive(oop reference, oop referent, ReferenceType type) const; - bool is_strongly_live(oop referent) const; - bool is_softly_live(oop reference, ReferenceType type) const; - - bool should_discover(oop reference, ReferenceType type) const; - bool should_drop(oop reference, ReferenceType type) const; - void keep_alive(oop reference, ReferenceType type) const; - void make_inactive(oop reference, ReferenceType type) const; - - void discover(oop reference, ReferenceType type); - - oop drop(oop reference, ReferenceType type); - oop* keep(oop reference, ReferenceType type); - - bool is_empty() const; - - void work(); - void collect_statistics(); - -public: - XReferenceProcessor(XWorkers* workers); - - void set_soft_reference_policy(bool clear); - void reset_statistics(); - - virtual bool discover_reference(oop reference, ReferenceType type); - void process_references(); - void enqueue_references(); -}; - -#endif // SHARE_GC_X_XREFERENCEPROCESSOR_HPP diff --git a/src/hotspot/share/gc/x/xRelocate.cpp b/src/hotspot/share/gc/x/xRelocate.cpp deleted file mode 100644 index 645989eaba393..0000000000000 --- a/src/hotspot/share/gc/x/xRelocate.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xAbort.inline.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xForwarding.inline.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xRelocate.hpp" -#include "gc/x/xRelocationSet.inline.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xThread.inline.hpp" -#include "gc/x/xWorkers.hpp" -#include "prims/jvmtiTagMap.hpp" -#include "runtime/atomic.hpp" -#include "utilities/debug.hpp" - -XRelocate::XRelocate(XWorkers* workers) : - _workers(workers) {} - -static uintptr_t forwarding_index(XForwarding* forwarding, uintptr_t from_addr) { - const uintptr_t from_offset = XAddress::offset(from_addr); - return (from_offset - forwarding->start()) >> forwarding->object_alignment_shift(); -} - -static uintptr_t forwarding_find(XForwarding* forwarding, uintptr_t from_addr, XForwardingCursor* cursor) { - const uintptr_t from_index = forwarding_index(forwarding, from_addr); - const XForwardingEntry entry = forwarding->find(from_index, cursor); - return entry.populated() ? XAddress::good(entry.to_offset()) : 0; -} - -static uintptr_t forwarding_insert(XForwarding* forwarding, uintptr_t from_addr, uintptr_t to_addr, XForwardingCursor* cursor) { - const uintptr_t from_index = forwarding_index(forwarding, from_addr); - const uintptr_t to_offset = XAddress::offset(to_addr); - const uintptr_t to_offset_final = forwarding->insert(from_index, to_offset, cursor); - return XAddress::good(to_offset_final); -} - -static uintptr_t relocate_object_inner(XForwarding* forwarding, uintptr_t from_addr, XForwardingCursor* cursor) { - assert(XHeap::heap()->is_object_live(from_addr), "Should be live"); - - // Allocate object - const size_t size = XUtils::object_size(from_addr); - const uintptr_t to_addr = XHeap::heap()->alloc_object_for_relocation(size); - if (to_addr == 0) { - // Allocation failed - return 0; - } - - // Copy object - XUtils::object_copy_disjoint(from_addr, to_addr, size); - - // Insert forwarding - const uintptr_t to_addr_final = forwarding_insert(forwarding, from_addr, to_addr, cursor); - if (to_addr_final != to_addr) { - // Already relocated, try undo allocation - XHeap::heap()->undo_alloc_object_for_relocation(to_addr, size); - } - - return to_addr_final; -} - -uintptr_t XRelocate::relocate_object(XForwarding* forwarding, uintptr_t from_addr) const { - XForwardingCursor cursor; - - // Lookup forwarding - uintptr_t to_addr = forwarding_find(forwarding, from_addr, &cursor); - if (to_addr != 0) { - // Already relocated - return to_addr; - } - - // Relocate object - if (forwarding->retain_page()) { - to_addr = relocate_object_inner(forwarding, from_addr, &cursor); - forwarding->release_page(); - - if (to_addr != 0) { - // Success - return to_addr; - } - - // Failed to relocate object. Wait for a worker thread to complete - // relocation of this page, and then forward the object. If the GC - // aborts the relocation phase before the page has been relocated, - // then wait return false and we just forward the object in-place. - if (!forwarding->wait_page_released()) { - // Forward object in-place - return forwarding_insert(forwarding, from_addr, from_addr, &cursor); - } - } - - // Forward object - return forward_object(forwarding, from_addr); -} - -uintptr_t XRelocate::forward_object(XForwarding* forwarding, uintptr_t from_addr) const { - XForwardingCursor cursor; - const uintptr_t to_addr = forwarding_find(forwarding, from_addr, &cursor); - assert(to_addr != 0, "Should be forwarded"); - return to_addr; -} - -static XPage* alloc_page(const XForwarding* forwarding) { - if (ZStressRelocateInPlace) { - // Simulate failure to allocate a new page. This will - // cause the page being relocated to be relocated in-place. - return nullptr; - } - - XAllocationFlags flags; - flags.set_non_blocking(); - flags.set_worker_relocation(); - return XHeap::heap()->alloc_page(forwarding->type(), forwarding->size(), flags); -} - -static void free_page(XPage* page) { - XHeap::heap()->free_page(page, true /* reclaimed */); -} - -static bool should_free_target_page(XPage* page) { - // Free target page if it is empty. We can end up with an empty target - // page if we allocated a new target page, and then lost the race to - // relocate the remaining objects, leaving the target page empty when - // relocation completed. - return page != nullptr && page->top() == page->start(); -} - -class XRelocateSmallAllocator { -private: - volatile size_t _in_place_count; - -public: - XRelocateSmallAllocator() : - _in_place_count(0) {} - - XPage* alloc_target_page(XForwarding* forwarding, XPage* target) { - XPage* const page = alloc_page(forwarding); - if (page == nullptr) { - Atomic::inc(&_in_place_count); - } - - return page; - } - - void share_target_page(XPage* page) { - // Does nothing - } - - void free_target_page(XPage* page) { - if (should_free_target_page(page)) { - free_page(page); - } - } - - void free_relocated_page(XPage* page) { - free_page(page); - } - - uintptr_t alloc_object(XPage* page, size_t size) const { - return (page != nullptr) ? page->alloc_object(size) : 0; - } - - void undo_alloc_object(XPage* page, uintptr_t addr, size_t size) const { - page->undo_alloc_object(addr, size); - } - - size_t in_place_count() const { - return _in_place_count; - } -}; - -class XRelocateMediumAllocator { -private: - XConditionLock _lock; - XPage* _shared; - bool _in_place; - volatile size_t _in_place_count; - -public: - XRelocateMediumAllocator() : - _lock(), - _shared(nullptr), - _in_place(false), - _in_place_count(0) {} - - ~XRelocateMediumAllocator() { - if (should_free_target_page(_shared)) { - free_page(_shared); - } - } - - XPage* alloc_target_page(XForwarding* forwarding, XPage* target) { - XLocker locker(&_lock); - - // Wait for any ongoing in-place relocation to complete - while (_in_place) { - _lock.wait(); - } - - // Allocate a new page only if the shared page is the same as the - // current target page. The shared page will be different from the - // current target page if another thread shared a page, or allocated - // a new page. - if (_shared == target) { - _shared = alloc_page(forwarding); - if (_shared == nullptr) { - Atomic::inc(&_in_place_count); - _in_place = true; - } - } - - return _shared; - } - - void share_target_page(XPage* page) { - XLocker locker(&_lock); - - assert(_in_place, "Invalid state"); - assert(_shared == nullptr, "Invalid state"); - assert(page != nullptr, "Invalid page"); - - _shared = page; - _in_place = false; - - _lock.notify_all(); - } - - void free_target_page(XPage* page) { - // Does nothing - } - - void free_relocated_page(XPage* page) { - free_page(page); - } - - uintptr_t alloc_object(XPage* page, size_t size) const { - return (page != nullptr) ? page->alloc_object_atomic(size) : 0; - } - - void undo_alloc_object(XPage* page, uintptr_t addr, size_t size) const { - page->undo_alloc_object_atomic(addr, size); - } - - size_t in_place_count() const { - return _in_place_count; - } -}; - -template -class XRelocateClosure : public ObjectClosure { -private: - Allocator* const _allocator; - XForwarding* _forwarding; - XPage* _target; - - bool relocate_object(uintptr_t from_addr) const { - XForwardingCursor cursor; - - // Lookup forwarding - if (forwarding_find(_forwarding, from_addr, &cursor) != 0) { - // Already relocated - return true; - } - - // Allocate object - const size_t size = XUtils::object_size(from_addr); - const uintptr_t to_addr = _allocator->alloc_object(_target, size); - if (to_addr == 0) { - // Allocation failed - return false; - } - - // Copy object. Use conjoint copying if we are relocating - // in-place and the new object overlapps with the old object. - if (_forwarding->in_place() && to_addr + size > from_addr) { - XUtils::object_copy_conjoint(from_addr, to_addr, size); - } else { - XUtils::object_copy_disjoint(from_addr, to_addr, size); - } - - // Insert forwarding - if (forwarding_insert(_forwarding, from_addr, to_addr, &cursor) != to_addr) { - // Already relocated, undo allocation - _allocator->undo_alloc_object(_target, to_addr, size); - } - - return true; - } - - virtual void do_object(oop obj) { - const uintptr_t addr = XOop::to_address(obj); - assert(XHeap::heap()->is_object_live(addr), "Should be live"); - - while (!relocate_object(addr)) { - // Allocate a new target page, or if that fails, use the page being - // relocated as the new target, which will cause it to be relocated - // in-place. - _target = _allocator->alloc_target_page(_forwarding, _target); - if (_target != nullptr) { - continue; - } - - // Claim the page being relocated to block other threads from accessing - // it, or its forwarding table, until it has been released (relocation - // completed). - _target = _forwarding->claim_page(); - _target->reset_for_in_place_relocation(); - _forwarding->set_in_place(); - } - } - -public: - XRelocateClosure(Allocator* allocator) : - _allocator(allocator), - _forwarding(nullptr), - _target(nullptr) {} - - ~XRelocateClosure() { - _allocator->free_target_page(_target); - } - - void do_forwarding(XForwarding* forwarding) { - _forwarding = forwarding; - - // Check if we should abort - if (XAbort::should_abort()) { - _forwarding->abort_page(); - return; - } - - // Relocate objects - _forwarding->object_iterate(this); - - // Verify - if (ZVerifyForwarding) { - _forwarding->verify(); - } - - // Release relocated page - _forwarding->release_page(); - - if (_forwarding->in_place()) { - // The relocated page has been relocated in-place and should not - // be freed. Keep it as target page until it is full, and offer to - // share it with other worker threads. - _allocator->share_target_page(_target); - } else { - // Detach and free relocated page - XPage* const page = _forwarding->detach_page(); - _allocator->free_relocated_page(page); - } - } -}; - -class XRelocateTask : public XTask { -private: - XRelocationSetParallelIterator _iter; - XRelocateSmallAllocator _small_allocator; - XRelocateMediumAllocator _medium_allocator; - - static bool is_small(XForwarding* forwarding) { - return forwarding->type() == XPageTypeSmall; - } - -public: - XRelocateTask(XRelocationSet* relocation_set) : - XTask("XRelocateTask"), - _iter(relocation_set), - _small_allocator(), - _medium_allocator() {} - - ~XRelocateTask() { - XStatRelocation::set_at_relocate_end(_small_allocator.in_place_count(), - _medium_allocator.in_place_count()); - } - - virtual void work() { - XRelocateClosure small(&_small_allocator); - XRelocateClosure medium(&_medium_allocator); - - for (XForwarding* forwarding; _iter.next(&forwarding);) { - if (is_small(forwarding)) { - small.do_forwarding(forwarding); - } else { - medium.do_forwarding(forwarding); - } - } - } -}; - -void XRelocate::relocate(XRelocationSet* relocation_set) { - XRelocateTask task(relocation_set); - _workers->run(&task); -} diff --git a/src/hotspot/share/gc/x/xRelocate.hpp b/src/hotspot/share/gc/x/xRelocate.hpp deleted file mode 100644 index 46ab39240f643..0000000000000 --- a/src/hotspot/share/gc/x/xRelocate.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XRELOCATE_HPP -#define SHARE_GC_X_XRELOCATE_HPP - -#include "gc/x/xRelocationSet.hpp" - -class XForwarding; -class XWorkers; - -class XRelocate { - friend class XRelocateTask; - -private: - XWorkers* const _workers; - - void work(XRelocationSetParallelIterator* iter); - -public: - XRelocate(XWorkers* workers); - - uintptr_t relocate_object(XForwarding* forwarding, uintptr_t from_addr) const; - uintptr_t forward_object(XForwarding* forwarding, uintptr_t from_addr) const; - - void relocate(XRelocationSet* relocation_set); -}; - -#endif // SHARE_GC_X_XRELOCATE_HPP diff --git a/src/hotspot/share/gc/x/xRelocationSet.cpp b/src/hotspot/share/gc/x/xRelocationSet.cpp deleted file mode 100644 index eeb42c4bf328c..0000000000000 --- a/src/hotspot/share/gc/x/xRelocationSet.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2017, 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. - */ - -#include "precompiled.hpp" -#include "gc/x/xArray.inline.hpp" -#include "gc/x/xForwarding.inline.hpp" -#include "gc/x/xForwardingAllocator.inline.hpp" -#include "gc/x/xRelocationSet.inline.hpp" -#include "gc/x/xRelocationSetSelector.inline.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xWorkers.hpp" -#include "runtime/atomic.hpp" -#include "utilities/debug.hpp" - -class XRelocationSetInstallTask : public XTask { -private: - XForwardingAllocator* const _allocator; - XForwarding** _forwardings; - const size_t _nforwardings; - XArrayParallelIterator _small_iter; - XArrayParallelIterator _medium_iter; - volatile size_t _small_next; - volatile size_t _medium_next; - - void install(XForwarding* forwarding, volatile size_t* next) { - const size_t index = Atomic::fetch_then_add(next, 1u); - assert(index < _nforwardings, "Invalid index"); - _forwardings[index] = forwarding; - } - - void install_small(XForwarding* forwarding) { - install(forwarding, &_small_next); - } - - void install_medium(XForwarding* forwarding) { - install(forwarding, &_medium_next); - } - -public: - XRelocationSetInstallTask(XForwardingAllocator* allocator, const XRelocationSetSelector* selector) : - XTask("XRelocationSetInstallTask"), - _allocator(allocator), - _forwardings(nullptr), - _nforwardings(selector->small()->length() + selector->medium()->length()), - _small_iter(selector->small()), - _medium_iter(selector->medium()), - _small_next(selector->medium()->length()), - _medium_next(0) { - - // Reset the allocator to have room for the relocation - // set, all forwardings, and all forwarding entries. - const size_t relocation_set_size = _nforwardings * sizeof(XForwarding*); - const size_t forwardings_size = _nforwardings * sizeof(XForwarding); - const size_t forwarding_entries_size = selector->forwarding_entries() * sizeof(XForwardingEntry); - _allocator->reset(relocation_set_size + forwardings_size + forwarding_entries_size); - - // Allocate relocation set - _forwardings = new (_allocator->alloc(relocation_set_size)) XForwarding*[_nforwardings]; - } - - ~XRelocationSetInstallTask() { - assert(_allocator->is_full(), "Should be full"); - } - - virtual void work() { - // Allocate and install forwardings for small pages - for (XPage* page; _small_iter.next(&page);) { - XForwarding* const forwarding = XForwarding::alloc(_allocator, page); - install_small(forwarding); - } - - // Allocate and install forwardings for medium pages - for (XPage* page; _medium_iter.next(&page);) { - XForwarding* const forwarding = XForwarding::alloc(_allocator, page); - install_medium(forwarding); - } - } - - XForwarding** forwardings() const { - return _forwardings; - } - - size_t nforwardings() const { - return _nforwardings; - } -}; - -XRelocationSet::XRelocationSet(XWorkers* workers) : - _workers(workers), - _allocator(), - _forwardings(nullptr), - _nforwardings(0) {} - -void XRelocationSet::install(const XRelocationSetSelector* selector) { - // Install relocation set - XRelocationSetInstallTask task(&_allocator, selector); - _workers->run(&task); - - _forwardings = task.forwardings(); - _nforwardings = task.nforwardings(); - - // Update statistics - XStatRelocation::set_at_install_relocation_set(_allocator.size()); -} - -void XRelocationSet::reset() { - // Destroy forwardings - XRelocationSetIterator iter(this); - for (XForwarding* forwarding; iter.next(&forwarding);) { - forwarding->~XForwarding(); - } - - _nforwardings = 0; -} diff --git a/src/hotspot/share/gc/x/xRelocationSet.hpp b/src/hotspot/share/gc/x/xRelocationSet.hpp deleted file mode 100644 index bbbb3770516b5..0000000000000 --- a/src/hotspot/share/gc/x/xRelocationSet.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XRELOCATIONSET_HPP -#define SHARE_GC_X_XRELOCATIONSET_HPP - -#include "gc/x/xArray.hpp" -#include "gc/x/xForwardingAllocator.hpp" - -class XForwarding; -class XRelocationSetSelector; -class XWorkers; - -class XRelocationSet { - template friend class XRelocationSetIteratorImpl; - -private: - XWorkers* _workers; - XForwardingAllocator _allocator; - XForwarding** _forwardings; - size_t _nforwardings; - -public: - XRelocationSet(XWorkers* workers); - - void install(const XRelocationSetSelector* selector); - void reset(); -}; - -template -class XRelocationSetIteratorImpl : public XArrayIteratorImpl { -public: - XRelocationSetIteratorImpl(XRelocationSet* relocation_set); -}; - -using XRelocationSetIterator = XRelocationSetIteratorImpl; -using XRelocationSetParallelIterator = XRelocationSetIteratorImpl; - -#endif // SHARE_GC_X_XRELOCATIONSET_HPP diff --git a/src/hotspot/share/gc/x/xRelocationSet.inline.hpp b/src/hotspot/share/gc/x/xRelocationSet.inline.hpp deleted file mode 100644 index 3b76fbce46a2b..0000000000000 --- a/src/hotspot/share/gc/x/xRelocationSet.inline.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XRELOCATIONSET_INLINE_HPP -#define SHARE_GC_X_XRELOCATIONSET_INLINE_HPP - -#include "gc/x/xRelocationSet.hpp" - -#include "gc/x/xArray.inline.hpp" - -template -inline XRelocationSetIteratorImpl::XRelocationSetIteratorImpl(XRelocationSet* relocation_set) : - XArrayIteratorImpl(relocation_set->_forwardings, relocation_set->_nforwardings) {} - -#endif // SHARE_GC_X_XRELOCATIONSET_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xRelocationSetSelector.cpp b/src/hotspot/share/gc/x/xRelocationSetSelector.cpp deleted file mode 100644 index 514e70b874357..0000000000000 --- a/src/hotspot/share/gc/x/xRelocationSetSelector.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xArray.inline.hpp" -#include "gc/x/xForwarding.inline.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xRelocationSetSelector.inline.hpp" -#include "jfr/jfrEvents.hpp" -#include "logging/log.hpp" -#include "runtime/globals.hpp" -#include "utilities/debug.hpp" -#include "utilities/powerOfTwo.hpp" - -XRelocationSetSelectorGroupStats::XRelocationSetSelectorGroupStats() : - _npages_candidates(0), - _total(0), - _live(0), - _empty(0), - _npages_selected(0), - _relocate(0) {} - -XRelocationSetSelectorGroup::XRelocationSetSelectorGroup(const char* name, - uint8_t page_type, - size_t page_size, - size_t object_size_limit) : - _name(name), - _page_type(page_type), - _page_size(page_size), - _object_size_limit(object_size_limit), - _fragmentation_limit(page_size * (ZFragmentationLimit / 100)), - _live_pages(), - _forwarding_entries(0), - _stats() {} - -bool XRelocationSetSelectorGroup::is_disabled() { - // Medium pages are disabled when their page size is zero - return _page_type == XPageTypeMedium && _page_size == 0; -} - -bool XRelocationSetSelectorGroup::is_selectable() { - // Large pages are not selectable - return _page_type != XPageTypeLarge; -} - -void XRelocationSetSelectorGroup::semi_sort() { - // Semi-sort live pages by number of live bytes in ascending order - const size_t npartitions_shift = 11; - const size_t npartitions = (size_t)1 << npartitions_shift; - const size_t partition_size = _page_size >> npartitions_shift; - const size_t partition_size_shift = exact_log2(partition_size); - - // Partition slots/fingers - int partitions[npartitions] = { /* zero initialize */ }; - - // Calculate partition slots - XArrayIterator iter1(&_live_pages); - for (XPage* page; iter1.next(&page);) { - const size_t index = page->live_bytes() >> partition_size_shift; - partitions[index]++; - } - - // Calculate partition fingers - int finger = 0; - for (size_t i = 0; i < npartitions; i++) { - const int slots = partitions[i]; - partitions[i] = finger; - finger += slots; - } - - // Allocate destination array - const int npages = _live_pages.length(); - XArray sorted_live_pages(npages, npages, nullptr); - - // Sort pages into partitions - XArrayIterator iter2(&_live_pages); - for (XPage* page; iter2.next(&page);) { - const size_t index = page->live_bytes() >> partition_size_shift; - const int finger = partitions[index]++; - assert(sorted_live_pages.at(finger) == nullptr, "Invalid finger"); - sorted_live_pages.at_put(finger, page); - } - - _live_pages.swap(&sorted_live_pages); -} - -void XRelocationSetSelectorGroup::select_inner() { - // Calculate the number of pages to relocate by successively including pages in - // a candidate relocation set and calculate the maximum space requirement for - // their live objects. - const int npages = _live_pages.length(); - int selected_from = 0; - int selected_to = 0; - size_t npages_selected = 0; - size_t selected_live_bytes = 0; - size_t selected_forwarding_entries = 0; - size_t from_live_bytes = 0; - size_t from_forwarding_entries = 0; - - semi_sort(); - - for (int from = 1; from <= npages; from++) { - // Add page to the candidate relocation set - XPage* const page = _live_pages.at(from - 1); - from_live_bytes += page->live_bytes(); - from_forwarding_entries += XForwarding::nentries(page); - - // Calculate the maximum number of pages needed by the candidate relocation set. - // By subtracting the object size limit from the pages size we get the maximum - // number of pages that the relocation set is guaranteed to fit in, regardless - // of in which order the objects are relocated. - const int to = ceil((double)(from_live_bytes) / (double)(_page_size - _object_size_limit)); - - // Calculate the relative difference in reclaimable space compared to our - // currently selected final relocation set. If this number is larger than the - // acceptable fragmentation limit, then the current candidate relocation set - // becomes our new final relocation set. - const int diff_from = from - selected_from; - const int diff_to = to - selected_to; - const double diff_reclaimable = 100 - percent_of(diff_to, diff_from); - if (diff_reclaimable > ZFragmentationLimit) { - selected_from = from; - selected_to = to; - selected_live_bytes = from_live_bytes; - npages_selected += 1; - selected_forwarding_entries = from_forwarding_entries; - } - - log_trace(gc, reloc)("Candidate Relocation Set (%s Pages): %d->%d, " - "%.1f%% relative defragmentation, " SIZE_FORMAT " forwarding entries, %s", - _name, from, to, diff_reclaimable, from_forwarding_entries, - (selected_from == from) ? "Selected" : "Rejected"); - } - - // Finalize selection - _live_pages.trunc_to(selected_from); - _forwarding_entries = selected_forwarding_entries; - - // Update statistics - _stats._relocate = selected_live_bytes; - _stats._npages_selected = npages_selected; - - log_trace(gc, reloc)("Relocation Set (%s Pages): %d->%d, %d skipped, " SIZE_FORMAT " forwarding entries", - _name, selected_from, selected_to, npages - selected_from, selected_forwarding_entries); -} - -void XRelocationSetSelectorGroup::select() { - if (is_disabled()) { - return; - } - - EventZRelocationSetGroup event; - - if (is_selectable()) { - select_inner(); - } - - // Send event - event.commit(_page_type, _stats.npages_candidates(), _stats.total(), _stats.empty(), _stats.npages_selected(), _stats.relocate()); -} - -XRelocationSetSelector::XRelocationSetSelector() : - _small("Small", XPageTypeSmall, XPageSizeSmall, XObjectSizeLimitSmall), - _medium("Medium", XPageTypeMedium, XPageSizeMedium, XObjectSizeLimitMedium), - _large("Large", XPageTypeLarge, 0 /* page_size */, 0 /* object_size_limit */), - _empty_pages() {} - -void XRelocationSetSelector::select() { - // Select pages to relocate. The resulting relocation set will be - // sorted such that medium pages comes first, followed by small - // pages. Pages within each page group will be semi-sorted by live - // bytes in ascending order. Relocating pages in this order allows - // us to start reclaiming memory more quickly. - - EventZRelocationSet event; - - // Select pages from each group - _large.select(); - _medium.select(); - _small.select(); - - // Send event - event.commit(total(), empty(), relocate()); -} - -XRelocationSetSelectorStats XRelocationSetSelector::stats() const { - XRelocationSetSelectorStats stats; - stats._small = _small.stats(); - stats._medium = _medium.stats(); - stats._large = _large.stats(); - return stats; -} diff --git a/src/hotspot/share/gc/x/xRelocationSetSelector.hpp b/src/hotspot/share/gc/x/xRelocationSetSelector.hpp deleted file mode 100644 index 75e40eeea8c31..0000000000000 --- a/src/hotspot/share/gc/x/xRelocationSetSelector.hpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XRELOCATIONSETSELECTOR_HPP -#define SHARE_GC_X_XRELOCATIONSETSELECTOR_HPP - -#include "gc/x/xArray.hpp" -#include "memory/allocation.hpp" - -class XPage; - -class XRelocationSetSelectorGroupStats { - friend class XRelocationSetSelectorGroup; - -private: - // Candidate set - size_t _npages_candidates; - size_t _total; - size_t _live; - size_t _empty; - - // Selected set - size_t _npages_selected; - size_t _relocate; - -public: - XRelocationSetSelectorGroupStats(); - - size_t npages_candidates() const; - size_t total() const; - size_t live() const; - size_t empty() const; - - size_t npages_selected() const; - size_t relocate() const; -}; - -class XRelocationSetSelectorStats { - friend class XRelocationSetSelector; - -private: - XRelocationSetSelectorGroupStats _small; - XRelocationSetSelectorGroupStats _medium; - XRelocationSetSelectorGroupStats _large; - -public: - const XRelocationSetSelectorGroupStats& small() const; - const XRelocationSetSelectorGroupStats& medium() const; - const XRelocationSetSelectorGroupStats& large() const; -}; - -class XRelocationSetSelectorGroup { -private: - const char* const _name; - const uint8_t _page_type; - const size_t _page_size; - const size_t _object_size_limit; - const size_t _fragmentation_limit; - XArray _live_pages; - size_t _forwarding_entries; - XRelocationSetSelectorGroupStats _stats; - - bool is_disabled(); - bool is_selectable(); - void semi_sort(); - void select_inner(); - -public: - XRelocationSetSelectorGroup(const char* name, - uint8_t page_type, - size_t page_size, - size_t object_size_limit); - - void register_live_page(XPage* page); - void register_empty_page(XPage* page); - void select(); - - const XArray* selected() const; - size_t forwarding_entries() const; - - const XRelocationSetSelectorGroupStats& stats() const; -}; - -class XRelocationSetSelector : public StackObj { -private: - XRelocationSetSelectorGroup _small; - XRelocationSetSelectorGroup _medium; - XRelocationSetSelectorGroup _large; - XArray _empty_pages; - - size_t total() const; - size_t empty() const; - size_t relocate() const; - -public: - XRelocationSetSelector(); - - void register_live_page(XPage* page); - void register_empty_page(XPage* page); - - bool should_free_empty_pages(int bulk) const; - const XArray* empty_pages() const; - void clear_empty_pages(); - - void select(); - - const XArray* small() const; - const XArray* medium() const; - size_t forwarding_entries() const; - - XRelocationSetSelectorStats stats() const; -}; - -#endif // SHARE_GC_X_XRELOCATIONSETSELECTOR_HPP diff --git a/src/hotspot/share/gc/x/xRelocationSetSelector.inline.hpp b/src/hotspot/share/gc/x/xRelocationSetSelector.inline.hpp deleted file mode 100644 index 25e0ede835de0..0000000000000 --- a/src/hotspot/share/gc/x/xRelocationSetSelector.inline.hpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XRELOCATIONSETSELECTOR_INLINE_HPP -#define SHARE_GC_X_XRELOCATIONSETSELECTOR_INLINE_HPP - -#include "gc/x/xRelocationSetSelector.hpp" - -#include "gc/x/xArray.inline.hpp" -#include "gc/x/xPage.inline.hpp" - -inline size_t XRelocationSetSelectorGroupStats::npages_candidates() const { - return _npages_candidates; -} - -inline size_t XRelocationSetSelectorGroupStats::total() const { - return _total; -} - -inline size_t XRelocationSetSelectorGroupStats::live() const { - return _live; -} - -inline size_t XRelocationSetSelectorGroupStats::empty() const { - return _empty; -} - -inline size_t XRelocationSetSelectorGroupStats::npages_selected() const { - return _npages_selected; -} - -inline size_t XRelocationSetSelectorGroupStats::relocate() const { - return _relocate; -} - -inline const XRelocationSetSelectorGroupStats& XRelocationSetSelectorStats::small() const { - return _small; -} - -inline const XRelocationSetSelectorGroupStats& XRelocationSetSelectorStats::medium() const { - return _medium; -} - -inline const XRelocationSetSelectorGroupStats& XRelocationSetSelectorStats::large() const { - return _large; -} - -inline void XRelocationSetSelectorGroup::register_live_page(XPage* page) { - const uint8_t type = page->type(); - const size_t size = page->size(); - const size_t live = page->live_bytes(); - const size_t garbage = size - live; - - if (garbage > _fragmentation_limit) { - _live_pages.append(page); - } - - _stats._npages_candidates++; - _stats._total += size; - _stats._live += live; -} - -inline void XRelocationSetSelectorGroup::register_empty_page(XPage* page) { - const size_t size = page->size(); - - _stats._npages_candidates++; - _stats._total += size; - _stats._empty += size; -} - -inline const XArray* XRelocationSetSelectorGroup::selected() const { - return &_live_pages; -} - -inline size_t XRelocationSetSelectorGroup::forwarding_entries() const { - return _forwarding_entries; -} - -inline const XRelocationSetSelectorGroupStats& XRelocationSetSelectorGroup::stats() const { - return _stats; -} - -inline void XRelocationSetSelector::register_live_page(XPage* page) { - const uint8_t type = page->type(); - - if (type == XPageTypeSmall) { - _small.register_live_page(page); - } else if (type == XPageTypeMedium) { - _medium.register_live_page(page); - } else { - _large.register_live_page(page); - } -} - -inline void XRelocationSetSelector::register_empty_page(XPage* page) { - const uint8_t type = page->type(); - - if (type == XPageTypeSmall) { - _small.register_empty_page(page); - } else if (type == XPageTypeMedium) { - _medium.register_empty_page(page); - } else { - _large.register_empty_page(page); - } - - _empty_pages.append(page); -} - -inline bool XRelocationSetSelector::should_free_empty_pages(int bulk) const { - return _empty_pages.length() >= bulk && _empty_pages.is_nonempty(); -} - -inline const XArray* XRelocationSetSelector::empty_pages() const { - return &_empty_pages; -} - -inline void XRelocationSetSelector::clear_empty_pages() { - return _empty_pages.clear(); -} - -inline size_t XRelocationSetSelector::total() const { - return _small.stats().total() + _medium.stats().total() + _large.stats().total(); -} - -inline size_t XRelocationSetSelector::empty() const { - return _small.stats().empty() + _medium.stats().empty() + _large.stats().empty(); -} - -inline size_t XRelocationSetSelector::relocate() const { - return _small.stats().relocate() + _medium.stats().relocate() + _large.stats().relocate(); -} - -inline const XArray* XRelocationSetSelector::small() const { - return _small.selected(); -} - -inline const XArray* XRelocationSetSelector::medium() const { - return _medium.selected(); -} - -inline size_t XRelocationSetSelector::forwarding_entries() const { - return _small.forwarding_entries() + _medium.forwarding_entries(); -} - -#endif // SHARE_GC_X_XRELOCATIONSETSELECTOR_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xResurrection.cpp b/src/hotspot/share/gc/x/xResurrection.cpp deleted file mode 100644 index 486f1f8db82e0..0000000000000 --- a/src/hotspot/share/gc/x/xResurrection.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xResurrection.hpp" -#include "runtime/atomic.hpp" -#include "runtime/safepoint.hpp" -#include "utilities/debug.hpp" - -volatile bool XResurrection::_blocked = false; - -void XResurrection::block() { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - _blocked = true; -} - -void XResurrection::unblock() { - // No need for anything stronger than a relaxed store here. - // The preceding handshake makes sure that all non-strong - // oops have already been healed at this point. - Atomic::store(&_blocked, false); -} diff --git a/src/hotspot/share/gc/x/xResurrection.hpp b/src/hotspot/share/gc/x/xResurrection.hpp deleted file mode 100644 index d6ce9820e02fe..0000000000000 --- a/src/hotspot/share/gc/x/xResurrection.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XRESURRECTION_HPP -#define SHARE_GC_X_XRESURRECTION_HPP - -#include "memory/allStatic.hpp" - -class XResurrection : public AllStatic { -private: - static volatile bool _blocked; - -public: - static bool is_blocked(); - static void block(); - static void unblock(); -}; - -#endif // SHARE_GC_X_XRESURRECTION_HPP diff --git a/src/hotspot/share/gc/x/xResurrection.inline.hpp b/src/hotspot/share/gc/x/xResurrection.inline.hpp deleted file mode 100644 index af1993945cc41..0000000000000 --- a/src/hotspot/share/gc/x/xResurrection.inline.hpp +++ /dev/null @@ -1,35 +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. - */ - -#ifndef SHARE_GC_X_XRESURRECTION_INLINE_HPP -#define SHARE_GC_X_XRESURRECTION_INLINE_HPP - -#include "gc/x/xResurrection.hpp" - -#include "runtime/atomic.hpp" - -inline bool XResurrection::is_blocked() { - return Atomic::load(&_blocked); -} - -#endif // SHARE_GC_X_XRESURRECTION_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xRootsIterator.cpp b/src/hotspot/share/gc/x/xRootsIterator.cpp deleted file mode 100644 index 4eaeb8e77c2a2..0000000000000 --- a/src/hotspot/share/gc/x/xRootsIterator.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "classfile/classLoaderDataGraph.hpp" -#include "gc/shared/oopStorageSetParState.inline.hpp" -#include "gc/x/xNMethod.hpp" -#include "gc/x/xNMethodTable.hpp" -#include "gc/x/xRootsIterator.hpp" -#include "gc/x/xStat.hpp" -#include "memory/resourceArea.hpp" -#include "prims/jvmtiTagMap.hpp" -#include "runtime/atomic.hpp" -#include "runtime/globals.hpp" -#include "runtime/safepoint.hpp" -#include "utilities/debug.hpp" - -static const XStatSubPhase XSubPhaseConcurrentRootsOopStorageSet("Concurrent Roots OopStorageSet"); -static const XStatSubPhase XSubPhaseConcurrentRootsClassLoaderDataGraph("Concurrent Roots ClassLoaderDataGraph"); -static const XStatSubPhase XSubPhaseConcurrentRootsJavaThreads("Concurrent Roots JavaThreads"); -static const XStatSubPhase XSubPhaseConcurrentRootsCodeCache("Concurrent Roots CodeCache"); -static const XStatSubPhase XSubPhaseConcurrentWeakRootsOopStorageSet("Concurrent Weak Roots OopStorageSet"); - -template -template -void XParallelApply::apply(ClosureType* cl) { - if (!Atomic::load(&_completed)) { - _iter.apply(cl); - if (!Atomic::load(&_completed)) { - Atomic::store(&_completed, true); - } - } -} - -XStrongOopStorageSetIterator::XStrongOopStorageSetIterator() : - _iter() {} - -void XStrongOopStorageSetIterator::apply(OopClosure* cl) { - XStatTimer timer(XSubPhaseConcurrentRootsOopStorageSet); - _iter.oops_do(cl); -} - -void XStrongCLDsIterator::apply(CLDClosure* cl) { - XStatTimer timer(XSubPhaseConcurrentRootsClassLoaderDataGraph); - ClassLoaderDataGraph::always_strong_cld_do(cl); -} - -XJavaThreadsIterator::XJavaThreadsIterator() : - _threads(), - _claimed(0) {} - -uint XJavaThreadsIterator::claim() { - return Atomic::fetch_then_add(&_claimed, 1u); -} - -void XJavaThreadsIterator::apply(ThreadClosure* cl) { - XStatTimer timer(XSubPhaseConcurrentRootsJavaThreads); - - // The resource mark is needed because interpreter oop maps are - // not reused in concurrent mode. Instead, they are temporary and - // resource allocated. - ResourceMark _rm; - - for (uint i = claim(); i < _threads.length(); i = claim()) { - cl->do_thread(_threads.thread_at(i)); - } -} - -XNMethodsIterator::XNMethodsIterator() { - if (!ClassUnloading) { - XNMethod::nmethods_do_begin(); - } -} - -XNMethodsIterator::~XNMethodsIterator() { - if (!ClassUnloading) { - XNMethod::nmethods_do_end(); - } -} - -void XNMethodsIterator::apply(NMethodClosure* cl) { - XStatTimer timer(XSubPhaseConcurrentRootsCodeCache); - XNMethod::nmethods_do(cl); -} - -XRootsIterator::XRootsIterator(int cld_claim) { - if (cld_claim != ClassLoaderData::_claim_none) { - ClassLoaderDataGraph::verify_claimed_marks_cleared(cld_claim); - } -} - -void XRootsIterator::apply(OopClosure* cl, - CLDClosure* cld_cl, - ThreadClosure* thread_cl, - NMethodClosure* nm_cl) { - _oop_storage_set.apply(cl); - _class_loader_data_graph.apply(cld_cl); - _java_threads.apply(thread_cl); - if (!ClassUnloading) { - _nmethods.apply(nm_cl); - } -} - -XWeakOopStorageSetIterator::XWeakOopStorageSetIterator() : - _iter() {} - -void XWeakOopStorageSetIterator::apply(OopClosure* cl) { - XStatTimer timer(XSubPhaseConcurrentWeakRootsOopStorageSet); - _iter.oops_do(cl); -} - -void XWeakOopStorageSetIterator::report_num_dead() { - _iter.report_num_dead(); -} - -void XWeakRootsIterator::report_num_dead() { - _oop_storage_set.iter().report_num_dead(); -} - -void XWeakRootsIterator::apply(OopClosure* cl) { - _oop_storage_set.apply(cl); -} diff --git a/src/hotspot/share/gc/x/xRootsIterator.hpp b/src/hotspot/share/gc/x/xRootsIterator.hpp deleted file mode 100644 index 9adc4c0293868..0000000000000 --- a/src/hotspot/share/gc/x/xRootsIterator.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XROOTSITERATOR_HPP -#define SHARE_GC_X_XROOTSITERATOR_HPP - -#include "gc/shared/oopStorageSetParState.hpp" -#include "logging/log.hpp" -#include "memory/iterator.hpp" -#include "runtime/threadSMR.hpp" - -template -class XParallelApply { -private: - Iterator _iter; - volatile bool _completed; - -public: - XParallelApply() : - _iter(), - _completed(false) {} - - template - void apply(ClosureType* cl); - - Iterator& iter() { - return _iter; - } -}; - -class XStrongOopStorageSetIterator { - OopStorageSetStrongParState _iter; - -public: - XStrongOopStorageSetIterator(); - - void apply(OopClosure* cl); -}; - -class XStrongCLDsIterator { -public: - void apply(CLDClosure* cl); -}; - -class XJavaThreadsIterator { -private: - ThreadsListHandle _threads; - volatile uint _claimed; - - uint claim(); - -public: - XJavaThreadsIterator(); - - void apply(ThreadClosure* cl); -}; - -class XNMethodsIterator { -public: - XNMethodsIterator(); - ~XNMethodsIterator(); - - void apply(NMethodClosure* cl); -}; - -class XRootsIterator { -private: - XParallelApply _oop_storage_set; - XParallelApply _class_loader_data_graph; - XParallelApply _java_threads; - XParallelApply _nmethods; - -public: - XRootsIterator(int cld_claim); - - void apply(OopClosure* cl, - CLDClosure* cld_cl, - ThreadClosure* thread_cl, - NMethodClosure* nm_cl); -}; - -class XWeakOopStorageSetIterator { -private: - OopStorageSetWeakParState _iter; - -public: - XWeakOopStorageSetIterator(); - - void apply(OopClosure* cl); - - void report_num_dead(); -}; - -class XWeakRootsIterator { -private: - XParallelApply _oop_storage_set; - -public: - void apply(OopClosure* cl); - - void report_num_dead(); -}; - -#endif // SHARE_GC_X_XROOTSITERATOR_HPP diff --git a/src/hotspot/share/gc/x/xRuntimeWorkers.cpp b/src/hotspot/share/gc/x/xRuntimeWorkers.cpp deleted file mode 100644 index d7e4a1262fcbd..0000000000000 --- a/src/hotspot/share/gc/x/xRuntimeWorkers.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xRuntimeWorkers.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xThread.hpp" -#include "runtime/java.hpp" - -class XRuntimeWorkersInitializeTask : public WorkerTask { -private: - const uint _nworkers; - uint _started; - XConditionLock _lock; - -public: - XRuntimeWorkersInitializeTask(uint nworkers) : - WorkerTask("XRuntimeWorkersInitializeTask"), - _nworkers(nworkers), - _started(0), - _lock() {} - - virtual void work(uint worker_id) { - // Wait for all threads to start - XLocker locker(&_lock); - if (++_started == _nworkers) { - // All threads started - _lock.notify_all(); - } else { - while (_started != _nworkers) { - _lock.wait(); - } - } - } -}; - -XRuntimeWorkers::XRuntimeWorkers() : - _workers("RuntimeWorker", - ParallelGCThreads) { - - log_info_p(gc, init)("Runtime Workers: %u", _workers.max_workers()); - - // Initialize worker threads - _workers.initialize_workers(); - _workers.set_active_workers(_workers.max_workers()); - if (_workers.active_workers() != _workers.max_workers()) { - vm_exit_during_initialization("Failed to create XRuntimeWorkers"); - } - - // Execute task to reduce latency in early safepoints, - // which otherwise would have to take on any warmup costs. - XRuntimeWorkersInitializeTask task(_workers.max_workers()); - _workers.run_task(&task); -} - -WorkerThreads* XRuntimeWorkers::workers() { - return &_workers; -} - -void XRuntimeWorkers::threads_do(ThreadClosure* tc) const { - _workers.threads_do(tc); -} diff --git a/src/hotspot/share/gc/x/xRuntimeWorkers.hpp b/src/hotspot/share/gc/x/xRuntimeWorkers.hpp deleted file mode 100644 index 114521d65067e..0000000000000 --- a/src/hotspot/share/gc/x/xRuntimeWorkers.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XRUNTIMEWORKERS_HPP -#define SHARE_GC_X_XRUNTIMEWORKERS_HPP - -#include "gc/shared/workerThread.hpp" - -class ThreadClosure; - -class XRuntimeWorkers { -private: - WorkerThreads _workers; - -public: - XRuntimeWorkers(); - - WorkerThreads* workers(); - - void threads_do(ThreadClosure* tc) const; -}; - -#endif // SHARE_GC_X_XRUNTIMEWORKERS_HPP diff --git a/src/hotspot/share/gc/x/xSafeDelete.hpp b/src/hotspot/share/gc/x/xSafeDelete.hpp deleted file mode 100644 index c41a38ce1873a..0000000000000 --- a/src/hotspot/share/gc/x/xSafeDelete.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 - * 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_GC_X_XSAFEDELETE_HPP -#define SHARE_GC_X_XSAFEDELETE_HPP - -#include "gc/x/xArray.hpp" -#include "gc/x/xLock.hpp" - -#include - -template -class XSafeDeleteImpl { -private: - using ItemT = std::remove_extent_t; - - XLock* _lock; - uint64_t _enabled; - XArray _deferred; - - bool deferred_delete(ItemT* item); - void immediate_delete(ItemT* item); - -public: - XSafeDeleteImpl(XLock* lock); - - void enable_deferred_delete(); - void disable_deferred_delete(); - - void operator()(ItemT* item); -}; - -template -class XSafeDelete : public XSafeDeleteImpl { -private: - XLock _lock; - -public: - XSafeDelete(); -}; - -template -class XSafeDeleteNoLock : public XSafeDeleteImpl { -public: - XSafeDeleteNoLock(); -}; - -#endif // SHARE_GC_X_XSAFEDELETE_HPP diff --git a/src/hotspot/share/gc/x/xSafeDelete.inline.hpp b/src/hotspot/share/gc/x/xSafeDelete.inline.hpp deleted file mode 100644 index 7e428c710e8ee..0000000000000 --- a/src/hotspot/share/gc/x/xSafeDelete.inline.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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 - * 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_GC_X_XSAFEDELETE_INLINE_HPP -#define SHARE_GC_X_XSAFEDELETE_INLINE_HPP - -#include "gc/x/xSafeDelete.hpp" - -#include "gc/x/xArray.inline.hpp" -#include "utilities/debug.hpp" - -#include - -template -XSafeDeleteImpl::XSafeDeleteImpl(XLock* lock) : - _lock(lock), - _enabled(0), - _deferred() {} - -template -bool XSafeDeleteImpl::deferred_delete(ItemT* item) { - XLocker locker(_lock); - if (_enabled > 0) { - _deferred.append(item); - return true; - } - - return false; -} - -template -void XSafeDeleteImpl::immediate_delete(ItemT* item) { - if (std::is_array::value) { - delete [] item; - } else { - delete item; - } -} - -template -void XSafeDeleteImpl::enable_deferred_delete() { - XLocker locker(_lock); - _enabled++; -} - -template -void XSafeDeleteImpl::disable_deferred_delete() { - XArray deferred; - - { - XLocker locker(_lock); - assert(_enabled > 0, "Invalid state"); - if (--_enabled == 0) { - deferred.swap(&_deferred); - } - } - - XArrayIterator iter(&deferred); - for (ItemT* item; iter.next(&item);) { - immediate_delete(item); - } -} - -template -void XSafeDeleteImpl::operator()(ItemT* item) { - if (!deferred_delete(item)) { - immediate_delete(item); - } -} - -template -XSafeDelete::XSafeDelete() : - XSafeDeleteImpl(&_lock), - _lock() {} - -template -XSafeDeleteNoLock::XSafeDeleteNoLock() : - XSafeDeleteImpl(nullptr) {} - -#endif // SHARE_GC_X_XSAFEDELETE_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xServiceability.cpp b/src/hotspot/share/gc/x/xServiceability.cpp deleted file mode 100644 index f3b51b6bb4a35..0000000000000 --- a/src/hotspot/share/gc/x/xServiceability.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/generationCounters.hpp" -#include "gc/shared/hSpaceCounters.hpp" -#include "gc/x/xCollectedHeap.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xServiceability.hpp" -#include "memory/metaspaceCounters.hpp" -#include "runtime/perfData.hpp" - -class XGenerationCounters : public GenerationCounters { -public: - XGenerationCounters(const char* name, int ordinal, int spaces, - size_t min_capacity, size_t max_capacity, size_t curr_capacity) : - GenerationCounters(name, ordinal, spaces, - min_capacity, max_capacity, curr_capacity) {} - - void update_capacity(size_t capacity) { - _current_size->set_value(capacity); - } -}; - -// Class to expose perf counters used by jstat. -class XServiceabilityCounters : public CHeapObj { -private: - XGenerationCounters _generation_counters; - HSpaceCounters _space_counters; - CollectorCounters _collector_counters; - -public: - XServiceabilityCounters(size_t min_capacity, size_t max_capacity); - - CollectorCounters* collector_counters(); - - void update_sizes(); -}; - -XServiceabilityCounters::XServiceabilityCounters(size_t min_capacity, size_t max_capacity) : - // generation.1 - _generation_counters("old" /* name */, - 1 /* ordinal */, - 1 /* spaces */, - min_capacity /* min_capacity */, - max_capacity /* max_capacity */, - min_capacity /* curr_capacity */), - // generation.1.space.0 - _space_counters(_generation_counters.name_space(), - "space" /* name */, - 0 /* ordinal */, - max_capacity /* max_capacity */, - min_capacity /* init_capacity */), - // gc.collector.2 - _collector_counters("Z concurrent cycle pauses" /* name */, - 2 /* ordinal */) {} - -CollectorCounters* XServiceabilityCounters::collector_counters() { - return &_collector_counters; -} - -void XServiceabilityCounters::update_sizes() { - if (UsePerfData) { - const size_t capacity = XHeap::heap()->capacity(); - const size_t used = MIN2(XHeap::heap()->used(), capacity); - - _generation_counters.update_capacity(capacity); - _space_counters.update_capacity(capacity); - _space_counters.update_used(used); - - MetaspaceCounters::update_performance_counters(); - } -} - -XServiceabilityMemoryPool::XServiceabilityMemoryPool(size_t min_capacity, size_t max_capacity) : - CollectedMemoryPool("ZHeap", - min_capacity, - max_capacity, - true /* support_usage_threshold */) {} - -size_t XServiceabilityMemoryPool::used_in_bytes() { - return XHeap::heap()->used(); -} - -MemoryUsage XServiceabilityMemoryPool::get_memory_usage() { - const size_t committed = XHeap::heap()->capacity(); - const size_t used = MIN2(XHeap::heap()->used(), committed); - - return MemoryUsage(initial_size(), used, committed, max_size()); -} - -XServiceabilityMemoryManager::XServiceabilityMemoryManager(const char* name, - XServiceabilityMemoryPool* pool) : - GCMemoryManager(name) { - add_pool(pool); -} - -XServiceability::XServiceability(size_t min_capacity, size_t max_capacity) : - _min_capacity(min_capacity), - _max_capacity(max_capacity), - _memory_pool(_min_capacity, _max_capacity), - _cycle_memory_manager("ZGC Cycles", &_memory_pool), - _pause_memory_manager("ZGC Pauses", &_memory_pool), - _counters(nullptr) {} - -void XServiceability::initialize() { - _counters = new XServiceabilityCounters(_min_capacity, _max_capacity); -} - -MemoryPool* XServiceability::memory_pool() { - return &_memory_pool; -} - -GCMemoryManager* XServiceability::cycle_memory_manager() { - return &_cycle_memory_manager; -} - -GCMemoryManager* XServiceability::pause_memory_manager() { - return &_pause_memory_manager; -} - -XServiceabilityCounters* XServiceability::counters() { - return _counters; -} - -XServiceabilityCycleTracer::XServiceabilityCycleTracer() : - _memory_manager_stats(XHeap::heap()->serviceability_cycle_memory_manager(), - XCollectedHeap::heap()->gc_cause(), - "end of GC cycle", - true /* allMemoryPoolsAffected */, - true /* recordGCBeginTime */, - true /* recordPreGCUsage */, - true /* recordPeakUsage */, - true /* recordPostGCUsage */, - true /* recordAccumulatedGCTime */, - true /* recordGCEndTime */, - true /* countCollection */) {} - -XServiceabilityPauseTracer::XServiceabilityPauseTracer() : - _svc_gc_marker(SvcGCMarker::CONCURRENT), - _counters_stats(XHeap::heap()->serviceability_counters()->collector_counters()), - _memory_manager_stats(XHeap::heap()->serviceability_pause_memory_manager(), - XCollectedHeap::heap()->gc_cause(), - "end of GC pause", - true /* allMemoryPoolsAffected */, - true /* recordGCBeginTime */, - false /* recordPreGCUsage */, - false /* recordPeakUsage */, - false /* recordPostGCUsage */, - true /* recordAccumulatedGCTime */, - true /* recordGCEndTime */, - true /* countCollection */) {} - -XServiceabilityPauseTracer::~XServiceabilityPauseTracer() { - XHeap::heap()->serviceability_counters()->update_sizes(); - MemoryService::track_memory_usage(); -} diff --git a/src/hotspot/share/gc/x/xServiceability.hpp b/src/hotspot/share/gc/x/xServiceability.hpp deleted file mode 100644 index d8e2fc9ba7973..0000000000000 --- a/src/hotspot/share/gc/x/xServiceability.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XSERVICEABILITY_HPP -#define SHARE_GC_X_XSERVICEABILITY_HPP - -#include "gc/shared/collectorCounters.hpp" -#include "gc/shared/gcVMOperations.hpp" -#include "memory/allocation.hpp" -#include "services/memoryManager.hpp" -#include "services/memoryPool.hpp" -#include "services/memoryService.hpp" - -class XServiceabilityCounters; - -class XServiceabilityMemoryPool : public CollectedMemoryPool { -public: - XServiceabilityMemoryPool(size_t min_capacity, size_t max_capacity); - - virtual size_t used_in_bytes(); - virtual MemoryUsage get_memory_usage(); -}; - -class XServiceabilityMemoryManager : public GCMemoryManager { -public: - XServiceabilityMemoryManager(const char* name, - XServiceabilityMemoryPool* pool); -}; - -class XServiceability { -private: - const size_t _min_capacity; - const size_t _max_capacity; - XServiceabilityMemoryPool _memory_pool; - XServiceabilityMemoryManager _cycle_memory_manager; - XServiceabilityMemoryManager _pause_memory_manager; - XServiceabilityCounters* _counters; - -public: - XServiceability(size_t min_capacity, size_t max_capacity); - - void initialize(); - - MemoryPool* memory_pool(); - GCMemoryManager* cycle_memory_manager(); - GCMemoryManager* pause_memory_manager(); - XServiceabilityCounters* counters(); -}; - -class XServiceabilityCycleTracer : public StackObj { -private: - TraceMemoryManagerStats _memory_manager_stats; - -public: - XServiceabilityCycleTracer(); -}; - -class XServiceabilityPauseTracer : public StackObj { -private: - SvcGCMarker _svc_gc_marker; - TraceCollectorStats _counters_stats; - TraceMemoryManagerStats _memory_manager_stats; - -public: - XServiceabilityPauseTracer(); - ~XServiceabilityPauseTracer(); -}; - -#endif // SHARE_GC_X_XSERVICEABILITY_HPP diff --git a/src/hotspot/share/gc/x/xStackWatermark.cpp b/src/hotspot/share/gc/x/xStackWatermark.cpp deleted file mode 100644 index b75113a7529fc..0000000000000 --- a/src/hotspot/share/gc/x/xStackWatermark.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xAddress.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xStackWatermark.hpp" -#include "gc/x/xThread.inline.hpp" -#include "gc/x/xThreadLocalAllocBuffer.hpp" -#include "gc/x/xThreadLocalData.hpp" -#include "gc/x/xVerify.hpp" -#include "memory/resourceArea.inline.hpp" -#include "runtime/frame.inline.hpp" -#include "utilities/preserveException.hpp" - -XOnStackNMethodClosure::XOnStackNMethodClosure() : - _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {} - -void XOnStackNMethodClosure::do_nmethod(nmethod* nm) { - const bool result = _bs_nm->nmethod_entry_barrier(nm); - assert(result, "NMethod on-stack must be alive"); -} - -ThreadLocalAllocStats& XStackWatermark::stats() { - return _stats; -} - -uint32_t XStackWatermark::epoch_id() const { - return *XAddressBadMaskHighOrderBitsAddr; -} - -XStackWatermark::XStackWatermark(JavaThread* jt) : - StackWatermark(jt, StackWatermarkKind::gc, *XAddressBadMaskHighOrderBitsAddr), - _jt_cl(), - _nm_cl(), - _stats() {} - -OopClosure* XStackWatermark::closure_from_context(void* context) { - if (context != nullptr) { - assert(XThread::is_worker(), "Unexpected thread passing in context: " PTR_FORMAT, p2i(context)); - return reinterpret_cast(context); - } else { - return &_jt_cl; - } -} - -void XStackWatermark::start_processing_impl(void* context) { - // Verify the head (no_frames) of the thread is bad before fixing it. - XVerify::verify_thread_head_bad(_jt); - - // Process the non-frame part of the thread - _jt->oops_do_no_frames(closure_from_context(context), &_nm_cl); - XThreadLocalData::do_invisible_root(_jt, XBarrier::load_barrier_on_invisible_root_oop_field); - - // Verification of frames is done after processing of the "head" (no_frames). - // The reason is that the exception oop is fiddled with during frame processing. - XVerify::verify_thread_frames_bad(_jt); - - // Update thread local address bad mask - XThreadLocalData::set_address_bad_mask(_jt, XAddressBadMask); - - // Retire TLAB - if (XGlobalPhase == XPhaseMark) { - XThreadLocalAllocBuffer::retire(_jt, &_stats); - } else { - XThreadLocalAllocBuffer::remap(_jt); - } - - // Publishes the processing start to concurrent threads - StackWatermark::start_processing_impl(context); -} - -void XStackWatermark::process(const frame& fr, RegisterMap& register_map, void* context) { - XVerify::verify_frame_bad(fr, register_map); - fr.oops_do(closure_from_context(context), &_nm_cl, ®ister_map, DerivedPointerIterationMode::_directly); -} diff --git a/src/hotspot/share/gc/x/xStackWatermark.hpp b/src/hotspot/share/gc/x/xStackWatermark.hpp deleted file mode 100644 index 9b73860bed091..0000000000000 --- a/src/hotspot/share/gc/x/xStackWatermark.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XSTACKWATERMARK_HPP -#define SHARE_GC_X_XSTACKWATERMARK_HPP - -#include "gc/shared/barrierSet.hpp" -#include "gc/shared/barrierSetNMethod.hpp" -#include "gc/shared/threadLocalAllocBuffer.hpp" -#include "gc/x/xBarrier.hpp" -#include "memory/allocation.hpp" -#include "memory/iterator.hpp" -#include "oops/oopsHierarchy.hpp" -#include "runtime/stackWatermark.hpp" -#include "utilities/globalDefinitions.hpp" - -class frame; -class JavaThread; - -class XOnStackNMethodClosure : public NMethodClosure { -private: - BarrierSetNMethod* _bs_nm; - - virtual void do_nmethod(nmethod* nm); - -public: - XOnStackNMethodClosure(); -}; - -class XStackWatermark : public StackWatermark { -private: - XLoadBarrierOopClosure _jt_cl; - XOnStackNMethodClosure _nm_cl; - ThreadLocalAllocStats _stats; - - OopClosure* closure_from_context(void* context); - - virtual uint32_t epoch_id() const; - virtual void start_processing_impl(void* context); - virtual void process(const frame& fr, RegisterMap& register_map, void* context); - -public: - XStackWatermark(JavaThread* jt); - - ThreadLocalAllocStats& stats(); -}; - -#endif // SHARE_GC_X_XSTACKWATERMARK_HPP diff --git a/src/hotspot/share/gc/x/xStat.cpp b/src/hotspot/share/gc/x/xStat.cpp deleted file mode 100644 index c445e9513970f..0000000000000 --- a/src/hotspot/share/gc/x/xStat.cpp +++ /dev/null @@ -1,1513 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xAbort.inline.hpp" -#include "gc/x/xCollectedHeap.hpp" -#include "gc/x/xCPU.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xNMethodTable.hpp" -#include "gc/x/xPageAllocator.inline.hpp" -#include "gc/x/xRelocationSetSelector.inline.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xThread.inline.hpp" -#include "gc/x/xTracer.inline.hpp" -#include "gc/x/xUtils.hpp" -#include "memory/metaspaceUtils.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/atomic.hpp" -#include "runtime/os.hpp" -#include "runtime/timer.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" -#include "utilities/ticks.hpp" - -#define XSIZE_FMT SIZE_FORMAT "M(%.0f%%)" -#define XSIZE_ARGS_WITH_MAX(size, max) ((size) / M), (percent_of(size, max)) -#define XSIZE_ARGS(size) XSIZE_ARGS_WITH_MAX(size, XStatHeap::max_capacity()) - -#define XTABLE_ARGS_NA "%9s", "-" -#define XTABLE_ARGS(size) SIZE_FORMAT_W(8) "M (%.0f%%)", \ - ((size) / M), (percent_of(size, XStatHeap::max_capacity())) - -// -// Stat sampler/counter data -// -struct XStatSamplerData { - uint64_t _nsamples; - uint64_t _sum; - uint64_t _max; - - XStatSamplerData() : - _nsamples(0), - _sum(0), - _max(0) {} - - void add(const XStatSamplerData& new_sample) { - _nsamples += new_sample._nsamples; - _sum += new_sample._sum; - _max = MAX2(_max, new_sample._max); - } -}; - -struct XStatCounterData { - uint64_t _counter; - - XStatCounterData() : - _counter(0) {} -}; - -// -// Stat sampler history -// -template -class XStatSamplerHistoryInterval { -private: - size_t _next; - XStatSamplerData _samples[size]; - XStatSamplerData _accumulated; - XStatSamplerData _total; - -public: - XStatSamplerHistoryInterval() : - _next(0), - _samples(), - _accumulated(), - _total() {} - - bool add(const XStatSamplerData& new_sample) { - // Insert sample - const XStatSamplerData old_sample = _samples[_next]; - _samples[_next] = new_sample; - - // Adjust accumulated - _accumulated._nsamples += new_sample._nsamples; - _accumulated._sum += new_sample._sum; - _accumulated._max = MAX2(_accumulated._max, new_sample._max); - - // Adjust total - _total._nsamples -= old_sample._nsamples; - _total._sum -= old_sample._sum; - _total._nsamples += new_sample._nsamples; - _total._sum += new_sample._sum; - if (_total._max < new_sample._max) { - // Found new max - _total._max = new_sample._max; - } else if (_total._max == old_sample._max) { - // Removed old max, reset and find new max - _total._max = 0; - for (size_t i = 0; i < size; i++) { - if (_total._max < _samples[i]._max) { - _total._max = _samples[i]._max; - } - } - } - - // Adjust next - if (++_next == size) { - _next = 0; - - // Clear accumulated - const XStatSamplerData zero; - _accumulated = zero; - - // Became full - return true; - } - - // Not yet full - return false; - } - - const XStatSamplerData& total() const { - return _total; - } - - const XStatSamplerData& accumulated() const { - return _accumulated; - } -}; - -class XStatSamplerHistory : public CHeapObj { -private: - XStatSamplerHistoryInterval<10> _10seconds; - XStatSamplerHistoryInterval<60> _10minutes; - XStatSamplerHistoryInterval<60> _10hours; - XStatSamplerData _total; - - uint64_t avg(uint64_t sum, uint64_t nsamples) const { - return (nsamples > 0) ? sum / nsamples : 0; - } - -public: - XStatSamplerHistory() : - _10seconds(), - _10minutes(), - _10hours(), - _total() {} - - void add(const XStatSamplerData& new_sample) { - if (_10seconds.add(new_sample)) { - if (_10minutes.add(_10seconds.total())) { - if (_10hours.add(_10minutes.total())) { - _total.add(_10hours.total()); - } - } - } - } - - uint64_t avg_10_seconds() const { - const uint64_t sum = _10seconds.total()._sum; - const uint64_t nsamples = _10seconds.total()._nsamples; - return avg(sum, nsamples); - } - - uint64_t avg_10_minutes() const { - const uint64_t sum = _10seconds.accumulated()._sum + - _10minutes.total()._sum; - const uint64_t nsamples = _10seconds.accumulated()._nsamples + - _10minutes.total()._nsamples; - return avg(sum, nsamples); - } - - uint64_t avg_10_hours() const { - const uint64_t sum = _10seconds.accumulated()._sum + - _10minutes.accumulated()._sum + - _10hours.total()._sum; - const uint64_t nsamples = _10seconds.accumulated()._nsamples + - _10minutes.accumulated()._nsamples + - _10hours.total()._nsamples; - return avg(sum, nsamples); - } - - uint64_t avg_total() const { - const uint64_t sum = _10seconds.accumulated()._sum + - _10minutes.accumulated()._sum + - _10hours.accumulated()._sum + - _total._sum; - const uint64_t nsamples = _10seconds.accumulated()._nsamples + - _10minutes.accumulated()._nsamples + - _10hours.accumulated()._nsamples + - _total._nsamples; - return avg(sum, nsamples); - } - - uint64_t max_10_seconds() const { - return _10seconds.total()._max; - } - - uint64_t max_10_minutes() const { - return MAX2(_10seconds.accumulated()._max, - _10minutes.total()._max); - } - - uint64_t max_10_hours() const { - return MAX3(_10seconds.accumulated()._max, - _10minutes.accumulated()._max, - _10hours.total()._max); - } - - uint64_t max_total() const { - return MAX4(_10seconds.accumulated()._max, - _10minutes.accumulated()._max, - _10hours.accumulated()._max, - _total._max); - } -}; - -// -// Stat unit printers -// -void XStatUnitTime(LogTargetHandle log, const XStatSampler& sampler, const XStatSamplerHistory& history) { - log.print(" %10s: %-41s " - "%9.3f / %-9.3f " - "%9.3f / %-9.3f " - "%9.3f / %-9.3f " - "%9.3f / %-9.3f ms", - sampler.group(), - sampler.name(), - TimeHelper::counter_to_millis(history.avg_10_seconds()), - TimeHelper::counter_to_millis(history.max_10_seconds()), - TimeHelper::counter_to_millis(history.avg_10_minutes()), - TimeHelper::counter_to_millis(history.max_10_minutes()), - TimeHelper::counter_to_millis(history.avg_10_hours()), - TimeHelper::counter_to_millis(history.max_10_hours()), - TimeHelper::counter_to_millis(history.avg_total()), - TimeHelper::counter_to_millis(history.max_total())); -} - -void XStatUnitBytes(LogTargetHandle log, const XStatSampler& sampler, const XStatSamplerHistory& history) { - log.print(" %10s: %-41s " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " MB", - sampler.group(), - sampler.name(), - history.avg_10_seconds() / M, - history.max_10_seconds() / M, - history.avg_10_minutes() / M, - history.max_10_minutes() / M, - history.avg_10_hours() / M, - history.max_10_hours() / M, - history.avg_total() / M, - history.max_total() / M); -} - -void XStatUnitThreads(LogTargetHandle log, const XStatSampler& sampler, const XStatSamplerHistory& history) { - log.print(" %10s: %-41s " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " threads", - sampler.group(), - sampler.name(), - history.avg_10_seconds(), - history.max_10_seconds(), - history.avg_10_minutes(), - history.max_10_minutes(), - history.avg_10_hours(), - history.max_10_hours(), - history.avg_total(), - history.max_total()); -} - -void XStatUnitBytesPerSecond(LogTargetHandle log, const XStatSampler& sampler, const XStatSamplerHistory& history) { - log.print(" %10s: %-41s " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " MB/s", - sampler.group(), - sampler.name(), - history.avg_10_seconds() / M, - history.max_10_seconds() / M, - history.avg_10_minutes() / M, - history.max_10_minutes() / M, - history.avg_10_hours() / M, - history.max_10_hours() / M, - history.avg_total() / M, - history.max_total() / M); -} - -void XStatUnitOpsPerSecond(LogTargetHandle log, const XStatSampler& sampler, const XStatSamplerHistory& history) { - log.print(" %10s: %-41s " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " - UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " ops/s", - sampler.group(), - sampler.name(), - history.avg_10_seconds(), - history.max_10_seconds(), - history.avg_10_minutes(), - history.max_10_minutes(), - history.avg_10_hours(), - history.max_10_hours(), - history.avg_total(), - history.max_total()); -} - -// -// Stat value -// -uintptr_t XStatValue::_base = 0; -uint32_t XStatValue::_cpu_offset = 0; - -XStatValue::XStatValue(const char* group, - const char* name, - uint32_t id, - uint32_t size) : - _group(group), - _name(name), - _id(id), - _offset(_cpu_offset) { - assert(_base == 0, "Already initialized"); - _cpu_offset += size; -} - -template -T* XStatValue::get_cpu_local(uint32_t cpu) const { - assert(_base != 0, "Not initialized"); - const uintptr_t cpu_base = _base + (_cpu_offset * cpu); - const uintptr_t value_addr = cpu_base + _offset; - return (T*)value_addr; -} - -void XStatValue::initialize() { - // Finalize and align CPU offset - _cpu_offset = align_up(_cpu_offset, (uint32_t)XCacheLineSize); - - // Allocation aligned memory - const size_t size = _cpu_offset * XCPU::count(); - _base = XUtils::alloc_aligned(XCacheLineSize, size); -} - -const char* XStatValue::group() const { - return _group; -} - -const char* XStatValue::name() const { - return _name; -} - -uint32_t XStatValue::id() const { - return _id; -} - -// -// Stat iterable value -// - -template -XStatIterableValue::XStatIterableValue(const char* group, - const char* name, - uint32_t size) : - XStatValue(group, name, _count++, size), - _next(insert()) {} - -template -T* XStatIterableValue::insert() const { - T* const next = _first; - _first = (T*)this; - return next; -} - -template -void XStatIterableValue::sort() { - T* first_unsorted = _first; - _first = nullptr; - - while (first_unsorted != nullptr) { - T* const value = first_unsorted; - first_unsorted = value->_next; - value->_next = nullptr; - - T** current = &_first; - - while (*current != nullptr) { - // First sort by group, then by name - const int group_cmp = strcmp((*current)->group(), value->group()); - if ((group_cmp > 0) || (group_cmp == 0 && strcmp((*current)->name(), value->name()) > 0)) { - break; - } - - current = &(*current)->_next; - } - value->_next = *current; - *current = value; - } -} - -// -// Stat sampler -// -XStatSampler::XStatSampler(const char* group, const char* name, XStatUnitPrinter printer) : - XStatIterableValue(group, name, sizeof(XStatSamplerData)), - _printer(printer) {} - -XStatSamplerData* XStatSampler::get() const { - return get_cpu_local(XCPU::id()); -} - -XStatSamplerData XStatSampler::collect_and_reset() const { - XStatSamplerData all; - - const uint32_t ncpus = XCPU::count(); - for (uint32_t i = 0; i < ncpus; i++) { - XStatSamplerData* const cpu_data = get_cpu_local(i); - if (cpu_data->_nsamples > 0) { - const uint64_t nsamples = Atomic::xchg(&cpu_data->_nsamples, (uint64_t)0); - const uint64_t sum = Atomic::xchg(&cpu_data->_sum, (uint64_t)0); - const uint64_t max = Atomic::xchg(&cpu_data->_max, (uint64_t)0); - all._nsamples += nsamples; - all._sum += sum; - if (all._max < max) { - all._max = max; - } - } - } - - return all; -} - -XStatUnitPrinter XStatSampler::printer() const { - return _printer; -} - -// -// Stat counter -// -XStatCounter::XStatCounter(const char* group, const char* name, XStatUnitPrinter printer) : - XStatIterableValue(group, name, sizeof(XStatCounterData)), - _sampler(group, name, printer) {} - -XStatCounterData* XStatCounter::get() const { - return get_cpu_local(XCPU::id()); -} - -void XStatCounter::sample_and_reset() const { - uint64_t counter = 0; - - const uint32_t ncpus = XCPU::count(); - for (uint32_t i = 0; i < ncpus; i++) { - XStatCounterData* const cpu_data = get_cpu_local(i); - counter += Atomic::xchg(&cpu_data->_counter, (uint64_t)0); - } - - XStatSample(_sampler, counter); -} - -// -// Stat unsampled counter -// -XStatUnsampledCounter::XStatUnsampledCounter(const char* name) : - XStatIterableValue("Unsampled", name, sizeof(XStatCounterData)) {} - -XStatCounterData* XStatUnsampledCounter::get() const { - return get_cpu_local(XCPU::id()); -} - -XStatCounterData XStatUnsampledCounter::collect_and_reset() const { - XStatCounterData all; - - const uint32_t ncpus = XCPU::count(); - for (uint32_t i = 0; i < ncpus; i++) { - XStatCounterData* const cpu_data = get_cpu_local(i); - all._counter += Atomic::xchg(&cpu_data->_counter, (uint64_t)0); - } - - return all; -} - -// -// Stat MMU (Minimum Mutator Utilization) -// -XStatMMUPause::XStatMMUPause() : - _start(0.0), - _end(0.0) {} - -XStatMMUPause::XStatMMUPause(const Ticks& start, const Ticks& end) : - _start(TimeHelper::counter_to_millis(start.value())), - _end(TimeHelper::counter_to_millis(end.value())) {} - -double XStatMMUPause::end() const { - return _end; -} - -double XStatMMUPause::overlap(double start, double end) const { - const double start_max = MAX2(start, _start); - const double end_min = MIN2(end, _end); - - if (end_min > start_max) { - // Overlap found - return end_min - start_max; - } - - // No overlap - return 0.0; -} - -size_t XStatMMU::_next = 0; -size_t XStatMMU::_npauses = 0; -XStatMMUPause XStatMMU::_pauses[200]; -double XStatMMU::_mmu_2ms = 100.0; -double XStatMMU::_mmu_5ms = 100.0; -double XStatMMU::_mmu_10ms = 100.0; -double XStatMMU::_mmu_20ms = 100.0; -double XStatMMU::_mmu_50ms = 100.0; -double XStatMMU::_mmu_100ms = 100.0; - -const XStatMMUPause& XStatMMU::pause(size_t index) { - return _pauses[(_next - index - 1) % ARRAY_SIZE(_pauses)]; -} - -double XStatMMU::calculate_mmu(double time_slice) { - const double end = pause(0).end(); - const double start = end - time_slice; - double time_paused = 0.0; - - // Find all overlapping pauses - for (size_t i = 0; i < _npauses; i++) { - const double overlap = pause(i).overlap(start, end); - if (overlap == 0.0) { - // No overlap - break; - } - - time_paused += overlap; - } - - // Calculate MMU - const double time_mutator = time_slice - time_paused; - return percent_of(time_mutator, time_slice); -} - -void XStatMMU::register_pause(const Ticks& start, const Ticks& end) { - // Add pause - const size_t index = _next++ % ARRAY_SIZE(_pauses); - _pauses[index] = XStatMMUPause(start, end); - _npauses = MIN2(_npauses + 1, ARRAY_SIZE(_pauses)); - - // Recalculate MMUs - _mmu_2ms = MIN2(_mmu_2ms, calculate_mmu(2)); - _mmu_5ms = MIN2(_mmu_5ms, calculate_mmu(5)); - _mmu_10ms = MIN2(_mmu_10ms, calculate_mmu(10)); - _mmu_20ms = MIN2(_mmu_20ms, calculate_mmu(20)); - _mmu_50ms = MIN2(_mmu_50ms, calculate_mmu(50)); - _mmu_100ms = MIN2(_mmu_100ms, calculate_mmu(100)); -} - -void XStatMMU::print() { - log_info(gc, mmu)("MMU: 2ms/%.1f%%, 5ms/%.1f%%, 10ms/%.1f%%, 20ms/%.1f%%, 50ms/%.1f%%, 100ms/%.1f%%", - _mmu_2ms, _mmu_5ms, _mmu_10ms, _mmu_20ms, _mmu_50ms, _mmu_100ms); -} - -// -// Stat phases -// -ConcurrentGCTimer XStatPhase::_timer; - -XStatPhase::XStatPhase(const char* group, const char* name) : - _sampler(group, name, XStatUnitTime) {} - -void XStatPhase::log_start(LogTargetHandle log, bool thread) const { - if (!log.is_enabled()) { - return; - } - - if (thread) { - ResourceMark rm; - log.print("%s (%s)", name(), Thread::current()->name()); - } else { - log.print("%s", name()); - } -} - -void XStatPhase::log_end(LogTargetHandle log, const Tickspan& duration, bool thread) const { - if (!log.is_enabled()) { - return; - } - - if (thread) { - ResourceMark rm; - log.print("%s (%s) %.3fms", name(), Thread::current()->name(), TimeHelper::counter_to_millis(duration.value())); - } else { - log.print("%s %.3fms", name(), TimeHelper::counter_to_millis(duration.value())); - } -} - -ConcurrentGCTimer* XStatPhase::timer() { - return &_timer; -} - -const char* XStatPhase::name() const { - return _sampler.name(); -} - -XStatPhaseCycle::XStatPhaseCycle(const char* name) : - XStatPhase("Collector", name) {} - -void XStatPhaseCycle::register_start(const Ticks& start) const { - timer()->register_gc_start(start); - - XTracer::tracer()->report_gc_start(XCollectedHeap::heap()->gc_cause(), start); - - XCollectedHeap::heap()->print_heap_before_gc(); - XCollectedHeap::heap()->trace_heap_before_gc(XTracer::tracer()); - - log_info(gc, start)("Garbage Collection (%s)", - GCCause::to_string(XCollectedHeap::heap()->gc_cause())); -} - -void XStatPhaseCycle::register_end(const Ticks& start, const Ticks& end) const { - if (XAbort::should_abort()) { - log_info(gc)("Garbage Collection (%s) Aborted", - GCCause::to_string(XCollectedHeap::heap()->gc_cause())); - return; - } - - timer()->register_gc_end(end); - - XCollectedHeap::heap()->print_heap_after_gc(); - XCollectedHeap::heap()->trace_heap_after_gc(XTracer::tracer()); - - XTracer::tracer()->report_gc_end(end, timer()->time_partitions()); - - const Tickspan duration = end - start; - XStatSample(_sampler, duration.value()); - - XStatLoad::print(); - XStatMMU::print(); - XStatMark::print(); - XStatNMethods::print(); - XStatMetaspace::print(); - XStatReferences::print(); - XStatRelocation::print(); - XStatHeap::print(); - - log_info(gc)("Garbage Collection (%s) " XSIZE_FMT "->" XSIZE_FMT, - GCCause::to_string(XCollectedHeap::heap()->gc_cause()), - XSIZE_ARGS(XStatHeap::used_at_mark_start()), - XSIZE_ARGS(XStatHeap::used_at_relocate_end())); -} - -Tickspan XStatPhasePause::_max; - -XStatPhasePause::XStatPhasePause(const char* name) : - XStatPhase("Phase", name) {} - -const Tickspan& XStatPhasePause::max() { - return _max; -} - -void XStatPhasePause::register_start(const Ticks& start) const { - timer()->register_gc_pause_start(name(), start); - - LogTarget(Debug, gc, phases, start) log; - log_start(log); -} - -void XStatPhasePause::register_end(const Ticks& start, const Ticks& end) const { - timer()->register_gc_pause_end(end); - - const Tickspan duration = end - start; - XStatSample(_sampler, duration.value()); - - // Track max pause time - if (_max < duration) { - _max = duration; - } - - // Track minimum mutator utilization - XStatMMU::register_pause(start, end); - - LogTarget(Info, gc, phases) log; - log_end(log, duration); -} - -XStatPhaseConcurrent::XStatPhaseConcurrent(const char* name) : - XStatPhase("Phase", name) {} - -void XStatPhaseConcurrent::register_start(const Ticks& start) const { - timer()->register_gc_concurrent_start(name(), start); - - LogTarget(Debug, gc, phases, start) log; - log_start(log); -} - -void XStatPhaseConcurrent::register_end(const Ticks& start, const Ticks& end) const { - if (XAbort::should_abort()) { - return; - } - - timer()->register_gc_concurrent_end(end); - - const Tickspan duration = end - start; - XStatSample(_sampler, duration.value()); - - LogTarget(Info, gc, phases) log; - log_end(log, duration); -} - -XStatSubPhase::XStatSubPhase(const char* name) : - XStatPhase("Subphase", name) {} - -void XStatSubPhase::register_start(const Ticks& start) const { - if (XThread::is_worker()) { - LogTarget(Trace, gc, phases, start) log; - log_start(log, true /* thread */); - } else { - LogTarget(Debug, gc, phases, start) log; - log_start(log, false /* thread */); - } -} - -void XStatSubPhase::register_end(const Ticks& start, const Ticks& end) const { - if (XAbort::should_abort()) { - return; - } - - XTracer::tracer()->report_thread_phase(name(), start, end); - - const Tickspan duration = end - start; - XStatSample(_sampler, duration.value()); - - if (XThread::is_worker()) { - LogTarget(Trace, gc, phases) log; - log_end(log, duration, true /* thread */); - } else { - LogTarget(Debug, gc, phases) log; - log_end(log, duration, false /* thread */); - } -} - -XStatCriticalPhase::XStatCriticalPhase(const char* name, bool verbose) : - XStatPhase("Critical", name), - _counter("Critical", name, XStatUnitOpsPerSecond), - _verbose(verbose) {} - -void XStatCriticalPhase::register_start(const Ticks& start) const { - // This is called from sensitive contexts, for example before an allocation stall - // has been resolved. This means we must not access any oops in here since that - // could lead to infinite recursion. Without access to the thread name we can't - // really log anything useful here. -} - -void XStatCriticalPhase::register_end(const Ticks& start, const Ticks& end) const { - XTracer::tracer()->report_thread_phase(name(), start, end); - - const Tickspan duration = end - start; - XStatSample(_sampler, duration.value()); - XStatInc(_counter); - - if (_verbose) { - LogTarget(Info, gc) log; - log_end(log, duration, true /* thread */); - } else { - LogTarget(Debug, gc) log; - log_end(log, duration, true /* thread */); - } -} - -// -// Stat timer -// -THREAD_LOCAL uint32_t XStatTimerDisable::_active = 0; - -// -// Stat sample/inc -// -void XStatSample(const XStatSampler& sampler, uint64_t value) { - XStatSamplerData* const cpu_data = sampler.get(); - Atomic::add(&cpu_data->_nsamples, 1u); - Atomic::add(&cpu_data->_sum, value); - - uint64_t max = cpu_data->_max; - for (;;) { - if (max >= value) { - // Not max - break; - } - - const uint64_t new_max = value; - const uint64_t prev_max = Atomic::cmpxchg(&cpu_data->_max, max, new_max); - if (prev_max == max) { - // Success - break; - } - - // Retry - max = prev_max; - } - - XTracer::tracer()->report_stat_sampler(sampler, value); -} - -void XStatInc(const XStatCounter& counter, uint64_t increment) { - XStatCounterData* const cpu_data = counter.get(); - const uint64_t value = Atomic::add(&cpu_data->_counter, increment); - - XTracer::tracer()->report_stat_counter(counter, increment, value); -} - -void XStatInc(const XStatUnsampledCounter& counter, uint64_t increment) { - XStatCounterData* const cpu_data = counter.get(); - Atomic::add(&cpu_data->_counter, increment); -} - -// -// Stat allocation rate -// -const XStatUnsampledCounter XStatAllocRate::_counter("Allocation Rate"); -TruncatedSeq XStatAllocRate::_samples(XStatAllocRate::sample_hz); -TruncatedSeq XStatAllocRate::_rate(XStatAllocRate::sample_hz); - -const XStatUnsampledCounter& XStatAllocRate::counter() { - return _counter; -} - -uint64_t XStatAllocRate::sample_and_reset() { - const XStatCounterData bytes_per_sample = _counter.collect_and_reset(); - _samples.add(bytes_per_sample._counter); - - const uint64_t bytes_per_second = _samples.sum(); - _rate.add(bytes_per_second); - - return bytes_per_second; -} - -double XStatAllocRate::predict() { - return _rate.predict_next(); -} - -double XStatAllocRate::avg() { - return _rate.avg(); -} - -double XStatAllocRate::sd() { - return _rate.sd(); -} - -// -// Stat thread -// -XStat::XStat() : - _metronome(sample_hz) { - set_name("XStat"); - create_and_start(); -} - -void XStat::sample_and_collect(XStatSamplerHistory* history) const { - // Sample counters - for (const XStatCounter* counter = XStatCounter::first(); counter != nullptr; counter = counter->next()) { - counter->sample_and_reset(); - } - - // Collect samples - for (const XStatSampler* sampler = XStatSampler::first(); sampler != nullptr; sampler = sampler->next()) { - XStatSamplerHistory& sampler_history = history[sampler->id()]; - sampler_history.add(sampler->collect_and_reset()); - } -} - -bool XStat::should_print(LogTargetHandle log) const { - static uint64_t print_at = ZStatisticsInterval; - const uint64_t now = os::elapsedTime(); - - if (now < print_at) { - return false; - } - - print_at = ((now / ZStatisticsInterval) * ZStatisticsInterval) + ZStatisticsInterval; - - return log.is_enabled(); -} - -void XStat::print(LogTargetHandle log, const XStatSamplerHistory* history) const { - // Print - log.print("=== Garbage Collection Statistics ======================================================================================================================="); - log.print(" Last 10s Last 10m Last 10h Total"); - log.print(" Avg / Max Avg / Max Avg / Max Avg / Max"); - - for (const XStatSampler* sampler = XStatSampler::first(); sampler != nullptr; sampler = sampler->next()) { - const XStatSamplerHistory& sampler_history = history[sampler->id()]; - const XStatUnitPrinter printer = sampler->printer(); - printer(log, *sampler, sampler_history); - } - - log.print("========================================================================================================================================================="); -} - -void XStat::run_service() { - XStatSamplerHistory* const history = new XStatSamplerHistory[XStatSampler::count()]; - LogTarget(Info, gc, stats) log; - - XStatSampler::sort(); - - // Main loop - while (_metronome.wait_for_tick()) { - sample_and_collect(history); - if (should_print(log)) { - print(log, history); - } - } - - delete [] history; -} - -void XStat::stop_service() { - _metronome.stop(); -} - -// -// Stat table -// -class XStatTablePrinter { -private: - static const size_t _buffer_size = 256; - - const size_t _column0_width; - const size_t _columnN_width; - char _buffer[_buffer_size]; - -public: - class XColumn { - private: - char* const _buffer; - const size_t _position; - const size_t _width; - const size_t _width_next; - - XColumn next() const { - // Insert space between columns - _buffer[_position + _width] = ' '; - return XColumn(_buffer, _position + _width + 1, _width_next, _width_next); - } - - size_t print(size_t position, const char* fmt, va_list va) { - const int res = jio_vsnprintf(_buffer + position, _buffer_size - position, fmt, va); - if (res < 0) { - return 0; - } - - return (size_t)res; - } - - public: - XColumn(char* buffer, size_t position, size_t width, size_t width_next) : - _buffer(buffer), - _position(position), - _width(width), - _width_next(width_next) {} - - XColumn left(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { - va_list va; - - va_start(va, fmt); - const size_t written = print(_position, fmt, va); - va_end(va); - - if (written < _width) { - // Fill empty space - memset(_buffer + _position + written, ' ', _width - written); - } - - return next(); - } - - XColumn right(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { - va_list va; - - va_start(va, fmt); - const size_t written = print(_position, fmt, va); - va_end(va); - - if (written > _width) { - // Line too long - return fill('?'); - } - - if (written < _width) { - // Short line, move all to right - memmove(_buffer + _position + _width - written, _buffer + _position, written); - - // Fill empty space - memset(_buffer + _position, ' ', _width - written); - } - - return next(); - } - - XColumn center(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { - va_list va; - - va_start(va, fmt); - const size_t written = print(_position, fmt, va); - va_end(va); - - if (written > _width) { - // Line too long - return fill('?'); - } - - if (written < _width) { - // Short line, move all to center - const size_t start_space = (_width - written) / 2; - const size_t end_space = _width - written - start_space; - memmove(_buffer + _position + start_space, _buffer + _position, written); - - // Fill empty spaces - memset(_buffer + _position, ' ', start_space); - memset(_buffer + _position + start_space + written, ' ', end_space); - } - - return next(); - } - - XColumn fill(char filler = ' ') { - memset(_buffer + _position, filler, _width); - return next(); - } - - const char* end() { - _buffer[_position] = '\0'; - return _buffer; - } - }; - -public: - XStatTablePrinter(size_t column0_width, size_t columnN_width) : - _column0_width(column0_width), - _columnN_width(columnN_width) {} - - XColumn operator()() { - return XColumn(_buffer, 0, _column0_width, _columnN_width); - } -}; - -// -// Stat cycle -// -uint64_t XStatCycle::_nwarmup_cycles = 0; -Ticks XStatCycle::_start_of_last; -Ticks XStatCycle::_end_of_last; -NumberSeq XStatCycle::_serial_time(0.7 /* alpha */); -NumberSeq XStatCycle::_parallelizable_time(0.7 /* alpha */); -uint XStatCycle::_last_active_workers = 0; - -void XStatCycle::at_start() { - _start_of_last = Ticks::now(); -} - -void XStatCycle::at_end(GCCause::Cause cause, uint active_workers) { - _end_of_last = Ticks::now(); - - if (cause == GCCause::_z_warmup) { - _nwarmup_cycles++; - } - - _last_active_workers = active_workers; - - // Calculate serial and parallelizable GC cycle times - const double duration = (_end_of_last - _start_of_last).seconds(); - const double workers_duration = XStatWorkers::get_and_reset_duration(); - const double serial_time = duration - workers_duration; - const double parallelizable_time = workers_duration * active_workers; - _serial_time.add(serial_time); - _parallelizable_time.add(parallelizable_time); -} - -bool XStatCycle::is_warm() { - return _nwarmup_cycles >= 3; -} - -uint64_t XStatCycle::nwarmup_cycles() { - return _nwarmup_cycles; -} - -bool XStatCycle::is_time_trustable() { - // The times are considered trustable if we - // have completed at least one warmup cycle. - return _nwarmup_cycles > 0; -} - -const AbsSeq& XStatCycle::serial_time() { - return _serial_time; -} - -const AbsSeq& XStatCycle::parallelizable_time() { - return _parallelizable_time; -} - -uint XStatCycle::last_active_workers() { - return _last_active_workers; -} - -double XStatCycle::time_since_last() { - if (_end_of_last.value() == 0) { - // No end recorded yet, return time since VM start - return os::elapsedTime(); - } - - const Ticks now = Ticks::now(); - const Tickspan time_since_last = now - _end_of_last; - return time_since_last.seconds(); -} - -// -// Stat workers -// -Ticks XStatWorkers::_start_of_last; -Tickspan XStatWorkers::_accumulated_duration; - -void XStatWorkers::at_start() { - _start_of_last = Ticks::now(); -} - -void XStatWorkers::at_end() { - const Ticks now = Ticks::now(); - const Tickspan duration = now - _start_of_last; - _accumulated_duration += duration; -} - -double XStatWorkers::get_and_reset_duration() { - const double duration = _accumulated_duration.seconds(); - const Ticks now = Ticks::now(); - _accumulated_duration = now - now; - return duration; -} - -// -// Stat load -// -void XStatLoad::print() { - double loadavg[3] = {}; - os::loadavg(loadavg, ARRAY_SIZE(loadavg)); - log_info(gc, load)("Load: %.2f/%.2f/%.2f", loadavg[0], loadavg[1], loadavg[2]); -} - -// -// Stat mark -// -size_t XStatMark::_nstripes; -size_t XStatMark::_nproactiveflush; -size_t XStatMark::_nterminateflush; -size_t XStatMark::_ntrycomplete; -size_t XStatMark::_ncontinue; -size_t XStatMark::_mark_stack_usage; - -void XStatMark::set_at_mark_start(size_t nstripes) { - _nstripes = nstripes; -} - -void XStatMark::set_at_mark_end(size_t nproactiveflush, - size_t nterminateflush, - size_t ntrycomplete, - size_t ncontinue) { - _nproactiveflush = nproactiveflush; - _nterminateflush = nterminateflush; - _ntrycomplete = ntrycomplete; - _ncontinue = ncontinue; -} - -void XStatMark::set_at_mark_free(size_t mark_stack_usage) { - _mark_stack_usage = mark_stack_usage; -} - -void XStatMark::print() { - log_info(gc, marking)("Mark: " - SIZE_FORMAT " stripe(s), " - SIZE_FORMAT " proactive flush(es), " - SIZE_FORMAT " terminate flush(es), " - SIZE_FORMAT " completion(s), " - SIZE_FORMAT " continuation(s) ", - _nstripes, - _nproactiveflush, - _nterminateflush, - _ntrycomplete, - _ncontinue); - - log_info(gc, marking)("Mark Stack Usage: " SIZE_FORMAT "M", _mark_stack_usage / M); -} - -// -// Stat relocation -// -XRelocationSetSelectorStats XStatRelocation::_selector_stats; -size_t XStatRelocation::_forwarding_usage; -size_t XStatRelocation::_small_in_place_count; -size_t XStatRelocation::_medium_in_place_count; - -void XStatRelocation::set_at_select_relocation_set(const XRelocationSetSelectorStats& selector_stats) { - _selector_stats = selector_stats; -} - -void XStatRelocation::set_at_install_relocation_set(size_t forwarding_usage) { - _forwarding_usage = forwarding_usage; -} - -void XStatRelocation::set_at_relocate_end(size_t small_in_place_count, size_t medium_in_place_count) { - _small_in_place_count = small_in_place_count; - _medium_in_place_count = medium_in_place_count; -} - -void XStatRelocation::print(const char* name, - const XRelocationSetSelectorGroupStats& selector_group, - size_t in_place_count) { - log_info(gc, reloc)("%s Pages: " SIZE_FORMAT " / " SIZE_FORMAT "M, Empty: " SIZE_FORMAT "M, " - "Relocated: " SIZE_FORMAT "M, In-Place: " SIZE_FORMAT, - name, - selector_group.npages_candidates(), - selector_group.total() / M, - selector_group.empty() / M, - selector_group.relocate() / M, - in_place_count); -} - -void XStatRelocation::print() { - print("Small", _selector_stats.small(), _small_in_place_count); - if (XPageSizeMedium != 0) { - print("Medium", _selector_stats.medium(), _medium_in_place_count); - } - print("Large", _selector_stats.large(), 0 /* in_place_count */); - - log_info(gc, reloc)("Forwarding Usage: " SIZE_FORMAT "M", _forwarding_usage / M); -} - -// -// Stat nmethods -// -void XStatNMethods::print() { - log_info(gc, nmethod)("NMethods: " SIZE_FORMAT " registered, " SIZE_FORMAT " unregistered", - XNMethodTable::registered_nmethods(), - XNMethodTable::unregistered_nmethods()); -} - -// -// Stat metaspace -// -void XStatMetaspace::print() { - MetaspaceCombinedStats stats = MetaspaceUtils::get_combined_statistics(); - log_info(gc, metaspace)("Metaspace: " - SIZE_FORMAT "M used, " - SIZE_FORMAT "M committed, " SIZE_FORMAT "M reserved", - stats.used() / M, - stats.committed() / M, - stats.reserved() / M); -} - -// -// Stat references -// -XStatReferences::XCount XStatReferences::_soft; -XStatReferences::XCount XStatReferences::_weak; -XStatReferences::XCount XStatReferences::_final; -XStatReferences::XCount XStatReferences::_phantom; - -void XStatReferences::set(XCount* count, size_t encountered, size_t discovered, size_t enqueued) { - count->encountered = encountered; - count->discovered = discovered; - count->enqueued = enqueued; -} - -void XStatReferences::set_soft(size_t encountered, size_t discovered, size_t enqueued) { - set(&_soft, encountered, discovered, enqueued); -} - -void XStatReferences::set_weak(size_t encountered, size_t discovered, size_t enqueued) { - set(&_weak, encountered, discovered, enqueued); -} - -void XStatReferences::set_final(size_t encountered, size_t discovered, size_t enqueued) { - set(&_final, encountered, discovered, enqueued); -} - -void XStatReferences::set_phantom(size_t encountered, size_t discovered, size_t enqueued) { - set(&_phantom, encountered, discovered, enqueued); -} - -void XStatReferences::print(const char* name, const XStatReferences::XCount& ref) { - log_info(gc, ref)("%s: " - SIZE_FORMAT " encountered, " - SIZE_FORMAT " discovered, " - SIZE_FORMAT " enqueued", - name, - ref.encountered, - ref.discovered, - ref.enqueued); -} - -void XStatReferences::print() { - print("Soft", _soft); - print("Weak", _weak); - print("Final", _final); - print("Phantom", _phantom); -} - -// -// Stat heap -// -XStatHeap::XAtInitialize XStatHeap::_at_initialize; -XStatHeap::XAtMarkStart XStatHeap::_at_mark_start; -XStatHeap::XAtMarkEnd XStatHeap::_at_mark_end; -XStatHeap::XAtRelocateStart XStatHeap::_at_relocate_start; -XStatHeap::XAtRelocateEnd XStatHeap::_at_relocate_end; - -size_t XStatHeap::capacity_high() { - return MAX4(_at_mark_start.capacity, - _at_mark_end.capacity, - _at_relocate_start.capacity, - _at_relocate_end.capacity); -} - -size_t XStatHeap::capacity_low() { - return MIN4(_at_mark_start.capacity, - _at_mark_end.capacity, - _at_relocate_start.capacity, - _at_relocate_end.capacity); -} - -size_t XStatHeap::free(size_t used) { - return _at_initialize.max_capacity - used; -} - -size_t XStatHeap::allocated(size_t used, size_t reclaimed) { - // The amount of allocated memory between point A and B is used(B) - used(A). - // However, we might also have reclaimed memory between point A and B. This - // means the current amount of used memory must be incremented by the amount - // reclaimed, so that used(B) represents the amount of used memory we would - // have had if we had not reclaimed anything. - return (used + reclaimed) - _at_mark_start.used; -} - -size_t XStatHeap::garbage(size_t reclaimed) { - return _at_mark_end.garbage - reclaimed; -} - -void XStatHeap::set_at_initialize(const XPageAllocatorStats& stats) { - _at_initialize.min_capacity = stats.min_capacity(); - _at_initialize.max_capacity = stats.max_capacity(); -} - -void XStatHeap::set_at_mark_start(const XPageAllocatorStats& stats) { - _at_mark_start.soft_max_capacity = stats.soft_max_capacity(); - _at_mark_start.capacity = stats.capacity(); - _at_mark_start.free = free(stats.used()); - _at_mark_start.used = stats.used(); -} - -void XStatHeap::set_at_mark_end(const XPageAllocatorStats& stats) { - _at_mark_end.capacity = stats.capacity(); - _at_mark_end.free = free(stats.used()); - _at_mark_end.used = stats.used(); - _at_mark_end.allocated = allocated(stats.used(), 0 /* reclaimed */); -} - -void XStatHeap::set_at_select_relocation_set(const XRelocationSetSelectorStats& stats) { - const size_t live = stats.small().live() + stats.medium().live() + stats.large().live(); - _at_mark_end.live = live; - _at_mark_end.garbage = _at_mark_start.used - live; -} - -void XStatHeap::set_at_relocate_start(const XPageAllocatorStats& stats) { - _at_relocate_start.capacity = stats.capacity(); - _at_relocate_start.free = free(stats.used()); - _at_relocate_start.used = stats.used(); - _at_relocate_start.allocated = allocated(stats.used(), stats.reclaimed()); - _at_relocate_start.garbage = garbage(stats.reclaimed()); - _at_relocate_start.reclaimed = stats.reclaimed(); -} - -void XStatHeap::set_at_relocate_end(const XPageAllocatorStats& stats, size_t non_worker_relocated) { - const size_t reclaimed = stats.reclaimed() - MIN2(non_worker_relocated, stats.reclaimed()); - - _at_relocate_end.capacity = stats.capacity(); - _at_relocate_end.capacity_high = capacity_high(); - _at_relocate_end.capacity_low = capacity_low(); - _at_relocate_end.free = free(stats.used()); - _at_relocate_end.free_high = free(stats.used_low()); - _at_relocate_end.free_low = free(stats.used_high()); - _at_relocate_end.used = stats.used(); - _at_relocate_end.used_high = stats.used_high(); - _at_relocate_end.used_low = stats.used_low(); - _at_relocate_end.allocated = allocated(stats.used(), reclaimed); - _at_relocate_end.garbage = garbage(reclaimed); - _at_relocate_end.reclaimed = reclaimed; -} - -size_t XStatHeap::max_capacity() { - return _at_initialize.max_capacity; -} - -size_t XStatHeap::used_at_mark_start() { - return _at_mark_start.used; -} - -size_t XStatHeap::used_at_relocate_end() { - return _at_relocate_end.used; -} - -void XStatHeap::print() { - log_info(gc, heap)("Min Capacity: " - XSIZE_FMT, XSIZE_ARGS(_at_initialize.min_capacity)); - log_info(gc, heap)("Max Capacity: " - XSIZE_FMT, XSIZE_ARGS(_at_initialize.max_capacity)); - log_info(gc, heap)("Soft Max Capacity: " - XSIZE_FMT, XSIZE_ARGS(_at_mark_start.soft_max_capacity)); - - XStatTablePrinter table(10, 18); - log_info(gc, heap)("%s", table() - .fill() - .center("Mark Start") - .center("Mark End") - .center("Relocate Start") - .center("Relocate End") - .center("High") - .center("Low") - .end()); - log_info(gc, heap)("%s", table() - .right("Capacity:") - .left(XTABLE_ARGS(_at_mark_start.capacity)) - .left(XTABLE_ARGS(_at_mark_end.capacity)) - .left(XTABLE_ARGS(_at_relocate_start.capacity)) - .left(XTABLE_ARGS(_at_relocate_end.capacity)) - .left(XTABLE_ARGS(_at_relocate_end.capacity_high)) - .left(XTABLE_ARGS(_at_relocate_end.capacity_low)) - .end()); - log_info(gc, heap)("%s", table() - .right("Free:") - .left(XTABLE_ARGS(_at_mark_start.free)) - .left(XTABLE_ARGS(_at_mark_end.free)) - .left(XTABLE_ARGS(_at_relocate_start.free)) - .left(XTABLE_ARGS(_at_relocate_end.free)) - .left(XTABLE_ARGS(_at_relocate_end.free_high)) - .left(XTABLE_ARGS(_at_relocate_end.free_low)) - .end()); - log_info(gc, heap)("%s", table() - .right("Used:") - .left(XTABLE_ARGS(_at_mark_start.used)) - .left(XTABLE_ARGS(_at_mark_end.used)) - .left(XTABLE_ARGS(_at_relocate_start.used)) - .left(XTABLE_ARGS(_at_relocate_end.used)) - .left(XTABLE_ARGS(_at_relocate_end.used_high)) - .left(XTABLE_ARGS(_at_relocate_end.used_low)) - .end()); - log_info(gc, heap)("%s", table() - .right("Live:") - .left(XTABLE_ARGS_NA) - .left(XTABLE_ARGS(_at_mark_end.live)) - .left(XTABLE_ARGS(_at_mark_end.live /* Same as at mark end */)) - .left(XTABLE_ARGS(_at_mark_end.live /* Same as at mark end */)) - .left(XTABLE_ARGS_NA) - .left(XTABLE_ARGS_NA) - .end()); - log_info(gc, heap)("%s", table() - .right("Allocated:") - .left(XTABLE_ARGS_NA) - .left(XTABLE_ARGS(_at_mark_end.allocated)) - .left(XTABLE_ARGS(_at_relocate_start.allocated)) - .left(XTABLE_ARGS(_at_relocate_end.allocated)) - .left(XTABLE_ARGS_NA) - .left(XTABLE_ARGS_NA) - .end()); - log_info(gc, heap)("%s", table() - .right("Garbage:") - .left(XTABLE_ARGS_NA) - .left(XTABLE_ARGS(_at_mark_end.garbage)) - .left(XTABLE_ARGS(_at_relocate_start.garbage)) - .left(XTABLE_ARGS(_at_relocate_end.garbage)) - .left(XTABLE_ARGS_NA) - .left(XTABLE_ARGS_NA) - .end()); - log_info(gc, heap)("%s", table() - .right("Reclaimed:") - .left(XTABLE_ARGS_NA) - .left(XTABLE_ARGS_NA) - .left(XTABLE_ARGS(_at_relocate_start.reclaimed)) - .left(XTABLE_ARGS(_at_relocate_end.reclaimed)) - .left(XTABLE_ARGS_NA) - .left(XTABLE_ARGS_NA) - .end()); -} diff --git a/src/hotspot/share/gc/x/xStat.hpp b/src/hotspot/share/gc/x/xStat.hpp deleted file mode 100644 index 4983e5fcab69f..0000000000000 --- a/src/hotspot/share/gc/x/xStat.hpp +++ /dev/null @@ -1,578 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XSTAT_HPP -#define SHARE_GC_X_XSTAT_HPP - -#include "gc/shared/concurrentGCThread.hpp" -#include "gc/shared/gcCause.hpp" -#include "gc/shared/gcTimer.hpp" -#include "gc/x/xMetronome.hpp" -#include "logging/logHandle.hpp" -#include "memory/allocation.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/numberSeq.hpp" -#include "utilities/ticks.hpp" - -class XPage; -class XPageAllocatorStats; -class XRelocationSetSelectorGroupStats; -class XRelocationSetSelectorStats; -class XStatSampler; -class XStatSamplerHistory; -struct XStatCounterData; -struct XStatSamplerData; - -// -// Stat unit printers -// -typedef void (*XStatUnitPrinter)(LogTargetHandle log, const XStatSampler&, const XStatSamplerHistory&); - -void XStatUnitTime(LogTargetHandle log, const XStatSampler& sampler, const XStatSamplerHistory& history); -void XStatUnitBytes(LogTargetHandle log, const XStatSampler& sampler, const XStatSamplerHistory& history); -void XStatUnitThreads(LogTargetHandle log, const XStatSampler& sampler, const XStatSamplerHistory& history); -void XStatUnitBytesPerSecond(LogTargetHandle log, const XStatSampler& sampler, const XStatSamplerHistory& history); -void XStatUnitOpsPerSecond(LogTargetHandle log, const XStatSampler& sampler, const XStatSamplerHistory& history); - -// -// Stat value -// -class XStatValue { -private: - static uintptr_t _base; - static uint32_t _cpu_offset; - - const char* const _group; - const char* const _name; - const uint32_t _id; - const uint32_t _offset; - -protected: - XStatValue(const char* group, - const char* name, - uint32_t id, - uint32_t size); - - template T* get_cpu_local(uint32_t cpu) const; - -public: - static void initialize(); - - const char* group() const; - const char* name() const; - uint32_t id() const; -}; - -// -// Stat iterable value -// -template -class XStatIterableValue : public XStatValue { -private: - static uint32_t _count; - static T* _first; - - T* _next; - - T* insert() const; - -protected: - XStatIterableValue(const char* group, - const char* name, - uint32_t size); - -public: - static void sort(); - - static uint32_t count() { - return _count; - } - - static T* first() { - return _first; - } - - T* next() const { - return _next; - } -}; - -template uint32_t XStatIterableValue::_count = 0; -template T* XStatIterableValue::_first = nullptr; - -// -// Stat sampler -// -class XStatSampler : public XStatIterableValue { -private: - const XStatUnitPrinter _printer; - -public: - XStatSampler(const char* group, - const char* name, - XStatUnitPrinter printer); - - XStatSamplerData* get() const; - XStatSamplerData collect_and_reset() const; - - XStatUnitPrinter printer() const; -}; - -// -// Stat counter -// -class XStatCounter : public XStatIterableValue { -private: - const XStatSampler _sampler; - -public: - XStatCounter(const char* group, - const char* name, - XStatUnitPrinter printer); - - XStatCounterData* get() const; - void sample_and_reset() const; -}; - -// -// Stat unsampled counter -// -class XStatUnsampledCounter : public XStatIterableValue { -public: - XStatUnsampledCounter(const char* name); - - XStatCounterData* get() const; - XStatCounterData collect_and_reset() const; -}; - -// -// Stat MMU (Minimum Mutator Utilization) -// -class XStatMMUPause { -private: - double _start; - double _end; - -public: - XStatMMUPause(); - XStatMMUPause(const Ticks& start, const Ticks& end); - - double end() const; - double overlap(double start, double end) const; -}; - -class XStatMMU { -private: - static size_t _next; - static size_t _npauses; - static XStatMMUPause _pauses[200]; // Record the last 200 pauses - - static double _mmu_2ms; - static double _mmu_5ms; - static double _mmu_10ms; - static double _mmu_20ms; - static double _mmu_50ms; - static double _mmu_100ms; - - static const XStatMMUPause& pause(size_t index); - static double calculate_mmu(double time_slice); - -public: - static void register_pause(const Ticks& start, const Ticks& end); - - static void print(); -}; - -// -// Stat phases -// -class XStatPhase { -private: - static ConcurrentGCTimer _timer; - -protected: - const XStatSampler _sampler; - - XStatPhase(const char* group, const char* name); - - void log_start(LogTargetHandle log, bool thread = false) const; - void log_end(LogTargetHandle log, const Tickspan& duration, bool thread = false) const; - -public: - static ConcurrentGCTimer* timer(); - - const char* name() const; - - virtual void register_start(const Ticks& start) const = 0; - virtual void register_end(const Ticks& start, const Ticks& end) const = 0; -}; - -class XStatPhaseCycle : public XStatPhase { -public: - XStatPhaseCycle(const char* name); - - virtual void register_start(const Ticks& start) const; - virtual void register_end(const Ticks& start, const Ticks& end) const; -}; - -class XStatPhasePause : public XStatPhase { -private: - static Tickspan _max; // Max pause time - -public: - XStatPhasePause(const char* name); - - static const Tickspan& max(); - - virtual void register_start(const Ticks& start) const; - virtual void register_end(const Ticks& start, const Ticks& end) const; -}; - -class XStatPhaseConcurrent : public XStatPhase { -public: - XStatPhaseConcurrent(const char* name); - - virtual void register_start(const Ticks& start) const; - virtual void register_end(const Ticks& start, const Ticks& end) const; -}; - -class XStatSubPhase : public XStatPhase { -public: - XStatSubPhase(const char* name); - - virtual void register_start(const Ticks& start) const; - virtual void register_end(const Ticks& start, const Ticks& end) const; -}; - -class XStatCriticalPhase : public XStatPhase { -private: - const XStatCounter _counter; - const bool _verbose; - -public: - XStatCriticalPhase(const char* name, bool verbose = true); - - virtual void register_start(const Ticks& start) const; - virtual void register_end(const Ticks& start, const Ticks& end) const; -}; - -// -// Stat timer -// -class XStatTimerDisable : public StackObj { -private: - static THREAD_LOCAL uint32_t _active; - -public: - XStatTimerDisable() { - _active++; - } - - ~XStatTimerDisable() { - _active--; - } - - static bool is_active() { - return _active > 0; - } -}; - -class XStatTimer : public StackObj { -private: - const bool _enabled; - const XStatPhase& _phase; - const Ticks _start; - -public: - XStatTimer(const XStatPhase& phase) : - _enabled(!XStatTimerDisable::is_active()), - _phase(phase), - _start(Ticks::now()) { - if (_enabled) { - _phase.register_start(_start); - } - } - - ~XStatTimer() { - if (_enabled) { - const Ticks end = Ticks::now(); - _phase.register_end(_start, end); - } - } -}; - -// -// Stat sample/increment -// -void XStatSample(const XStatSampler& sampler, uint64_t value); -void XStatInc(const XStatCounter& counter, uint64_t increment = 1); -void XStatInc(const XStatUnsampledCounter& counter, uint64_t increment = 1); - -// -// Stat allocation rate -// -class XStatAllocRate : public AllStatic { -private: - static const XStatUnsampledCounter _counter; - static TruncatedSeq _samples; - static TruncatedSeq _rate; - -public: - static const uint64_t sample_hz = 10; - - static const XStatUnsampledCounter& counter(); - static uint64_t sample_and_reset(); - - static double predict(); - static double avg(); - static double sd(); -}; - -// -// Stat thread -// -class XStat : public ConcurrentGCThread { -private: - static const uint64_t sample_hz = 1; - - XMetronome _metronome; - - void sample_and_collect(XStatSamplerHistory* history) const; - bool should_print(LogTargetHandle log) const; - void print(LogTargetHandle log, const XStatSamplerHistory* history) const; - -protected: - virtual void run_service(); - virtual void stop_service(); - -public: - XStat(); -}; - -// -// Stat cycle -// -class XStatCycle : public AllStatic { -private: - static uint64_t _nwarmup_cycles; - static Ticks _start_of_last; - static Ticks _end_of_last; - static NumberSeq _serial_time; - static NumberSeq _parallelizable_time; - static uint _last_active_workers; - -public: - static void at_start(); - static void at_end(GCCause::Cause cause, uint active_workers); - - static bool is_warm(); - static uint64_t nwarmup_cycles(); - - static bool is_time_trustable(); - static const AbsSeq& serial_time(); - static const AbsSeq& parallelizable_time(); - - static uint last_active_workers(); - - static double time_since_last(); -}; - -// -// Stat workers -// -class XStatWorkers : public AllStatic { -private: - static Ticks _start_of_last; - static Tickspan _accumulated_duration; - -public: - static void at_start(); - static void at_end(); - - static double get_and_reset_duration(); -}; - -// -// Stat load -// -class XStatLoad : public AllStatic { -public: - static void print(); -}; - -// -// Stat mark -// -class XStatMark : public AllStatic { -private: - static size_t _nstripes; - static size_t _nproactiveflush; - static size_t _nterminateflush; - static size_t _ntrycomplete; - static size_t _ncontinue; - static size_t _mark_stack_usage; - -public: - static void set_at_mark_start(size_t nstripes); - static void set_at_mark_end(size_t nproactiveflush, - size_t nterminateflush, - size_t ntrycomplete, - size_t ncontinue); - static void set_at_mark_free(size_t mark_stack_usage); - - static void print(); -}; - -// -// Stat relocation -// -class XStatRelocation : public AllStatic { -private: - static XRelocationSetSelectorStats _selector_stats; - static size_t _forwarding_usage; - static size_t _small_in_place_count; - static size_t _medium_in_place_count; - - static void print(const char* name, - const XRelocationSetSelectorGroupStats& selector_group, - size_t in_place_count); - -public: - static void set_at_select_relocation_set(const XRelocationSetSelectorStats& selector_stats); - static void set_at_install_relocation_set(size_t forwarding_usage); - static void set_at_relocate_end(size_t small_in_place_count, size_t medium_in_place_count); - - static void print(); -}; - -// -// Stat nmethods -// -class XStatNMethods : public AllStatic { -public: - static void print(); -}; - -// -// Stat metaspace -// -class XStatMetaspace : public AllStatic { -public: - static void print(); -}; - -// -// Stat references -// -class XStatReferences : public AllStatic { -private: - static struct XCount { - size_t encountered; - size_t discovered; - size_t enqueued; - } _soft, _weak, _final, _phantom; - - static void set(XCount* count, size_t encountered, size_t discovered, size_t enqueued); - static void print(const char* name, const XCount& ref); - -public: - static void set_soft(size_t encountered, size_t discovered, size_t enqueued); - static void set_weak(size_t encountered, size_t discovered, size_t enqueued); - static void set_final(size_t encountered, size_t discovered, size_t enqueued); - static void set_phantom(size_t encountered, size_t discovered, size_t enqueued); - - static void print(); -}; - -// -// Stat heap -// -class XStatHeap : public AllStatic { -private: - static struct XAtInitialize { - size_t min_capacity; - size_t max_capacity; - } _at_initialize; - - static struct XAtMarkStart { - size_t soft_max_capacity; - size_t capacity; - size_t free; - size_t used; - } _at_mark_start; - - static struct XAtMarkEnd { - size_t capacity; - size_t free; - size_t used; - size_t live; - size_t allocated; - size_t garbage; - } _at_mark_end; - - static struct XAtRelocateStart { - size_t capacity; - size_t free; - size_t used; - size_t allocated; - size_t garbage; - size_t reclaimed; - } _at_relocate_start; - - static struct XAtRelocateEnd { - size_t capacity; - size_t capacity_high; - size_t capacity_low; - size_t free; - size_t free_high; - size_t free_low; - size_t used; - size_t used_high; - size_t used_low; - size_t allocated; - size_t garbage; - size_t reclaimed; - } _at_relocate_end; - - static size_t capacity_high(); - static size_t capacity_low(); - static size_t free(size_t used); - static size_t allocated(size_t used, size_t reclaimed); - static size_t garbage(size_t reclaimed); - -public: - static void set_at_initialize(const XPageAllocatorStats& stats); - static void set_at_mark_start(const XPageAllocatorStats& stats); - static void set_at_mark_end(const XPageAllocatorStats& stats); - static void set_at_select_relocation_set(const XRelocationSetSelectorStats& stats); - static void set_at_relocate_start(const XPageAllocatorStats& stats); - static void set_at_relocate_end(const XPageAllocatorStats& stats, size_t non_worker_relocated); - - static size_t max_capacity(); - static size_t used_at_mark_start(); - static size_t used_at_relocate_end(); - - static void print(); -}; - -#endif // SHARE_GC_X_XSTAT_HPP diff --git a/src/hotspot/share/gc/x/xTask.cpp b/src/hotspot/share/gc/x/xTask.cpp deleted file mode 100644 index 25f6d12f33dbb..0000000000000 --- a/src/hotspot/share/gc/x/xTask.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xThread.hpp" - -XTask::Task::Task(XTask* task, const char* name) : - WorkerTask(name), - _task(task) {} - -void XTask::Task::work(uint worker_id) { - XThread::set_worker_id(worker_id); - _task->work(); - XThread::clear_worker_id(); -} - -XTask::XTask(const char* name) : - _worker_task(this, name) {} - -const char* XTask::name() const { - return _worker_task.name(); -} - -WorkerTask* XTask::worker_task() { - return &_worker_task; -} diff --git a/src/hotspot/share/gc/x/xTask.hpp b/src/hotspot/share/gc/x/xTask.hpp deleted file mode 100644 index 08adaed83e596..0000000000000 --- a/src/hotspot/share/gc/x/xTask.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XTASK_HPP -#define SHARE_GC_X_XTASK_HPP - -#include "gc/shared/workerThread.hpp" -#include "memory/allocation.hpp" - -class XTask : public StackObj { -private: - class Task : public WorkerTask { - private: - XTask* const _task; - - public: - Task(XTask* task, const char* name); - - virtual void work(uint worker_id); - }; - - Task _worker_task; - -public: - XTask(const char* name); - - const char* name() const; - WorkerTask* worker_task(); - - virtual void work() = 0; -}; - -#endif // SHARE_GC_X_XTASK_HPP diff --git a/src/hotspot/share/gc/x/xThread.cpp b/src/hotspot/share/gc/x/xThread.cpp deleted file mode 100644 index fb9785690cff3..0000000000000 --- a/src/hotspot/share/gc/x/xThread.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xThread.inline.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/nonJavaThread.hpp" -#include "utilities/debug.hpp" - -THREAD_LOCAL bool XThread::_initialized; -THREAD_LOCAL uintptr_t XThread::_id; -THREAD_LOCAL bool XThread::_is_vm; -THREAD_LOCAL bool XThread::_is_java; -THREAD_LOCAL bool XThread::_is_worker; -THREAD_LOCAL uint XThread::_worker_id; - -void XThread::initialize() { - assert(!_initialized, "Already initialized"); - const Thread* const thread = Thread::current(); - _initialized = true; - _id = (uintptr_t)thread; - _is_vm = thread->is_VM_thread(); - _is_java = thread->is_Java_thread(); - _is_worker = false; - _worker_id = (uint)-1; -} - -const char* XThread::name() { - const Thread* const thread = Thread::current(); - if (thread->is_Named_thread()) { - const NamedThread* const named = (const NamedThread*)thread; - return named->name(); - } else if (thread->is_Java_thread()) { - return "Java"; - } - - return "Unknown"; -} - -void XThread::set_worker() { - ensure_initialized(); - _is_worker = true; -} - -bool XThread::has_worker_id() { - return _initialized && - _is_worker && - _worker_id != (uint)-1; -} - -void XThread::set_worker_id(uint worker_id) { - ensure_initialized(); - assert(!has_worker_id(), "Worker id already initialized"); - _worker_id = worker_id; -} - -void XThread::clear_worker_id() { - assert(has_worker_id(), "Worker id not initialized"); - _worker_id = (uint)-1; -} diff --git a/src/hotspot/share/gc/x/xThread.hpp b/src/hotspot/share/gc/x/xThread.hpp deleted file mode 100644 index 24df6ce1ca24d..0000000000000 --- a/src/hotspot/share/gc/x/xThread.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XTHREAD_HPP -#define SHARE_GC_X_XTHREAD_HPP - -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" - -class XThread : public AllStatic { - friend class XTask; - friend class XWorkersInitializeTask; - friend class XRuntimeWorkersInitializeTask; - -private: - static THREAD_LOCAL bool _initialized; - static THREAD_LOCAL uintptr_t _id; - static THREAD_LOCAL bool _is_vm; - static THREAD_LOCAL bool _is_java; - static THREAD_LOCAL bool _is_worker; - static THREAD_LOCAL uint _worker_id; - - static void initialize(); - static void ensure_initialized(); - - static void set_worker(); - - static bool has_worker_id(); - static void set_worker_id(uint worker_id); - static void clear_worker_id(); - -public: - static const char* name(); - static uintptr_t id(); - static bool is_vm(); - static bool is_java(); - static bool is_worker(); - static uint worker_id(); -}; - -#endif // SHARE_GC_X_XTHREAD_HPP diff --git a/src/hotspot/share/gc/x/xThread.inline.hpp b/src/hotspot/share/gc/x/xThread.inline.hpp deleted file mode 100644 index eb6ff63e5f7be..0000000000000 --- a/src/hotspot/share/gc/x/xThread.inline.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XTHREAD_INLINE_HPP -#define SHARE_GC_X_XTHREAD_INLINE_HPP - -#include "gc/x/xThread.hpp" - -#include "utilities/debug.hpp" - -inline void XThread::ensure_initialized() { - if (!_initialized) { - initialize(); - } -} - -inline uintptr_t XThread::id() { - ensure_initialized(); - return _id; -} - -inline bool XThread::is_vm() { - ensure_initialized(); - return _is_vm; -} - -inline bool XThread::is_java() { - ensure_initialized(); - return _is_java; -} - -inline bool XThread::is_worker() { - ensure_initialized(); - return _is_worker; -} - -inline uint XThread::worker_id() { - assert(has_worker_id(), "Worker id not initialized"); - return _worker_id; -} - -#endif // SHARE_GC_X_XTHREAD_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xThreadLocalAllocBuffer.cpp b/src/hotspot/share/gc/x/xThreadLocalAllocBuffer.cpp deleted file mode 100644 index 7dc0a128b64f0..0000000000000 --- a/src/hotspot/share/gc/x/xThreadLocalAllocBuffer.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/tlab_globals.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xStackWatermark.hpp" -#include "gc/x/xThreadLocalAllocBuffer.hpp" -#include "gc/x/xValue.inline.hpp" -#include "runtime/globals.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/stackWatermarkSet.inline.hpp" - -XPerWorker* XThreadLocalAllocBuffer::_stats = nullptr; - -void XThreadLocalAllocBuffer::initialize() { - if (UseTLAB) { - assert(_stats == nullptr, "Already initialized"); - _stats = new XPerWorker(); - reset_statistics(); - } -} - -void XThreadLocalAllocBuffer::reset_statistics() { - if (UseTLAB) { - XPerWorkerIterator iter(_stats); - for (ThreadLocalAllocStats* stats; iter.next(&stats);) { - stats->reset(); - } - } -} - -void XThreadLocalAllocBuffer::publish_statistics() { - if (UseTLAB) { - ThreadLocalAllocStats total; - - XPerWorkerIterator iter(_stats); - for (ThreadLocalAllocStats* stats; iter.next(&stats);) { - total.update(*stats); - } - - total.publish(); - } -} - -static void fixup_address(HeapWord** p) { - *p = (HeapWord*)XAddress::good_or_null((uintptr_t)*p); -} - -void XThreadLocalAllocBuffer::retire(JavaThread* thread, ThreadLocalAllocStats* stats) { - if (UseTLAB) { - stats->reset(); - thread->tlab().addresses_do(fixup_address); - thread->tlab().retire(stats); - if (ResizeTLAB) { - thread->tlab().resize(); - } - } -} - -void XThreadLocalAllocBuffer::remap(JavaThread* thread) { - if (UseTLAB) { - thread->tlab().addresses_do(fixup_address); - } -} - -void XThreadLocalAllocBuffer::update_stats(JavaThread* thread) { - if (UseTLAB) { - XStackWatermark* const watermark = StackWatermarkSet::get(thread, StackWatermarkKind::gc); - _stats->addr()->update(watermark->stats()); - } -} diff --git a/src/hotspot/share/gc/x/xThreadLocalAllocBuffer.hpp b/src/hotspot/share/gc/x/xThreadLocalAllocBuffer.hpp deleted file mode 100644 index 521f4da19096a..0000000000000 --- a/src/hotspot/share/gc/x/xThreadLocalAllocBuffer.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XTHREADLOCALALLOCBUFFER_HPP -#define SHARE_GC_X_XTHREADLOCALALLOCBUFFER_HPP - -#include "gc/shared/threadLocalAllocBuffer.hpp" -#include "gc/x/xValue.hpp" -#include "memory/allStatic.hpp" - -class JavaThread; - -class XThreadLocalAllocBuffer : public AllStatic { -private: - static XPerWorker* _stats; - -public: - static void initialize(); - - static void reset_statistics(); - static void publish_statistics(); - - static void retire(JavaThread* thread, ThreadLocalAllocStats* stats); - static void remap(JavaThread* thread); - static void update_stats(JavaThread* thread); -}; - -#endif // SHARE_GC_X_XTHREADLOCALALLOCBUFFER_HPP diff --git a/src/hotspot/share/gc/x/xThreadLocalData.hpp b/src/hotspot/share/gc/x/xThreadLocalData.hpp deleted file mode 100644 index adc72f6ca76d8..0000000000000 --- a/src/hotspot/share/gc/x/xThreadLocalData.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XTHREADLOCALDATA_HPP -#define SHARE_GC_X_XTHREADLOCALDATA_HPP - -#include "gc/x/xMarkStack.hpp" -#include "gc/x/xGlobals.hpp" -#include "runtime/javaThread.hpp" -#include "utilities/debug.hpp" -#include "utilities/sizes.hpp" - -class XThreadLocalData { -private: - uintptr_t _address_bad_mask; - XMarkThreadLocalStacks _stacks; - oop* _invisible_root; - - XThreadLocalData() : - _address_bad_mask(0), - _stacks(), - _invisible_root(nullptr) {} - - static XThreadLocalData* data(Thread* thread) { - return thread->gc_data(); - } - -public: - static void create(Thread* thread) { - new (data(thread)) XThreadLocalData(); - } - - static void destroy(Thread* thread) { - data(thread)->~XThreadLocalData(); - } - - static void set_address_bad_mask(Thread* thread, uintptr_t mask) { - data(thread)->_address_bad_mask = mask; - } - - static XMarkThreadLocalStacks* stacks(Thread* thread) { - return &data(thread)->_stacks; - } - - static void set_invisible_root(Thread* thread, oop* root) { - assert(data(thread)->_invisible_root == nullptr, "Already set"); - data(thread)->_invisible_root = root; - } - - static void clear_invisible_root(Thread* thread) { - assert(data(thread)->_invisible_root != nullptr, "Should be set"); - data(thread)->_invisible_root = nullptr; - } - - template - static void do_invisible_root(Thread* thread, T f) { - if (data(thread)->_invisible_root != nullptr) { - f(data(thread)->_invisible_root); - } - } - - static ByteSize address_bad_mask_offset() { - return Thread::gc_data_offset() + byte_offset_of(XThreadLocalData, _address_bad_mask); - } - - static ByteSize nmethod_disarmed_offset() { - return address_bad_mask_offset() + in_ByteSize(XAddressBadMaskHighOrderBitsOffset); - } -}; - -#endif // SHARE_GC_X_XTHREADLOCALDATA_HPP diff --git a/src/hotspot/share/gc/x/xTracer.cpp b/src/hotspot/share/gc/x/xTracer.cpp deleted file mode 100644 index 3a0bd2b00e3bf..0000000000000 --- a/src/hotspot/share/gc/x/xTracer.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcId.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xTracer.hpp" -#include "jfr/jfrEvents.hpp" -#include "runtime/safepointVerifiers.hpp" -#include "utilities/debug.hpp" -#include "utilities/macros.hpp" -#if INCLUDE_JFR -#include "jfr/metadata/jfrSerializer.hpp" -#endif - -#if INCLUDE_JFR - -class XPageTypeConstant : public JfrSerializer { -public: - virtual void serialize(JfrCheckpointWriter& writer) { - writer.write_count(3); - writer.write_key(XPageTypeSmall); - writer.write("Small"); - writer.write_key(XPageTypeMedium); - writer.write("Medium"); - writer.write_key(XPageTypeLarge); - writer.write("Large"); - } -}; - -class XStatisticsCounterTypeConstant : public JfrSerializer { -public: - virtual void serialize(JfrCheckpointWriter& writer) { - writer.write_count(XStatCounter::count()); - for (XStatCounter* counter = XStatCounter::first(); counter != nullptr; counter = counter->next()) { - writer.write_key(counter->id()); - writer.write(counter->name()); - } - } -}; - -class XStatisticsSamplerTypeConstant : public JfrSerializer { -public: - virtual void serialize(JfrCheckpointWriter& writer) { - writer.write_count(XStatSampler::count()); - for (XStatSampler* sampler = XStatSampler::first(); sampler != nullptr; sampler = sampler->next()) { - writer.write_key(sampler->id()); - writer.write(sampler->name()); - } - } -}; - -static void register_jfr_type_serializers() { - JfrSerializer::register_serializer(TYPE_ZPAGETYPETYPE, - true /* permit_cache */, - new XPageTypeConstant()); - JfrSerializer::register_serializer(TYPE_ZSTATISTICSCOUNTERTYPE, - true /* permit_cache */, - new XStatisticsCounterTypeConstant()); - JfrSerializer::register_serializer(TYPE_ZSTATISTICSSAMPLERTYPE, - true /* permit_cache */, - new XStatisticsSamplerTypeConstant()); -} - -#endif // INCLUDE_JFR - -XTracer* XTracer::_tracer = nullptr; - -XTracer::XTracer() : - GCTracer(Z) {} - -void XTracer::initialize() { - assert(_tracer == nullptr, "Already initialized"); - _tracer = new XTracer(); - JFR_ONLY(register_jfr_type_serializers();) -} - -void XTracer::send_stat_counter(const XStatCounter& counter, uint64_t increment, uint64_t value) { - NoSafepointVerifier nsv; - - EventZStatisticsCounter e; - if (e.should_commit()) { - e.set_id(counter.id()); - e.set_increment(increment); - e.set_value(value); - e.commit(); - } -} - -void XTracer::send_stat_sampler(const XStatSampler& sampler, uint64_t value) { - NoSafepointVerifier nsv; - - EventZStatisticsSampler e; - if (e.should_commit()) { - e.set_id(sampler.id()); - e.set_value(value); - e.commit(); - } -} - -void XTracer::send_thread_phase(const char* name, const Ticks& start, const Ticks& end) { - NoSafepointVerifier nsv; - - EventZThreadPhase e(UNTIMED); - if (e.should_commit()) { - e.set_gcId(GCId::current_or_undefined()); - e.set_name(name); - e.set_starttime(start); - e.set_endtime(end); - e.commit(); - } -} - -void XTracer::send_thread_debug(const char* name, const Ticks& start, const Ticks& end) { - NoSafepointVerifier nsv; - - EventZThreadDebug e(UNTIMED); - if (e.should_commit()) { - e.set_gcId(GCId::current_or_undefined()); - e.set_name(name); - e.set_starttime(start); - e.set_endtime(end); - e.commit(); - } -} diff --git a/src/hotspot/share/gc/x/xTracer.hpp b/src/hotspot/share/gc/x/xTracer.hpp deleted file mode 100644 index d9219d79c51f3..0000000000000 --- a/src/hotspot/share/gc/x/xTracer.hpp +++ /dev/null @@ -1,65 +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. - */ - -#ifndef SHARE_GC_X_XTRACER_HPP -#define SHARE_GC_X_XTRACER_HPP - -#include "gc/shared/gcTrace.hpp" - -class XStatCounter; -class XStatPhase; -class XStatSampler; - -class XTracer : public GCTracer, public CHeapObj { -private: - static XTracer* _tracer; - - XTracer(); - - void send_stat_counter(const XStatCounter& counter, uint64_t increment, uint64_t value); - void send_stat_sampler(const XStatSampler& sampler, uint64_t value); - void send_thread_phase(const char* name, const Ticks& start, const Ticks& end); - void send_thread_debug(const char* name, const Ticks& start, const Ticks& end); - -public: - static XTracer* tracer(); - static void initialize(); - - void report_stat_counter(const XStatCounter& counter, uint64_t increment, uint64_t value); - void report_stat_sampler(const XStatSampler& sampler, uint64_t value); - void report_thread_phase(const char* name, const Ticks& start, const Ticks& end); - void report_thread_debug(const char* name, const Ticks& start, const Ticks& end); -}; - -// For temporary latency measurements during development and debugging -class XTraceThreadDebug : public StackObj { -private: - const Ticks _start; - const char* const _name; - -public: - XTraceThreadDebug(const char* name); - ~XTraceThreadDebug(); -}; - -#endif // SHARE_GC_X_XTRACER_HPP diff --git a/src/hotspot/share/gc/x/xTracer.inline.hpp b/src/hotspot/share/gc/x/xTracer.inline.hpp deleted file mode 100644 index 22dd2e2b6fb43..0000000000000 --- a/src/hotspot/share/gc/x/xTracer.inline.hpp +++ /dev/null @@ -1,67 +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. - */ - -#ifndef SHARE_GC_X_XTRACER_INLINE_HPP -#define SHARE_GC_X_XTRACER_INLINE_HPP - -#include "gc/x/xTracer.hpp" - -#include "jfr/jfrEvents.hpp" - -inline XTracer* XTracer::tracer() { - return _tracer; -} - -inline void XTracer::report_stat_counter(const XStatCounter& counter, uint64_t increment, uint64_t value) { - if (EventZStatisticsCounter::is_enabled()) { - send_stat_counter(counter, increment, value); - } -} - -inline void XTracer::report_stat_sampler(const XStatSampler& sampler, uint64_t value) { - if (EventZStatisticsSampler::is_enabled()) { - send_stat_sampler(sampler, value); - } -} - -inline void XTracer::report_thread_phase(const char* name, const Ticks& start, const Ticks& end) { - if (EventZThreadPhase::is_enabled()) { - send_thread_phase(name, start, end); - } -} - -inline void XTracer::report_thread_debug(const char* name, const Ticks& start, const Ticks& end) { - if (EventZThreadDebug::is_enabled()) { - send_thread_debug(name, start, end); - } -} - -inline XTraceThreadDebug::XTraceThreadDebug(const char* name) : - _start(Ticks::now()), - _name(name) {} - -inline XTraceThreadDebug::~XTraceThreadDebug() { - XTracer::tracer()->report_thread_debug(_name, _start, Ticks::now()); -} - -#endif // SHARE_GC_X_XTRACER_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xUncommitter.cpp b/src/hotspot/share/gc/x/xUncommitter.cpp deleted file mode 100644 index ffd57b8c2a8e1..0000000000000 --- a/src/hotspot/share/gc/x/xUncommitter.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xUncommitter.hpp" -#include "jfr/jfrEvents.hpp" -#include "logging/log.hpp" - -static const XStatCounter XCounterUncommit("Memory", "Uncommit", XStatUnitBytesPerSecond); - -XUncommitter::XUncommitter(XPageAllocator* page_allocator) : - _page_allocator(page_allocator), - _lock(), - _stop(false) { - set_name("XUncommitter"); - create_and_start(); -} - -bool XUncommitter::wait(uint64_t timeout) const { - XLocker locker(&_lock); - while (!ZUncommit && !_stop) { - _lock.wait(); - } - - if (!_stop && timeout > 0) { - log_debug(gc, heap)("Uncommit Timeout: " UINT64_FORMAT "s", timeout); - _lock.wait(timeout * MILLIUNITS); - } - - return !_stop; -} - -bool XUncommitter::should_continue() const { - XLocker locker(&_lock); - return !_stop; -} - -void XUncommitter::run_service() { - uint64_t timeout = 0; - - while (wait(timeout)) { - EventZUncommit event; - size_t uncommitted = 0; - - while (should_continue()) { - // Uncommit chunk - const size_t flushed = _page_allocator->uncommit(&timeout); - if (flushed == 0) { - // Done - break; - } - - uncommitted += flushed; - } - - if (uncommitted > 0) { - // Update statistics - XStatInc(XCounterUncommit, uncommitted); - log_info(gc, heap)("Uncommitted: " SIZE_FORMAT "M(%.0f%%)", - uncommitted / M, percent_of(uncommitted, XHeap::heap()->max_capacity())); - - // Send event - event.commit(uncommitted); - } - } -} - -void XUncommitter::stop_service() { - XLocker locker(&_lock); - _stop = true; - _lock.notify_all(); -} diff --git a/src/hotspot/share/gc/x/xUncommitter.hpp b/src/hotspot/share/gc/x/xUncommitter.hpp deleted file mode 100644 index 9f6212fa98db9..0000000000000 --- a/src/hotspot/share/gc/x/xUncommitter.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XUNCOMMITTER_HPP -#define SHARE_GC_X_XUNCOMMITTER_HPP - -#include "gc/shared/concurrentGCThread.hpp" -#include "gc/x/xLock.hpp" - -class XPageAllocation; - -class XUncommitter : public ConcurrentGCThread { -private: - XPageAllocator* const _page_allocator; - mutable XConditionLock _lock; - bool _stop; - - bool wait(uint64_t timeout) const; - bool should_continue() const; - -protected: - virtual void run_service(); - virtual void stop_service(); - -public: - XUncommitter(XPageAllocator* page_allocator); -}; - -#endif // SHARE_GC_X_XUNCOMMITTER_HPP diff --git a/src/hotspot/share/gc/x/xUnload.cpp b/src/hotspot/share/gc/x/xUnload.cpp deleted file mode 100644 index c501ace7d1444..0000000000000 --- a/src/hotspot/share/gc/x/xUnload.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "classfile/classLoaderDataGraph.hpp" -#include "classfile/systemDictionary.hpp" -#include "code/codeBehaviours.hpp" -#include "code/codeCache.hpp" -#include "code/dependencyContext.hpp" -#include "gc/shared/gcBehaviours.hpp" -#include "gc/shared/suspendibleThreadSet.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xNMethod.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xUnload.hpp" -#include "memory/metaspaceUtils.hpp" -#include "oops/access.inline.hpp" - -static const XStatSubPhase XSubPhaseConcurrentClassesUnlink("Concurrent Classes Unlink"); -static const XStatSubPhase XSubPhaseConcurrentClassesPurge("Concurrent Classes Purge"); - -class XPhantomIsAliveObjectClosure : public BoolObjectClosure { -public: - virtual bool do_object_b(oop o) { - return XBarrier::is_alive_barrier_on_phantom_oop(o); - } -}; - -class XIsUnloadingOopClosure : public OopClosure { -private: - XPhantomIsAliveObjectClosure _is_alive; - bool _is_unloading; - -public: - XIsUnloadingOopClosure() : - _is_alive(), - _is_unloading(false) {} - - virtual void do_oop(oop* p) { - const oop o = RawAccess<>::oop_load(p); - if (o != nullptr && !_is_alive.do_object_b(o)) { - _is_unloading = true; - } - } - - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } - - bool is_unloading() const { - return _is_unloading; - } -}; - -class XIsUnloadingBehaviour : public IsUnloadingBehaviour { -public: - virtual bool has_dead_oop(nmethod* nm) const { - XReentrantLock* const lock = XNMethod::lock_for_nmethod(nm); - XLocker locker(lock); - XIsUnloadingOopClosure cl; - XNMethod::nmethod_oops_do_inner(nm, &cl); - return cl.is_unloading(); - } -}; - -class XCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { -public: - virtual bool lock(nmethod* nm) { - XReentrantLock* const lock = XNMethod::ic_lock_for_nmethod(nm); - lock->lock(); - return true; - } - - virtual void unlock(nmethod* nm) { - XReentrantLock* const lock = XNMethod::ic_lock_for_nmethod(nm); - lock->unlock(); - } - - virtual bool is_safe(nmethod* nm) { - if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading()) { - return true; - } - - XReentrantLock* const lock = XNMethod::ic_lock_for_nmethod(nm); - return lock->is_owned(); - } -}; - -XUnload::XUnload(XWorkers* workers) : - _workers(workers) { - - if (!ClassUnloading) { - return; - } - - static XIsUnloadingBehaviour is_unloading_behaviour; - IsUnloadingBehaviour::set_current(&is_unloading_behaviour); - - static XCompiledICProtectionBehaviour ic_protection_behaviour; - CompiledICProtectionBehaviour::set_current(&ic_protection_behaviour); -} - -void XUnload::prepare() { - if (!ClassUnloading) { - return; - } - - CodeCache::increment_unloading_cycle(); - DependencyContext::cleaning_start(); -} - -void XUnload::unlink() { - if (!ClassUnloading) { - return; - } - - XStatTimer timer(XSubPhaseConcurrentClassesUnlink); - SuspendibleThreadSetJoiner sts; - bool unloading_occurred; - - { - MutexLocker ml(ClassLoaderDataGraph_lock); - unloading_occurred = SystemDictionary::do_unloading(XStatPhase::timer()); - } - - Klass::clean_weak_klass_links(unloading_occurred); - XNMethod::unlink(_workers, unloading_occurred); - DependencyContext::cleaning_end(); -} - -void XUnload::purge() { - if (!ClassUnloading) { - return; - } - - XStatTimer timer(XSubPhaseConcurrentClassesPurge); - - { - SuspendibleThreadSetJoiner sts; - XNMethod::purge(); - } - - ClassLoaderDataGraph::purge(/*at_safepoint*/false); - CodeCache::purge_exception_caches(); -} - -void XUnload::finish() { - // Resize and verify metaspace - MetaspaceGC::compute_new_size(); - DEBUG_ONLY(MetaspaceUtils::verify();) -} diff --git a/src/hotspot/share/gc/x/xUnload.hpp b/src/hotspot/share/gc/x/xUnload.hpp deleted file mode 100644 index df6ba7ed2eb71..0000000000000 --- a/src/hotspot/share/gc/x/xUnload.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2018, 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 - * 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_GC_X_XUNLOAD_HPP -#define SHARE_GC_X_XUNLOAD_HPP - -class XWorkers; - -class XUnload { -private: - XWorkers* const _workers; - -public: - XUnload(XWorkers* workers); - - void prepare(); - void unlink(); - void purge(); - void finish(); -}; - -#endif // SHARE_GC_X_XUNLOAD_HPP diff --git a/src/hotspot/share/gc/x/xUnmapper.cpp b/src/hotspot/share/gc/x/xUnmapper.cpp deleted file mode 100644 index 17371cf1394d6..0000000000000 --- a/src/hotspot/share/gc/x/xUnmapper.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xList.inline.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xPage.inline.hpp" -#include "gc/x/xPageAllocator.hpp" -#include "gc/x/xUnmapper.hpp" -#include "jfr/jfrEvents.hpp" -#include "runtime/globals.hpp" - -XUnmapper::XUnmapper(XPageAllocator* page_allocator) : - _page_allocator(page_allocator), - _lock(), - _queue(), - _enqueued_bytes(0), - _warned_sync_unmapping(false), - _stop(false) { - set_name("XUnmapper"); - create_and_start(); -} - -XPage* XUnmapper::dequeue() { - XLocker locker(&_lock); - - for (;;) { - if (_stop) { - return nullptr; - } - - XPage* const page = _queue.remove_first(); - if (page != nullptr) { - _enqueued_bytes -= page->size(); - return page; - } - - _lock.wait(); - } -} - -bool XUnmapper::try_enqueue(XPage* page) { - if (ZVerifyViews) { - // Asynchronous unmap and destroy is not supported with ZVerifyViews - return false; - } - - // Enqueue for asynchronous unmap and destroy - XLocker locker(&_lock); - if (is_saturated()) { - // The unmapper thread is lagging behind and is unable to unmap memory fast enough - if (!_warned_sync_unmapping) { - _warned_sync_unmapping = true; - log_warning_p(gc)("WARNING: Encountered synchronous unmapping because asynchronous unmapping could not keep up"); - } - log_debug(gc, unmap)("Synchronous unmapping " SIZE_FORMAT "M page", page->size() / M); - return false; - } - - log_trace(gc, unmap)("Asynchronous unmapping " SIZE_FORMAT "M page (" SIZE_FORMAT "M / " SIZE_FORMAT "M enqueued)", - page->size() / M, _enqueued_bytes / M, queue_capacity() / M); - - _queue.insert_last(page); - _enqueued_bytes += page->size(); - _lock.notify_all(); - - return true; -} - -size_t XUnmapper::queue_capacity() const { - return align_up(_page_allocator->max_capacity() * ZAsyncUnmappingLimit / 100.0, XGranuleSize); -} - -bool XUnmapper::is_saturated() const { - return _enqueued_bytes >= queue_capacity(); -} - -void XUnmapper::do_unmap_and_destroy_page(XPage* page) const { - EventZUnmap event; - const size_t unmapped = page->size(); - - // Unmap and destroy - _page_allocator->unmap_page(page); - _page_allocator->destroy_page(page); - - // Send event - event.commit(unmapped); -} - -void XUnmapper::unmap_and_destroy_page(XPage* page) { - if (!try_enqueue(page)) { - // Synchronously unmap and destroy - do_unmap_and_destroy_page(page); - } -} - -void XUnmapper::run_service() { - for (;;) { - XPage* const page = dequeue(); - if (page == nullptr) { - // Stop - return; - } - - do_unmap_and_destroy_page(page); - } -} - -void XUnmapper::stop_service() { - XLocker locker(&_lock); - _stop = true; - _lock.notify_all(); -} diff --git a/src/hotspot/share/gc/x/xUnmapper.hpp b/src/hotspot/share/gc/x/xUnmapper.hpp deleted file mode 100644 index 811588f14d6f8..0000000000000 --- a/src/hotspot/share/gc/x/xUnmapper.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XUNMAPPER_HPP -#define SHARE_GC_X_XUNMAPPER_HPP - -#include "gc/shared/concurrentGCThread.hpp" -#include "gc/x/xList.hpp" -#include "gc/x/xLock.hpp" - -class XPage; -class XPageAllocator; - -class XUnmapper : public ConcurrentGCThread { -private: - XPageAllocator* const _page_allocator; - XConditionLock _lock; - XList _queue; - size_t _enqueued_bytes; - bool _warned_sync_unmapping; - bool _stop; - - XPage* dequeue(); - bool try_enqueue(XPage* page); - size_t queue_capacity() const; - bool is_saturated() const; - void do_unmap_and_destroy_page(XPage* page) const; - -protected: - virtual void run_service(); - virtual void stop_service(); - -public: - XUnmapper(XPageAllocator* page_allocator); - - void unmap_and_destroy_page(XPage* page); -}; - -#endif // SHARE_GC_X_XUNMAPPER_HPP diff --git a/src/hotspot/share/gc/x/xUtils.hpp b/src/hotspot/share/gc/x/xUtils.hpp deleted file mode 100644 index 26f14c0e98f78..0000000000000 --- a/src/hotspot/share/gc/x/xUtils.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XUTILS_HPP -#define SHARE_GC_X_XUTILS_HPP - -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" - -class XUtils : public AllStatic { -public: - // Allocation - static uintptr_t alloc_aligned(size_t alignment, size_t size); - - // Size conversion - static size_t bytes_to_words(size_t size_in_words); - static size_t words_to_bytes(size_t size_in_words); - - // Object - static size_t object_size(uintptr_t addr); - static void object_copy_disjoint(uintptr_t from, uintptr_t to, size_t size); - static void object_copy_conjoint(uintptr_t from, uintptr_t to, size_t size); -}; - -#endif // SHARE_GC_X_XUTILS_HPP diff --git a/src/hotspot/share/gc/x/xUtils.inline.hpp b/src/hotspot/share/gc/x/xUtils.inline.hpp deleted file mode 100644 index 09180959311d8..0000000000000 --- a/src/hotspot/share/gc/x/xUtils.inline.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XUTILS_INLINE_HPP -#define SHARE_GC_X_XUTILS_INLINE_HPP - -#include "gc/x/xUtils.hpp" - -#include "gc/x/xOop.inline.hpp" -#include "oops/oop.inline.hpp" -#include "utilities/align.hpp" -#include "utilities/copy.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" - -inline size_t XUtils::bytes_to_words(size_t size_in_bytes) { - assert(is_aligned(size_in_bytes, BytesPerWord), "Size not word aligned"); - return size_in_bytes >> LogBytesPerWord; -} - -inline size_t XUtils::words_to_bytes(size_t size_in_words) { - return size_in_words << LogBytesPerWord; -} - -inline size_t XUtils::object_size(uintptr_t addr) { - return words_to_bytes(XOop::from_address(addr)->size()); -} - -inline void XUtils::object_copy_disjoint(uintptr_t from, uintptr_t to, size_t size) { - Copy::aligned_disjoint_words((HeapWord*)from, (HeapWord*)to, bytes_to_words(size)); -} - -inline void XUtils::object_copy_conjoint(uintptr_t from, uintptr_t to, size_t size) { - if (from != to) { - Copy::aligned_conjoint_words((HeapWord*)from, (HeapWord*)to, bytes_to_words(size)); - } -} - -#endif // SHARE_GC_X_XUTILS_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xValue.hpp b/src/hotspot/share/gc/x/xValue.hpp deleted file mode 100644 index 4b2838c8a2c28..0000000000000 --- a/src/hotspot/share/gc/x/xValue.hpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XVALUE_HPP -#define SHARE_GC_X_XVALUE_HPP - -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" - -// -// Storage -// - -template -class XValueStorage : public AllStatic { -private: - static uintptr_t _top; - static uintptr_t _end; - -public: - static const size_t offset = 4 * K; - - static uintptr_t alloc(size_t size); -}; - -class XContendedStorage : public XValueStorage { -public: - static size_t alignment(); - static uint32_t count(); - static uint32_t id(); -}; - -class XPerCPUStorage : public XValueStorage { -public: - static size_t alignment(); - static uint32_t count(); - static uint32_t id(); -}; - -class XPerNUMAStorage : public XValueStorage { -public: - static size_t alignment(); - static uint32_t count(); - static uint32_t id(); -}; - -class XPerWorkerStorage : public XValueStorage { -public: - static size_t alignment(); - static uint32_t count(); - static uint32_t id(); -}; - -// -// Value -// - -template -class XValue : public CHeapObj { -private: - const uintptr_t _addr; - - uintptr_t value_addr(uint32_t value_id) const; - -public: - XValue(); - XValue(const T& value); - - const T* addr(uint32_t value_id = S::id()) const; - T* addr(uint32_t value_id = S::id()); - - const T& get(uint32_t value_id = S::id()) const; - T& get(uint32_t value_id = S::id()); - - void set(const T& value, uint32_t value_id = S::id()); - void set_all(const T& value); -}; - -template using XContended = XValue; -template using XPerCPU = XValue; -template using XPerNUMA = XValue; -template using XPerWorker = XValue; - -// -// Iterator -// - -template -class XValueIterator { -private: - XValue* const _value; - uint32_t _value_id; - -public: - XValueIterator(XValue* value); - - bool next(T** value); -}; - -template using XPerCPUIterator = XValueIterator; -template using XPerNUMAIterator = XValueIterator; -template using XPerWorkerIterator = XValueIterator; - -template -class XValueConstIterator { -private: - const XValue* const _value; - uint32_t _value_id; - -public: - XValueConstIterator(const XValue* value); - - bool next(const T** value); -}; - -template using XPerCPUConstIterator = XValueConstIterator; -template using XPerNUMAConstIterator = XValueConstIterator; -template using XPerWorkerConstIterator = XValueConstIterator; - -#endif // SHARE_GC_X_XVALUE_HPP diff --git a/src/hotspot/share/gc/x/xValue.inline.hpp b/src/hotspot/share/gc/x/xValue.inline.hpp deleted file mode 100644 index 1b12eb7d55525..0000000000000 --- a/src/hotspot/share/gc/x/xValue.inline.hpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XVALUE_INLINE_HPP -#define SHARE_GC_X_XVALUE_INLINE_HPP - -#include "gc/x/xValue.hpp" - -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xCPU.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xNUMA.hpp" -#include "gc/x/xThread.inline.hpp" -#include "gc/x/xUtils.hpp" -#include "runtime/globals.hpp" -#include "utilities/align.hpp" - -// -// Storage -// - -template uintptr_t XValueStorage::_end = 0; -template uintptr_t XValueStorage::_top = 0; - -template -uintptr_t XValueStorage::alloc(size_t size) { - assert(size <= offset, "Allocation too large"); - - // Allocate entry in existing memory block - const uintptr_t addr = align_up(_top, S::alignment()); - _top = addr + size; - - if (_top < _end) { - // Success - return addr; - } - - // Allocate new block of memory - const size_t block_alignment = offset; - const size_t block_size = offset * S::count(); - _top = XUtils::alloc_aligned(block_alignment, block_size); - _end = _top + offset; - - // Retry allocation - return alloc(size); -} - -inline size_t XContendedStorage::alignment() { - return XCacheLineSize; -} - -inline uint32_t XContendedStorage::count() { - return 1; -} - -inline uint32_t XContendedStorage::id() { - return 0; -} - -inline size_t XPerCPUStorage::alignment() { - return sizeof(uintptr_t); -} - -inline uint32_t XPerCPUStorage::count() { - return XCPU::count(); -} - -inline uint32_t XPerCPUStorage::id() { - return XCPU::id(); -} - -inline size_t XPerNUMAStorage::alignment() { - return sizeof(uintptr_t); -} - -inline uint32_t XPerNUMAStorage::count() { - return XNUMA::count(); -} - -inline uint32_t XPerNUMAStorage::id() { - return XNUMA::id(); -} - -inline size_t XPerWorkerStorage::alignment() { - return sizeof(uintptr_t); -} - -inline uint32_t XPerWorkerStorage::count() { - return UseDynamicNumberOfGCThreads ? ConcGCThreads : MAX2(ConcGCThreads, ParallelGCThreads); -} - -inline uint32_t XPerWorkerStorage::id() { - return XThread::worker_id(); -} - -// -// Value -// - -template -inline uintptr_t XValue::value_addr(uint32_t value_id) const { - return _addr + (value_id * S::offset); -} - -template -inline XValue::XValue() : - _addr(S::alloc(sizeof(T))) { - // Initialize all instances - XValueIterator iter(this); - for (T* addr; iter.next(&addr);) { - ::new (addr) T; - } -} - -template -inline XValue::XValue(const T& value) : - _addr(S::alloc(sizeof(T))) { - // Initialize all instances - XValueIterator iter(this); - for (T* addr; iter.next(&addr);) { - ::new (addr) T(value); - } -} - -template -inline const T* XValue::addr(uint32_t value_id) const { - return reinterpret_cast(value_addr(value_id)); -} - -template -inline T* XValue::addr(uint32_t value_id) { - return reinterpret_cast(value_addr(value_id)); -} - -template -inline const T& XValue::get(uint32_t value_id) const { - return *addr(value_id); -} - -template -inline T& XValue::get(uint32_t value_id) { - return *addr(value_id); -} - -template -inline void XValue::set(const T& value, uint32_t value_id) { - get(value_id) = value; -} - -template -inline void XValue::set_all(const T& value) { - XValueIterator iter(this); - for (T* addr; iter.next(&addr);) { - *addr = value; - } -} - -// -// Iterator -// - -template -inline XValueIterator::XValueIterator(XValue* value) : - _value(value), - _value_id(0) {} - -template -inline bool XValueIterator::next(T** value) { - if (_value_id < S::count()) { - *value = _value->addr(_value_id++); - return true; - } - return false; -} - -template -inline XValueConstIterator::XValueConstIterator(const XValue* value) : - _value(value), - _value_id(0) {} - -template -inline bool XValueConstIterator::next(const T** value) { - if (_value_id < S::count()) { - *value = _value->addr(_value_id++); - return true; - } - return false; -} - -#endif // SHARE_GC_X_XVALUE_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xVerify.cpp b/src/hotspot/share/gc/x/xVerify.cpp deleted file mode 100644 index ac6e8ee65d0f3..0000000000000 --- a/src/hotspot/share/gc/x/xVerify.cpp +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "classfile/classLoaderData.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xHeap.inline.hpp" -#include "gc/x/xNMethod.hpp" -#include "gc/x/xOop.hpp" -#include "gc/x/xPageAllocator.hpp" -#include "gc/x/xResurrection.hpp" -#include "gc/x/xRootsIterator.hpp" -#include "gc/x/xStackWatermark.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xVerify.hpp" -#include "memory/iterator.inline.hpp" -#include "memory/resourceArea.hpp" -#include "oops/oop.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/globals.hpp" -#include "runtime/handles.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/safepoint.hpp" -#include "runtime/stackFrameStream.inline.hpp" -#include "runtime/stackWatermark.inline.hpp" -#include "runtime/stackWatermarkSet.inline.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/preserveException.hpp" - -#define BAD_OOP_ARG(o, p) "Bad oop " PTR_FORMAT " found at " PTR_FORMAT, p2i(o), p2i(p) - -static void z_verify_oop(oop* p) { - const oop o = RawAccess<>::oop_load(p); - if (o != nullptr) { - const uintptr_t addr = XOop::to_address(o); - guarantee(XAddress::is_good(addr), BAD_OOP_ARG(o, p)); - guarantee(oopDesc::is_oop(XOop::from_address(addr)), BAD_OOP_ARG(o, p)); - } -} - -static void z_verify_possibly_weak_oop(oop* p) { - const oop o = RawAccess<>::oop_load(p); - if (o != nullptr) { - const uintptr_t addr = XOop::to_address(o); - guarantee(XAddress::is_good(addr) || XAddress::is_finalizable_good(addr), BAD_OOP_ARG(o, p)); - guarantee(oopDesc::is_oop(XOop::from_address(XAddress::good(addr))), BAD_OOP_ARG(o, p)); - } -} - -class XVerifyRootClosure : public OopClosure { -private: - const bool _verify_fixed; - -public: - XVerifyRootClosure(bool verify_fixed) : - _verify_fixed(verify_fixed) {} - - virtual void do_oop(oop* p) { - if (_verify_fixed) { - z_verify_oop(p); - } else { - // Don't know the state of the oop. - oop obj = *p; - obj = NativeAccess::oop_load(&obj); - z_verify_oop(&obj); - } - } - - virtual void do_oop(narrowOop*) { - ShouldNotReachHere(); - } - - bool verify_fixed() const { - return _verify_fixed; - } -}; - -class XVerifyStack : public OopClosure { -private: - XVerifyRootClosure* const _cl; - JavaThread* const _jt; - uint64_t _last_good; - bool _verifying_bad_frames; - -public: - XVerifyStack(XVerifyRootClosure* cl, JavaThread* jt) : - _cl(cl), - _jt(jt), - _last_good(0), - _verifying_bad_frames(false) { - XStackWatermark* const stack_watermark = StackWatermarkSet::get(jt, StackWatermarkKind::gc); - - if (_cl->verify_fixed()) { - assert(stack_watermark->processing_started(), "Should already have been fixed"); - assert(stack_watermark->processing_completed(), "Should already have been fixed"); - } else { - // We don't really know the state of the stack, verify watermark. - if (!stack_watermark->processing_started()) { - _verifying_bad_frames = true; - } else { - // Not time yet to verify bad frames - _last_good = stack_watermark->last_processed(); - } - } - } - - void do_oop(oop* p) { - if (_verifying_bad_frames) { - const oop obj = *p; - guarantee(!XAddress::is_good(XOop::to_address(obj)), BAD_OOP_ARG(obj, p)); - } - _cl->do_oop(p); - } - - void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } - - void prepare_next_frame(frame& frame) { - if (_cl->verify_fixed()) { - // All frames need to be good - return; - } - - // The verification has two modes, depending on whether we have reached the - // last processed frame or not. Before it is reached, we expect everything to - // be good. After reaching it, we expect everything to be bad. - const uintptr_t sp = reinterpret_cast(frame.sp()); - - if (!_verifying_bad_frames && sp == _last_good) { - // Found the last good frame, now verify the bad ones - _verifying_bad_frames = true; - } - } - - void verify_frames() { - NMethodToOopClosure nm_cl(_cl, false /* fix_relocations */); - for (StackFrameStream frames(_jt, true /* update */, false /* process_frames */); - !frames.is_done(); - frames.next()) { - frame& frame = *frames.current(); - frame.oops_do(this, &nm_cl, frames.register_map(), DerivedPointerIterationMode::_ignore); - prepare_next_frame(frame); - } - } -}; - -class XVerifyOopClosure : public ClaimMetadataVisitingOopIterateClosure { -private: - const bool _verify_weaks; - -public: - XVerifyOopClosure(bool verify_weaks) : - ClaimMetadataVisitingOopIterateClosure(ClassLoaderData::_claim_other), - _verify_weaks(verify_weaks) {} - - virtual void do_oop(oop* p) { - if (_verify_weaks) { - z_verify_possibly_weak_oop(p); - } else { - // We should never encounter finalizable oops through strong - // paths. This assumes we have only visited strong roots. - z_verify_oop(p); - } - } - - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } - - virtual ReferenceIterationMode reference_iteration_mode() { - return _verify_weaks ? DO_FIELDS : DO_FIELDS_EXCEPT_REFERENT; - } - - // Don't follow this metadata when verifying oops - virtual void do_method(Method* m) {} - virtual void do_nmethod(nmethod* nm) {} -}; - -typedef ClaimingCLDToOopClosure XVerifyCLDClosure; - -class XVerifyThreadClosure : public ThreadClosure { -private: - XVerifyRootClosure* const _cl; - -public: - XVerifyThreadClosure(XVerifyRootClosure* cl) : - _cl(cl) {} - - virtual void do_thread(Thread* thread) { - thread->oops_do_no_frames(_cl, nullptr); - - JavaThread* const jt = JavaThread::cast(thread); - if (!jt->has_last_Java_frame()) { - return; - } - - XVerifyStack verify_stack(_cl, jt); - verify_stack.verify_frames(); - } -}; - -class XVerifyNMethodClosure : public NMethodClosure { -private: - OopClosure* const _cl; - BarrierSetNMethod* const _bs_nm; - const bool _verify_fixed; - - bool trust_nmethod_state() const { - // The root iterator will visit non-processed - // nmethods class unloading is turned off. - return ClassUnloading || _verify_fixed; - } - -public: - XVerifyNMethodClosure(OopClosure* cl, bool verify_fixed) : - _cl(cl), - _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()), - _verify_fixed(verify_fixed) {} - - virtual void do_nmethod(nmethod* nm) { - assert(!trust_nmethod_state() || !_bs_nm->is_armed(nm), "Should not encounter any armed nmethods"); - - XNMethod::nmethod_oops_do(nm, _cl); - } -}; - -void XVerify::roots_strong(bool verify_fixed) { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); - assert(!XResurrection::is_blocked(), "Invalid phase"); - - XVerifyRootClosure cl(verify_fixed); - XVerifyCLDClosure cld_cl(&cl); - XVerifyThreadClosure thread_cl(&cl); - XVerifyNMethodClosure nm_cl(&cl, verify_fixed); - - XRootsIterator iter(ClassLoaderData::_claim_none); - iter.apply(&cl, - &cld_cl, - &thread_cl, - &nm_cl); -} - -void XVerify::roots_weak() { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); - assert(!XResurrection::is_blocked(), "Invalid phase"); - - XVerifyRootClosure cl(true /* verify_fixed */); - XWeakRootsIterator iter; - iter.apply(&cl); -} - -void XVerify::objects(bool verify_weaks) { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); - assert(XGlobalPhase == XPhaseMarkCompleted, "Invalid phase"); - assert(!XResurrection::is_blocked(), "Invalid phase"); - - XVerifyOopClosure cl(verify_weaks); - ObjectToOopClosure object_cl(&cl); - XHeap::heap()->object_iterate(&object_cl, verify_weaks); -} - -void XVerify::before_zoperation() { - // Verify strong roots - XStatTimerDisable disable; - if (ZVerifyRoots) { - roots_strong(false /* verify_fixed */); - } -} - -void XVerify::after_mark() { - // Verify all strong roots and strong references - XStatTimerDisable disable; - if (ZVerifyRoots) { - roots_strong(true /* verify_fixed */); - } - if (ZVerifyObjects) { - objects(false /* verify_weaks */); - } -} - -void XVerify::after_weak_processing() { - // Verify all roots and all references - XStatTimerDisable disable; - if (ZVerifyRoots) { - roots_strong(true /* verify_fixed */); - roots_weak(); - } - if (ZVerifyObjects) { - objects(true /* verify_weaks */); - } -} - -template -class XPageDebugMapOrUnmapClosure : public XPageClosure { -private: - const XPageAllocator* const _allocator; - -public: - XPageDebugMapOrUnmapClosure(const XPageAllocator* allocator) : - _allocator(allocator) {} - - void do_page(const XPage* page) { - if (Map) { - _allocator->debug_map_page(page); - } else { - _allocator->debug_unmap_page(page); - } - } -}; - -XVerifyViewsFlip::XVerifyViewsFlip(const XPageAllocator* allocator) : - _allocator(allocator) { - if (ZVerifyViews) { - // Unmap all pages - XPageDebugMapOrUnmapClosure cl(_allocator); - XHeap::heap()->pages_do(&cl); - } -} - -XVerifyViewsFlip::~XVerifyViewsFlip() { - if (ZVerifyViews) { - // Map all pages - XPageDebugMapOrUnmapClosure cl(_allocator); - XHeap::heap()->pages_do(&cl); - } -} - -#ifdef ASSERT - -class XVerifyBadOopClosure : public OopClosure { -public: - virtual void do_oop(oop* p) { - const oop o = *p; - assert(!XAddress::is_good(XOop::to_address(o)), "Should not be good: " PTR_FORMAT, p2i(o)); - } - - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } -}; - -// This class encapsulates various marks we need to deal with calling the -// frame iteration code from arbitrary points in the runtime. It is mostly -// due to problems that we might want to eventually clean up inside of the -// frame iteration code, such as creating random handles even though there -// is no safepoint to protect against, and fiddling around with exceptions. -class StackWatermarkProcessingMark { - ResetNoHandleMark _rnhm; - HandleMark _hm; - PreserveExceptionMark _pem; - ResourceMark _rm; - -public: - StackWatermarkProcessingMark(Thread* thread) : - _rnhm(), - _hm(thread), - _pem(thread), - _rm(thread) {} -}; - -void XVerify::verify_frame_bad(const frame& fr, RegisterMap& register_map) { - XVerifyBadOopClosure verify_cl; - fr.oops_do(&verify_cl, nullptr, ®ister_map, DerivedPointerIterationMode::_ignore); -} - -void XVerify::verify_thread_head_bad(JavaThread* jt) { - XVerifyBadOopClosure verify_cl; - jt->oops_do_no_frames(&verify_cl, nullptr); -} - -void XVerify::verify_thread_frames_bad(JavaThread* jt) { - if (jt->has_last_Java_frame()) { - XVerifyBadOopClosure verify_cl; - StackWatermarkProcessingMark swpm(Thread::current()); - // Traverse the execution stack - for (StackFrameStream fst(jt, true /* update */, false /* process_frames */); !fst.is_done(); fst.next()) { - fst.current()->oops_do(&verify_cl, nullptr /* code_cl */, fst.register_map(), DerivedPointerIterationMode::_ignore); - } - } -} - -#endif // ASSERT diff --git a/src/hotspot/share/gc/x/xVerify.hpp b/src/hotspot/share/gc/x/xVerify.hpp deleted file mode 100644 index bbe10f376fa6a..0000000000000 --- a/src/hotspot/share/gc/x/xVerify.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XVERIFY_HPP -#define SHARE_GC_X_XVERIFY_HPP - -#include "memory/allStatic.hpp" - -class frame; -class XPageAllocator; - -class XVerify : public AllStatic { -private: - static void roots_strong(bool verify_fixed); - static void roots_weak(); - - static void objects(bool verify_weaks); - -public: - static void before_zoperation(); - static void after_mark(); - static void after_weak_processing(); - - static void verify_thread_head_bad(JavaThread* thread) NOT_DEBUG_RETURN; - static void verify_thread_frames_bad(JavaThread* thread) NOT_DEBUG_RETURN; - static void verify_frame_bad(const frame& fr, RegisterMap& register_map) NOT_DEBUG_RETURN; -}; - -class XVerifyViewsFlip { -private: - const XPageAllocator* const _allocator; - -public: - XVerifyViewsFlip(const XPageAllocator* allocator); - ~XVerifyViewsFlip(); -}; - -#endif // SHARE_GC_X_XVERIFY_HPP diff --git a/src/hotspot/share/gc/x/xVirtualMemory.cpp b/src/hotspot/share/gc/x/xVirtualMemory.cpp deleted file mode 100644 index 63cb789d8de12..0000000000000 --- a/src/hotspot/share/gc/x/xVirtualMemory.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xAddressSpaceLimit.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xVirtualMemory.inline.hpp" -#include "nmt/memTracker.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" - -XVirtualMemoryManager::XVirtualMemoryManager(size_t max_capacity) : - _manager(), - _reserved(0), - _initialized(false) { - - // Check max supported heap size - if (max_capacity > XAddressOffsetMax) { - log_error_p(gc)("Java heap too large (max supported heap size is " SIZE_FORMAT "G)", - XAddressOffsetMax / G); - return; - } - - // Initialize platform specific parts before reserving address space - pd_initialize_before_reserve(); - - // Reserve address space - if (!reserve(max_capacity)) { - log_error_pd(gc)("Failed to reserve enough address space for Java heap"); - return; - } - - // Initialize platform specific parts after reserving address space - pd_initialize_after_reserve(); - - // Successfully initialized - _initialized = true; -} - -size_t XVirtualMemoryManager::reserve_discontiguous(uintptr_t start, size_t size, size_t min_range) { - if (size < min_range) { - // Too small - return 0; - } - - assert(is_aligned(size, XGranuleSize), "Misaligned"); - - if (reserve_contiguous(start, size)) { - return size; - } - - const size_t half = size / 2; - if (half < min_range) { - // Too small - return 0; - } - - // Divide and conquer - const size_t first_part = align_down(half, XGranuleSize); - const size_t second_part = size - first_part; - return reserve_discontiguous(start, first_part, min_range) + - reserve_discontiguous(start + first_part, second_part, min_range); -} - -size_t XVirtualMemoryManager::reserve_discontiguous(size_t size) { - // Don't try to reserve address ranges smaller than 1% of the requested size. - // This avoids an explosion of reservation attempts in case large parts of the - // address space is already occupied. - const size_t min_range = align_up(size / 100, XGranuleSize); - size_t start = 0; - size_t reserved = 0; - - // Reserve size somewhere between [0, XAddressOffsetMax) - while (reserved < size && start < XAddressOffsetMax) { - const size_t remaining = MIN2(size - reserved, XAddressOffsetMax - start); - reserved += reserve_discontiguous(start, remaining, min_range); - start += remaining; - } - - return reserved; -} - -bool XVirtualMemoryManager::reserve_contiguous(uintptr_t start, size_t size) { - assert(is_aligned(size, XGranuleSize), "Must be granule aligned"); - - // Reserve address views - const uintptr_t marked0 = XAddress::marked0(start); - const uintptr_t marked1 = XAddress::marked1(start); - const uintptr_t remapped = XAddress::remapped(start); - - // Reserve address space - if (!pd_reserve(marked0, size)) { - return false; - } - - if (!pd_reserve(marked1, size)) { - pd_unreserve(marked0, size); - return false; - } - - if (!pd_reserve(remapped, size)) { - pd_unreserve(marked0, size); - pd_unreserve(marked1, size); - return false; - } - - // Register address views with native memory tracker - nmt_reserve(marked0, size); - nmt_reserve(marked1, size); - nmt_reserve(remapped, size); - - // Make the address range free - _manager.free(start, size); - - return true; -} - -bool XVirtualMemoryManager::reserve_contiguous(size_t size) { - // Allow at most 8192 attempts spread evenly across [0, XAddressOffsetMax) - const size_t unused = XAddressOffsetMax - size; - const size_t increment = MAX2(align_up(unused / 8192, XGranuleSize), XGranuleSize); - - for (size_t start = 0; start + size <= XAddressOffsetMax; start += increment) { - if (reserve_contiguous(start, size)) { - // Success - return true; - } - } - - // Failed - return false; -} - -bool XVirtualMemoryManager::reserve(size_t max_capacity) { - const size_t limit = MIN2(XAddressOffsetMax, XAddressSpaceLimit::heap_view()); - const size_t size = MIN2(max_capacity * XVirtualToPhysicalRatio, limit); - - size_t reserved = size; - bool contiguous = true; - - // Prefer a contiguous address space - if (!reserve_contiguous(size)) { - // Fall back to a discontiguous address space - reserved = reserve_discontiguous(size); - contiguous = false; - } - - log_info_p(gc, init)("Address Space Type: %s/%s/%s", - (contiguous ? "Contiguous" : "Discontiguous"), - (limit == XAddressOffsetMax ? "Unrestricted" : "Restricted"), - (reserved == size ? "Complete" : "Degraded")); - log_info_p(gc, init)("Address Space Size: " SIZE_FORMAT "M x " SIZE_FORMAT " = " SIZE_FORMAT "M", - reserved / M, XHeapViews, (reserved * XHeapViews) / M); - - // Record reserved - _reserved = reserved; - - return reserved >= max_capacity; -} - -void XVirtualMemoryManager::nmt_reserve(uintptr_t start, size_t size) { - MemTracker::record_virtual_memory_reserve((void*)start, size, CALLER_PC); - MemTracker::record_virtual_memory_tag((void*)start, mtJavaHeap); -} - -bool XVirtualMemoryManager::is_initialized() const { - return _initialized; -} - -XVirtualMemory XVirtualMemoryManager::alloc(size_t size, bool force_low_address) { - uintptr_t start; - - // Small pages are allocated at low addresses, while medium/large pages - // are allocated at high addresses (unless forced to be at a low address). - if (force_low_address || size <= XPageSizeSmall) { - start = _manager.alloc_low_address(size); - } else { - start = _manager.alloc_high_address(size); - } - - return XVirtualMemory(start, size); -} - -void XVirtualMemoryManager::free(const XVirtualMemory& vmem) { - _manager.free(vmem.start(), vmem.size()); -} diff --git a/src/hotspot/share/gc/x/xVirtualMemory.hpp b/src/hotspot/share/gc/x/xVirtualMemory.hpp deleted file mode 100644 index c9e5c67ea5750..0000000000000 --- a/src/hotspot/share/gc/x/xVirtualMemory.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XVIRTUALMEMORY_HPP -#define SHARE_GC_X_XVIRTUALMEMORY_HPP - -#include "gc/x/xMemory.hpp" - -class VMStructs; - -class XVirtualMemory { - friend class ::VMStructs; - -private: - uintptr_t _start; - uintptr_t _end; - -public: - XVirtualMemory(); - XVirtualMemory(uintptr_t start, size_t size); - - bool is_null() const; - uintptr_t start() const; - uintptr_t end() const; - size_t size() const; - - XVirtualMemory split(size_t size); -}; - -class XVirtualMemoryManager { -private: - XMemoryManager _manager; - uintptr_t _reserved; - bool _initialized; - - // Platform specific implementation - void pd_initialize_before_reserve(); - void pd_initialize_after_reserve(); - bool pd_reserve(uintptr_t addr, size_t size); - void pd_unreserve(uintptr_t addr, size_t size); - - bool reserve_contiguous(uintptr_t start, size_t size); - bool reserve_contiguous(size_t size); - size_t reserve_discontiguous(uintptr_t start, size_t size, size_t min_range); - size_t reserve_discontiguous(size_t size); - bool reserve(size_t max_capacity); - - void nmt_reserve(uintptr_t start, size_t size); - -public: - XVirtualMemoryManager(size_t max_capacity); - - bool is_initialized() const; - - size_t reserved() const; - uintptr_t lowest_available_address() const; - - XVirtualMemory alloc(size_t size, bool force_low_address); - void free(const XVirtualMemory& vmem); -}; - -#endif // SHARE_GC_X_XVIRTUALMEMORY_HPP diff --git a/src/hotspot/share/gc/x/xVirtualMemory.inline.hpp b/src/hotspot/share/gc/x/xVirtualMemory.inline.hpp deleted file mode 100644 index 8c834b42c7f47..0000000000000 --- a/src/hotspot/share/gc/x/xVirtualMemory.inline.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2015, 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 - * 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_GC_X_XVIRTUALMEMORY_INLINE_HPP -#define SHARE_GC_X_XVIRTUALMEMORY_INLINE_HPP - -#include "gc/x/xVirtualMemory.hpp" - -#include "gc/x/xMemory.inline.hpp" - -inline XVirtualMemory::XVirtualMemory() : - _start(UINTPTR_MAX), - _end(UINTPTR_MAX) {} - -inline XVirtualMemory::XVirtualMemory(uintptr_t start, size_t size) : - _start(start), - _end(start + size) {} - -inline bool XVirtualMemory::is_null() const { - return _start == UINTPTR_MAX; -} - -inline uintptr_t XVirtualMemory::start() const { - return _start; -} - -inline uintptr_t XVirtualMemory::end() const { - return _end; -} - -inline size_t XVirtualMemory::size() const { - return _end - _start; -} - -inline XVirtualMemory XVirtualMemory::split(size_t size) { - _start += size; - return XVirtualMemory(_start - size, size); -} - -inline size_t XVirtualMemoryManager::reserved() const { - return _reserved; -} - -inline uintptr_t XVirtualMemoryManager::lowest_available_address() const { - return _manager.peek_low_address(); -} - -#endif // SHARE_GC_X_XVIRTUALMEMORY_INLINE_HPP diff --git a/src/hotspot/share/gc/x/xWeakRootsProcessor.cpp b/src/hotspot/share/gc/x/xWeakRootsProcessor.cpp deleted file mode 100644 index 0271fcd8c3d66..0000000000000 --- a/src/hotspot/share/gc/x/xWeakRootsProcessor.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xBarrier.inline.hpp" -#include "gc/x/xRootsIterator.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xWeakRootsProcessor.hpp" -#include "gc/x/xWorkers.hpp" - -class XPhantomCleanOopClosure : public OopClosure { -public: - virtual void do_oop(oop* p) { - // Read the oop once, to make sure the liveness check - // and the later clearing uses the same value. - const oop obj = Atomic::load(p); - if (XBarrier::is_alive_barrier_on_phantom_oop(obj)) { - XBarrier::keep_alive_barrier_on_phantom_oop_field(p); - } else { - // The destination could have been modified/reused, in which case - // we don't want to clear it. However, no one could write the same - // oop here again (the object would be strongly live and we would - // not consider clearing such oops), so therefore we don't have an - // ABA problem here. - Atomic::cmpxchg(p, obj, oop(nullptr)); - } - } - - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } -}; - -XWeakRootsProcessor::XWeakRootsProcessor(XWorkers* workers) : - _workers(workers) {} - -class XProcessWeakRootsTask : public XTask { -private: - XWeakRootsIterator _weak_roots; - -public: - XProcessWeakRootsTask() : - XTask("XProcessWeakRootsTask"), - _weak_roots() {} - - ~XProcessWeakRootsTask() { - _weak_roots.report_num_dead(); - } - - virtual void work() { - XPhantomCleanOopClosure cl; - _weak_roots.apply(&cl); - } -}; - -void XWeakRootsProcessor::process_weak_roots() { - XProcessWeakRootsTask task; - _workers->run(&task); -} diff --git a/src/hotspot/share/gc/x/xWeakRootsProcessor.hpp b/src/hotspot/share/gc/x/xWeakRootsProcessor.hpp deleted file mode 100644 index c63b2702374b2..0000000000000 --- a/src/hotspot/share/gc/x/xWeakRootsProcessor.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_GC_X_XWEAKROOTSPROCESSOR_HPP -#define SHARE_GC_X_XWEAKROOTSPROCESSOR_HPP - -class XWorkers; - -class XWeakRootsProcessor { -private: - XWorkers* const _workers; - -public: - XWeakRootsProcessor(XWorkers* workers); - - void process_weak_roots(); -}; - -#endif // SHARE_GC_X_XWEAKROOTSPROCESSOR_HPP diff --git a/src/hotspot/share/gc/x/xWorkers.cpp b/src/hotspot/share/gc/x/xWorkers.cpp deleted file mode 100644 index 642c63f0531e5..0000000000000 --- a/src/hotspot/share/gc/x/xWorkers.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/shared/gc_globals.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xLock.inline.hpp" -#include "gc/x/xStat.hpp" -#include "gc/x/xTask.hpp" -#include "gc/x/xThread.hpp" -#include "gc/x/xWorkers.hpp" -#include "runtime/java.hpp" - -class XWorkersInitializeTask : public WorkerTask { -private: - const uint _nworkers; - uint _started; - XConditionLock _lock; - -public: - XWorkersInitializeTask(uint nworkers) : - WorkerTask("XWorkersInitializeTask"), - _nworkers(nworkers), - _started(0), - _lock() {} - - virtual void work(uint worker_id) { - // Register as worker - XThread::set_worker(); - - // Wait for all threads to start - XLocker locker(&_lock); - if (++_started == _nworkers) { - // All threads started - _lock.notify_all(); - } else { - while (_started != _nworkers) { - _lock.wait(); - } - } - } -}; - -XWorkers::XWorkers() : - _workers("XWorker", - UseDynamicNumberOfGCThreads ? ConcGCThreads : MAX2(ConcGCThreads, ParallelGCThreads)) { - - if (UseDynamicNumberOfGCThreads) { - log_info_p(gc, init)("GC Workers: %u (dynamic)", _workers.max_workers()); - } else { - log_info_p(gc, init)("GC Workers: %u/%u (static)", ConcGCThreads, _workers.max_workers()); - } - - // Initialize worker threads - _workers.initialize_workers(); - _workers.set_active_workers(_workers.max_workers()); - if (_workers.active_workers() != _workers.max_workers()) { - vm_exit_during_initialization("Failed to create XWorkers"); - } - - // Execute task to register threads as workers - XWorkersInitializeTask task(_workers.max_workers()); - _workers.run_task(&task); -} - -uint XWorkers::active_workers() const { - return _workers.active_workers(); -} - -void XWorkers::set_active_workers(uint nworkers) { - log_info(gc, task)("Using %u workers", nworkers); - _workers.set_active_workers(nworkers); -} - -void XWorkers::run(XTask* task) { - log_debug(gc, task)("Executing Task: %s, Active Workers: %u", task->name(), active_workers()); - XStatWorkers::at_start(); - _workers.run_task(task->worker_task()); - XStatWorkers::at_end(); -} - -void XWorkers::run_all(XTask* task) { - // Save number of active workers - const uint prev_active_workers = _workers.active_workers(); - - // Execute task using all workers - _workers.set_active_workers(_workers.max_workers()); - log_debug(gc, task)("Executing Task: %s, Active Workers: %u", task->name(), active_workers()); - _workers.run_task(task->worker_task()); - - // Restore number of active workers - _workers.set_active_workers(prev_active_workers); -} - -void XWorkers::threads_do(ThreadClosure* tc) const { - _workers.threads_do(tc); -} diff --git a/src/hotspot/share/gc/x/xWorkers.hpp b/src/hotspot/share/gc/x/xWorkers.hpp deleted file mode 100644 index 33c49bb7fef5c..0000000000000 --- a/src/hotspot/share/gc/x/xWorkers.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_GC_X_XWORKERS_HPP -#define SHARE_GC_X_XWORKERS_HPP - -#include "gc/shared/workerThread.hpp" - -class ThreadClosure; -class XTask; - -class XWorkers { -private: - WorkerThreads _workers; - -public: - XWorkers(); - - uint active_workers() const; - void set_active_workers(uint nworkers); - - void run(XTask* task); - void run_all(XTask* task); - - void threads_do(ThreadClosure* tc) const; -}; - -#endif // SHARE_GC_X_XWORKERS_HPP diff --git a/src/hotspot/share/gc/x/x_globals.hpp b/src/hotspot/share/gc/x/x_globals.hpp deleted file mode 100644 index ab47d7ba9c8a3..0000000000000 --- a/src/hotspot/share/gc/x/x_globals.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 - * 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_GC_X_X_GLOBALS_HPP -#define SHARE_GC_X_X_GLOBALS_HPP - -#define GC_X_FLAGS(develop, \ - develop_pd, \ - product, \ - product_pd, \ - range, \ - constraint) \ - \ - product(bool, ZVerifyViews, false, DIAGNOSTIC, \ - "Verify heap view accesses") \ - \ -// end of GC_X_FLAGS - -#endif // SHARE_GC_X_X_GLOBALS_HPP diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp index a46681d131c94..12ee400eb2da2 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp @@ -239,21 +239,23 @@ void ZLoadBarrierStubC2::emit_code(MacroAssembler& masm) { ZBarrierSet::assembler()->generate_c2_load_barrier_stub(&masm, static_cast(this)); } -ZStoreBarrierStubC2* ZStoreBarrierStubC2::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic) { +ZStoreBarrierStubC2* ZStoreBarrierStubC2::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive) { AARCH64_ONLY(fatal("Should use ZStoreBarrierStubC2Aarch64::create")); - ZStoreBarrierStubC2* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic); + ZStoreBarrierStubC2* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic, is_nokeepalive); register_stub(stub); return stub; } -ZStoreBarrierStubC2::ZStoreBarrierStubC2(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic) +ZStoreBarrierStubC2::ZStoreBarrierStubC2(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, + bool is_native, bool is_atomic, bool is_nokeepalive) : ZBarrierStubC2(node), _ref_addr(ref_addr), _new_zaddress(new_zaddress), _new_zpointer(new_zpointer), _is_native(is_native), - _is_atomic(is_atomic) {} + _is_atomic(is_atomic), + _is_nokeepalive(is_nokeepalive) {} Address ZStoreBarrierStubC2::ref_addr() const { return _ref_addr; @@ -275,6 +277,10 @@ bool ZStoreBarrierStubC2::is_atomic() const { return _is_atomic; } +bool ZStoreBarrierStubC2::is_nokeepalive() const { + return _is_nokeepalive; +} + void ZStoreBarrierStubC2::emit_code(MacroAssembler& masm) { ZBarrierSet::assembler()->generate_c2_store_barrier_stub(&masm, static_cast(this)); } diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp index bf46780226eea..58f75441b910c 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp @@ -79,18 +79,20 @@ class ZStoreBarrierStubC2 : public ZBarrierStubC2 { const Register _new_zpointer; const bool _is_native; const bool _is_atomic; + const bool _is_nokeepalive; protected: - ZStoreBarrierStubC2(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic); + ZStoreBarrierStubC2(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive); public: - static ZStoreBarrierStubC2* create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic); + static ZStoreBarrierStubC2* create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive); Address ref_addr() const; Register new_zaddress() const; Register new_zpointer() const; bool is_native() const; bool is_atomic() const; + bool is_nokeepalive() const; virtual void emit_code(MacroAssembler& masm); }; diff --git a/src/hotspot/share/gc/z/shared/vmStructs_z_shared.hpp b/src/hotspot/share/gc/z/shared/vmStructs_z_shared.hpp deleted file mode 100644 index f0c03abbf7ac7..0000000000000 --- a/src/hotspot/share/gc/z/shared/vmStructs_z_shared.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017, 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. - */ - -#ifndef SHARE_GC_Z_SHARED_VMSTRUCTS_Z_SHARED_HPP -#define SHARE_GC_Z_SHARED_VMSTRUCTS_Z_SHARED_HPP - -#include "gc/x/vmStructs_x.hpp" -#include "gc/z/vmStructs_z.hpp" - -#define VM_STRUCTS_Z_SHARED(nonstatic_field, volatile_nonstatic_field, static_field) \ - VM_STRUCTS_X( \ - nonstatic_field, \ - volatile_nonstatic_field, \ - static_field) \ - \ - VM_STRUCTS_Z( \ - nonstatic_field, \ - volatile_nonstatic_field, \ - static_field) - -#define VM_INT_CONSTANTS_Z_SHARED(declare_constant, declare_constant_with_value) \ - VM_INT_CONSTANTS_X( \ - declare_constant, \ - declare_constant_with_value) \ - \ - VM_INT_CONSTANTS_Z( \ - declare_constant, \ - declare_constant_with_value) - -#define VM_LONG_CONSTANTS_Z_SHARED(declare_constant) \ - VM_LONG_CONSTANTS_X( \ - declare_constant) \ - \ - VM_LONG_CONSTANTS_Z( \ - declare_constant) - -#define VM_TYPES_Z_SHARED(declare_type, declare_toplevel_type, declare_integer_type) \ - VM_TYPES_X( \ - declare_type, \ - declare_toplevel_type, \ - declare_integer_type) \ - \ - VM_TYPES_Z( \ - declare_type, \ - declare_toplevel_type, \ - declare_integer_type) - -#endif // SHARE_GC_Z_SHARED_VMSTRUCTS_Z_SHARED_HPP diff --git a/src/hotspot/share/gc/z/shared/zSharedArguments.cpp b/src/hotspot/share/gc/z/shared/zSharedArguments.cpp deleted file mode 100644 index 4d7e9827f18a0..0000000000000 --- a/src/hotspot/share/gc/z/shared/zSharedArguments.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2017, 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. - */ - -#include "precompiled.hpp" -#include "gc/shared/gcArguments.hpp" -#include "gc/x/xArguments.hpp" -#include "gc/z/shared/zSharedArguments.hpp" -#include "gc/z/zArguments.hpp" -#include "runtime/globals.hpp" -#include "runtime/globals_extension.hpp" -#include "runtime/java.hpp" - -void ZSharedArguments::initialize_alignments() { - if (ZGenerational) { - ZArguments::initialize_alignments(); - } else { - XArguments::initialize_alignments(); - } -} - -void ZSharedArguments::initialize_heap_flags_and_sizes() { - GCArguments::initialize_heap_flags_and_sizes(); - - if (ZGenerational) { - ZArguments::initialize_heap_flags_and_sizes(); - } else { - XArguments::initialize_heap_flags_and_sizes(); - } -} - -void ZSharedArguments::initialize() { - GCArguments::initialize(); - - if (ZGenerational) { - ZArguments::initialize(); - } else { - XArguments::initialize(); - } -} - -size_t ZSharedArguments::heap_virtual_to_physical_ratio() { - if (ZGenerational) { - return ZArguments::heap_virtual_to_physical_ratio(); - } else { - return XArguments::heap_virtual_to_physical_ratio(); - } -} - -size_t ZSharedArguments::conservative_max_heap_alignment() { - return 0; -} - -CollectedHeap* ZSharedArguments::create_heap() { - if (ZGenerational) { - return ZArguments::create_heap(); - } else { - return XArguments::create_heap(); - } -} - -bool ZSharedArguments::is_supported() const { - if (ZGenerational) { - return ZArguments::is_os_supported(); - } else { - return XArguments::is_os_supported(); - } -} diff --git a/src/hotspot/share/gc/z/shared/zSharedArguments.hpp b/src/hotspot/share/gc/z/shared/zSharedArguments.hpp deleted file mode 100644 index c53f28ee0f97c..0000000000000 --- a/src/hotspot/share/gc/z/shared/zSharedArguments.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2017, 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. - */ - -#ifndef SHARE_GC_Z_SHARED_ZSHAREDARGUMENTS_HPP -#define SHARE_GC_Z_SHARED_ZSHAREDARGUMENTS_HPP - -#include "gc/shared/gcArguments.hpp" - -class CollectedHeap; - -class ZSharedArguments : public GCArguments { -private: - virtual void initialize_alignments(); - virtual void initialize_heap_flags_and_sizes(); - - virtual void initialize(); - virtual size_t conservative_max_heap_alignment(); - virtual size_t heap_virtual_to_physical_ratio(); - virtual CollectedHeap* create_heap(); - - virtual bool is_supported() const; - - bool is_os_supported() const; -}; - -#endif // SHARE_GC_Z_SHARED_ZSHAREDARGUMENTS_HPP diff --git a/src/hotspot/share/gc/z/shared/z_shared_globals.hpp b/src/hotspot/share/gc/z/shared/z_shared_globals.hpp deleted file mode 100644 index 4421d3fb0c3cc..0000000000000 --- a/src/hotspot/share/gc/z/shared/z_shared_globals.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 - * 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_GC_Z_SHARED_Z_SHARED_GLOBALS_HPP -#define SHARE_GC_Z_SHARED_Z_SHARED_GLOBALS_HPP - -#include "gc/x/x_globals.hpp" -#include "gc/z/z_globals.hpp" - -#define GC_Z_SHARED_FLAGS(develop, \ - develop_pd, \ - product, \ - product_pd, \ - range, \ - constraint) \ - \ - product(double, ZAllocationSpikeTolerance, 2.0, \ - "Allocation spike tolerance factor") \ - \ - /* Updated in arguments parsing to ZGenerational ? 5.0 : 25.0 */ \ - product(double, ZFragmentationLimit, 0 /* ignored */, \ - "Maximum allowed heap fragmentation") \ - range(0, 100) \ - \ - product(size_t, ZMarkStackSpaceLimit, 8*G, \ - "Maximum number of bytes allocated for mark stacks") \ - range(32*M, 1024*G) \ - \ - product(double, ZCollectionInterval, 0, \ - "Force GC at a fixed time interval (in seconds). " \ - "Backwards compatible alias for ZCollectionIntervalMajor") \ - \ - product(bool, ZProactive, true, \ - "Enable proactive GC cycles") \ - \ - product(bool, ZUncommit, true, \ - "Uncommit unused memory") \ - \ - product(uintx, ZUncommitDelay, 5 * 60, \ - "Uncommit memory if it has been unused for the specified " \ - "amount of time (in seconds)") \ - \ - product(double, ZAsyncUnmappingLimit, 100.0, DIAGNOSTIC, \ - "Specify the max amount (percentage of max heap size) of async " \ - "unmapping that can be in-flight before unmapping requests are " \ - "temporarily forced to be synchronous instead. " \ - "The default means after an amount of pages proportional to the " \ - "max capacity is enqueued, we resort to synchronous unmapping.") \ - \ - product(uint, ZStatisticsInterval, 10, DIAGNOSTIC, \ - "Time between statistics print outs (in seconds)") \ - range(1, (uint)-1) \ - \ - product(bool, ZStressRelocateInPlace, false, DIAGNOSTIC, \ - "Always relocate pages in-place") \ - \ - product(bool, ZVerifyRoots, trueInDebug, DIAGNOSTIC, \ - "Verify roots") \ - \ - product(bool, ZVerifyObjects, false, DIAGNOSTIC, \ - "Verify objects") \ - \ - product(bool, ZVerifyMarking, trueInDebug, DIAGNOSTIC, \ - "Verify marking stacks") \ - \ - product(bool, ZVerifyForwarding, false, DIAGNOSTIC, \ - "Verify forwarding tables") \ - \ - GC_X_FLAGS( \ - develop, \ - develop_pd, \ - product, \ - product_pd, \ - range, \ - constraint) \ - \ - GC_Z_FLAGS( \ - develop, \ - develop_pd, \ - product, \ - product_pd, \ - range, \ - constraint) - -// end of GC_Z_SHARED_FLAGS - -#endif // SHARE_GC_Z_SHARED_Z_SHARED_GLOBALS_HPP diff --git a/src/hotspot/share/gc/z/zArguments.cpp b/src/hotspot/share/gc/z/zArguments.cpp index f3ff568c64d14..331ca9f7c9423 100644 --- a/src/hotspot/share/gc/z/zArguments.cpp +++ b/src/hotspot/share/gc/z/zArguments.cpp @@ -38,6 +38,8 @@ void ZArguments::initialize_alignments() { } void ZArguments::initialize_heap_flags_and_sizes() { + GCArguments::initialize_heap_flags_and_sizes(); + if (!FLAG_IS_CMDLINE(MaxHeapSize) && !FLAG_IS_CMDLINE(MaxRAMPercentage) && !FLAG_IS_CMDLINE(SoftMaxHeapSize)) { @@ -117,6 +119,8 @@ void ZArguments::select_max_gc_threads() { } void ZArguments::initialize() { + GCArguments::initialize(); + // Check mark stack size const size_t mark_stack_space_limit = ZAddressSpaceLimit::mark_stack(); if (ZMarkStackSpaceLimit > mark_stack_space_limit) { @@ -220,6 +224,10 @@ void ZArguments::initialize() { #endif } +size_t ZArguments::conservative_max_heap_alignment() { + return 0; +} + size_t ZArguments::heap_virtual_to_physical_ratio() { return ZVirtualToPhysicalRatio; } @@ -228,6 +236,6 @@ CollectedHeap* ZArguments::create_heap() { return new ZCollectedHeap(); } -bool ZArguments::is_supported() { +bool ZArguments::is_supported() const { return is_os_supported(); } diff --git a/src/hotspot/share/gc/z/zArguments.hpp b/src/hotspot/share/gc/z/zArguments.hpp index 7d1c00d30d1cc..b51eb116dbfe6 100644 --- a/src/hotspot/share/gc/z/zArguments.hpp +++ b/src/hotspot/share/gc/z/zArguments.hpp @@ -28,20 +28,21 @@ class CollectedHeap; -class ZArguments : AllStatic { +class ZArguments : public GCArguments { private: static void select_max_gc_threads(); -public: - static void initialize_alignments(); - static void initialize_heap_flags_and_sizes(); - static void initialize(); - static size_t heap_virtual_to_physical_ratio(); - static CollectedHeap* create_heap(); - - static bool is_supported(); - static bool is_os_supported(); + +public: + virtual void initialize_alignments(); + virtual void initialize_heap_flags_and_sizes(); + virtual void initialize(); + virtual size_t conservative_max_heap_alignment(); + virtual size_t heap_virtual_to_physical_ratio(); + virtual CollectedHeap* create_heap(); + + virtual bool is_supported() const; }; #endif // SHARE_GC_Z_ZARGUMENTS_HPP diff --git a/src/hotspot/share/gc/z/zBarrierSetRuntime.cpp b/src/hotspot/share/gc/z/zBarrierSetRuntime.cpp index b41fec3d0a552..c267d9bb24aa6 100644 --- a/src/hotspot/share/gc/z/zBarrierSetRuntime.cpp +++ b/src/hotspot/share/gc/z/zBarrierSetRuntime.cpp @@ -59,6 +59,10 @@ JRT_LEAF(void, ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing(oo ZBarrier::store_barrier_on_heap_oop_field((zpointer*)p, false /* heal */); JRT_END +JRT_LEAF(void, ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing(oop* p)) + ZBarrier::no_keep_alive_store_barrier_on_heap_oop_field((zpointer*)p); +JRT_END + JRT_LEAF(void, ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing(oop* p)) ZBarrier::store_barrier_on_native_oop_field((zpointer*)p, false /* heal */); JRT_END @@ -126,6 +130,10 @@ address ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr() { return reinterpret_cast
    (store_barrier_on_oop_field_without_healing); } +address ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr() { + return reinterpret_cast
    (no_keepalive_store_barrier_on_oop_field_without_healing); +} + address ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr() { return reinterpret_cast
    (store_barrier_on_native_oop_field_without_healing); } diff --git a/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp b/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp index 8a81f162bf1ef..8d59be02e68c9 100644 --- a/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp +++ b/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp @@ -40,6 +40,7 @@ class ZBarrierSetRuntime : public AllStatic { static oopDesc* no_keepalive_load_barrier_on_phantom_oop_field_preloaded(oopDesc* o, oop* p); static void store_barrier_on_oop_field_with_healing(oop* p); static void store_barrier_on_oop_field_without_healing(oop* p); + static void no_keepalive_store_barrier_on_oop_field_without_healing(oop* p); static void store_barrier_on_native_oop_field_without_healing(oop* p); static void load_barrier_on_oop_array(oop* p, size_t length); static void clone(oopDesc* src, oopDesc* dst, size_t size); @@ -54,6 +55,7 @@ class ZBarrierSetRuntime : public AllStatic { static address no_keepalive_load_barrier_on_phantom_oop_field_preloaded_addr(); static address store_barrier_on_oop_field_with_healing_addr(); static address store_barrier_on_oop_field_without_healing_addr(); + static address no_keepalive_store_barrier_on_oop_field_without_healing_addr(); static address store_barrier_on_native_oop_field_without_healing_addr(); static address load_barrier_on_oop_array_addr(); static address clone_addr(); diff --git a/src/hotspot/share/gc/z/zDirector.cpp b/src/hotspot/share/gc/z/zDirector.cpp index 481525c425af0..3c0cb660206a2 100644 --- a/src/hotspot/share/gc/z/zDirector.cpp +++ b/src/hotspot/share/gc/z/zDirector.cpp @@ -535,6 +535,19 @@ static double calculate_young_to_old_worker_ratio(const ZDirectorStats& stats) { const size_t reclaimed_per_old_gc = stats._old_stats._stat_heap._reclaimed_avg; const double current_young_bytes_freed_per_gc_time = double(reclaimed_per_young_gc) / double(young_gc_time); const double current_old_bytes_freed_per_gc_time = double(reclaimed_per_old_gc) / double(old_gc_time); + + if (current_young_bytes_freed_per_gc_time == 0.0) { + if (current_old_bytes_freed_per_gc_time == 0.0) { + // Neither young nor old collections have reclaimed any memory. + // Give them equal priority. + return 1.0; + } + + // Only old collections have reclaimed memory. + // Prioritize old. + return ZOldGCThreads; + } + const double old_vs_young_efficiency_ratio = current_old_bytes_freed_per_gc_time / current_young_bytes_freed_per_gc_time; return old_vs_young_efficiency_ratio; diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 40aa76867f424..1e917bb5ee39d 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -241,10 +241,10 @@ void ZHeap::undo_alloc_page(ZPage* page) { log_trace(gc)("Undo page allocation, thread: " PTR_FORMAT " (%s), page: " PTR_FORMAT ", size: " SIZE_FORMAT, p2i(Thread::current()), ZUtils::thread_name(), p2i(page), page->size()); - free_page(page); + free_page(page, false /* allow_defragment */); } -void ZHeap::free_page(ZPage* page) { +void ZHeap::free_page(ZPage* page, bool allow_defragment) { // Remove page table entry _page_table.remove(page); @@ -253,7 +253,7 @@ void ZHeap::free_page(ZPage* page) { } // Free page - _page_allocator.free_page(page); + _page_allocator.free_page(page, allow_defragment); } size_t ZHeap::free_empty_pages(const ZArray* pages) { diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 18fa0d6349bea..7b75c63cf8ce0 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -104,7 +104,7 @@ class ZHeap { // Page allocation ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); void undo_alloc_page(ZPage* page); - void free_page(ZPage* page); + void free_page(ZPage* page, bool allow_defragment); size_t free_empty_pages(const ZArray* pages); // Object allocation diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index 01200f76b519e..12c17468bfb7e 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -30,6 +30,7 @@ #include "gc/z/zGeneration.inline.hpp" #include "gc/z/zGenerationId.hpp" #include "gc/z/zGlobals.hpp" +#include "gc/z/zLargePages.inline.hpp" #include "gc/z/zLock.inline.hpp" #include "gc/z/zPage.inline.hpp" #include "gc/z/zPageAge.hpp" @@ -46,6 +47,7 @@ #include "runtime/globals.hpp" #include "runtime/init.hpp" #include "runtime/java.hpp" +#include "runtime/os.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -232,29 +234,38 @@ bool ZPageAllocator::is_initialized() const { class ZPreTouchTask : public ZTask { private: - const ZPhysicalMemoryManager* const _physical; - volatile zoffset _start; - const zoffset_end _end; + volatile uintptr_t _current; + const uintptr_t _end; + + static void pretouch(zaddress zaddr, size_t size) { + const uintptr_t addr = untype(zaddr); + const size_t page_size = ZLargePages::is_explicit() ? ZGranuleSize : os::vm_page_size(); + os::pretouch_memory((void*)addr, (void*)(addr + size), page_size); + } public: - ZPreTouchTask(const ZPhysicalMemoryManager* physical, zoffset start, zoffset_end end) + ZPreTouchTask(zoffset start, zoffset_end end) : ZTask("ZPreTouchTask"), - _physical(physical), - _start(start), - _end(end) {} + _current(untype(start)), + _end(untype(end)) {} virtual void work() { + const size_t size = ZGranuleSize; + for (;;) { - // Get granule offset - const size_t size = ZGranuleSize; - const zoffset offset = to_zoffset(Atomic::fetch_then_add((uintptr_t*)&_start, size)); - if (offset >= _end) { + // Claim an offset for this thread + const uintptr_t claimed = Atomic::fetch_then_add(&_current, size); + if (claimed >= _end) { // Done break; } - // Pre-touch granule - _physical->pretouch(offset, size); + // At this point we know that we have a valid zoffset / zaddress. + const zoffset offset = to_zoffset(claimed); + const zaddress addr = ZOffset::address(offset); + + // Pre-touch the granule + pretouch(addr, size); } } }; @@ -271,11 +282,11 @@ bool ZPageAllocator::prime_cache(ZWorkers* workers, size_t size) { if (AlwaysPreTouch) { // Pre-touch page - ZPreTouchTask task(&_physical, page->start(), page->end()); + ZPreTouchTask task(page->start(), page->end()); workers->run_all(&task); } - free_page(page); + free_page(page, false /* allow_defragment */); return true; } @@ -462,6 +473,38 @@ void ZPageAllocator::destroy_page(ZPage* page) { safe_destroy_page(page); } +bool ZPageAllocator::should_defragment(const ZPage* page) const { + // A small page can end up at a high address (second half of the address space) + // if we've split a larger page or we have a constrained address space. To help + // fight address space fragmentation we remap such pages to a lower address, if + // a lower address is available. + return page->type() == ZPageType::small && + page->start() >= to_zoffset(_virtual.reserved() / 2) && + page->start() > _virtual.lowest_available_address(); +} + +ZPage* ZPageAllocator::defragment_page(ZPage* page) { + // Harvest the physical memory (which is committed) + ZPhysicalMemory pmem; + ZPhysicalMemory& old_pmem = page->physical_memory(); + pmem.add_segments(old_pmem); + old_pmem.remove_segments(); + + _unmapper->unmap_and_destroy_page(page); + + // Allocate new virtual memory at a low address + const ZVirtualMemory vmem = _virtual.alloc(pmem.size(), true /* force_low_address */); + + // Create the new page and map it + ZPage* new_page = new ZPage(ZPageType::small, vmem, pmem); + map_page(new_page); + + // Update statistics + ZStatInc(ZCounterDefragment); + + return new_page; +} + bool ZPageAllocator::is_alloc_allowed(size_t size) const { const size_t available = _current_max_capacity - _used - _claimed; return available >= size; @@ -623,16 +666,6 @@ ZPage* ZPageAllocator::alloc_page_create(ZPageAllocation* allocation) { return new ZPage(allocation->type(), vmem, pmem); } -bool ZPageAllocator::should_defragment(const ZPage* page) const { - // A small page can end up at a high address (second half of the address space) - // if we've split a larger page or we have a constrained address space. To help - // fight address space fragmentation we remap such pages to a lower address, if - // a lower address is available. - return page->type() == ZPageType::small && - page->start() >= to_zoffset(_virtual.reserved() / 2) && - page->start() > _virtual.lowest_available_address(); -} - bool ZPageAllocator::is_alloc_satisfied(ZPageAllocation* allocation) const { // The allocation is immediately satisfied if the list of pages contains // exactly one page, with the type and size that was requested. However, @@ -652,12 +685,6 @@ bool ZPageAllocator::is_alloc_satisfied(ZPageAllocation* allocation) const { return false; } - if (should_defragment(page)) { - // Defragment address space - ZStatInc(ZCounterDefragment); - return false; - } - // Allocation immediately satisfied return true; } @@ -773,6 +800,18 @@ void ZPageAllocator::satisfy_stalled() { } } +ZPage* ZPageAllocator::prepare_to_recycle(ZPage* page, bool allow_defragment) { + // Make sure we have a page that is safe to recycle + ZPage* const to_recycle = _safe_recycle.register_and_clone_if_activated(page); + + // Defragment the page before recycle if allowed and needed + if (allow_defragment && should_defragment(to_recycle)) { + return defragment_page(to_recycle); + } + + return to_recycle; +} + void ZPageAllocator::recycle_page(ZPage* page) { // Set time when last used page->set_last_used(); @@ -781,9 +820,11 @@ void ZPageAllocator::recycle_page(ZPage* page) { _cache.free_page(page); } -void ZPageAllocator::free_page(ZPage* page) { +void ZPageAllocator::free_page(ZPage* page, bool allow_defragment) { const ZGenerationId generation_id = page->generation_id(); - ZPage* const to_recycle = _safe_recycle.register_and_clone_if_activated(page); + + // Prepare page for recycling before taking the lock + ZPage* const to_recycle = prepare_to_recycle(page, allow_defragment); ZLocker locker(&_lock); @@ -800,11 +841,12 @@ void ZPageAllocator::free_page(ZPage* page) { } void ZPageAllocator::free_pages(const ZArray* pages) { - ZArray to_recycle; + ZArray to_recycle_pages; size_t young_size = 0; size_t old_size = 0; + // Prepare pages for recycling before taking the lock ZArrayIterator pages_iter(pages); for (ZPage* page; pages_iter.next(&page);) { if (page->is_young()) { @@ -812,7 +854,12 @@ void ZPageAllocator::free_pages(const ZArray* pages) { } else { old_size += page->size(); } - to_recycle.push(_safe_recycle.register_and_clone_if_activated(page)); + + // Prepare to recycle + ZPage* const to_recycle = prepare_to_recycle(page, true /* allow_defragment */); + + // Register for recycling + to_recycle_pages.push(to_recycle); } ZLocker locker(&_lock); @@ -823,7 +870,7 @@ void ZPageAllocator::free_pages(const ZArray* pages) { decrease_used_generation(ZGenerationId::old, old_size); // Free pages - ZArrayIterator iter(&to_recycle); + ZArrayIterator iter(&to_recycle_pages); for (ZPage* page; iter.next(&page);) { recycle_page(page); } @@ -833,11 +880,16 @@ void ZPageAllocator::free_pages(const ZArray* pages) { } void ZPageAllocator::free_pages_alloc_failed(ZPageAllocation* allocation) { - ZArray to_recycle; + ZArray to_recycle_pages; + // Prepare pages for recycling before taking the lock ZListRemoveIterator allocation_pages_iter(allocation->pages()); for (ZPage* page; allocation_pages_iter.next(&page);) { - to_recycle.push(_safe_recycle.register_and_clone_if_activated(page)); + // Prepare to recycle + ZPage* const to_recycle = prepare_to_recycle(page, false /* allow_defragment */); + + // Register for recycling + to_recycle_pages.push(to_recycle); } ZLocker locker(&_lock); @@ -849,7 +901,7 @@ void ZPageAllocator::free_pages_alloc_failed(ZPageAllocation* allocation) { size_t freed = 0; // Free any allocated/flushed pages - ZArrayIterator iter(&to_recycle); + ZArrayIterator iter(&to_recycle_pages); for (ZPage* page; iter.next(&page);) { freed += page->size(); recycle_page(page); diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index 5d3d59a416344..7df83a10eaf5a 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -104,13 +104,15 @@ class ZPageAllocator { void destroy_page(ZPage* page); + bool should_defragment(const ZPage* page) const; + ZPage* defragment_page(ZPage* page); + bool is_alloc_allowed(size_t size) const; bool alloc_page_common_inner(ZPageType type, size_t size, ZList* pages); bool alloc_page_common(ZPageAllocation* allocation); bool alloc_page_stall(ZPageAllocation* allocation); bool alloc_page_or_stall(ZPageAllocation* allocation); - bool should_defragment(const ZPage* page) const; bool is_alloc_satisfied(ZPageAllocation* allocation) const; ZPage* alloc_page_create(ZPageAllocation* allocation); ZPage* alloc_page_finalize(ZPageAllocation* allocation); @@ -149,9 +151,10 @@ class ZPageAllocator { void reset_statistics(ZGenerationId id); ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); + ZPage* prepare_to_recycle(ZPage* page, bool allow_defragment); void recycle_page(ZPage* page); void safe_destroy_page(ZPage* page); - void free_page(ZPage* page); + void free_page(ZPage* page, bool allow_defragment); void free_pages(const ZArray* pages); void enable_safe_destroy() const; diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.cpp b/src/hotspot/share/gc/z/zPhysicalMemory.cpp index 099adbfb9cc1e..a04fce2d9a9d8 100644 --- a/src/hotspot/share/gc/z/zPhysicalMemory.cpp +++ b/src/hotspot/share/gc/z/zPhysicalMemory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,20 +46,24 @@ ZPhysicalMemory::ZPhysicalMemory() ZPhysicalMemory::ZPhysicalMemory(const ZPhysicalMemorySegment& segment) : _segments() { - add_segment(segment); + _segments.append(segment); } ZPhysicalMemory::ZPhysicalMemory(const ZPhysicalMemory& pmem) - : _segments() { - add_segments(pmem); + : _segments(pmem.nsegments()) { + _segments.appendAll(&pmem._segments); } const ZPhysicalMemory& ZPhysicalMemory::operator=(const ZPhysicalMemory& pmem) { - // Free segments - _segments.clear_and_deallocate(); + // Check for self-assignment + if (this == &pmem) { + return *this; + } - // Copy segments - add_segments(pmem); + // Free and copy segments + _segments.clear_and_deallocate(); + _segments.reserve(pmem.nsegments()); + _segments.appendAll(&pmem._segments); return *this; } @@ -353,12 +357,6 @@ bool ZPhysicalMemoryManager::uncommit(ZPhysicalMemory& pmem) { return true; } -void ZPhysicalMemoryManager::pretouch(zoffset offset, size_t size) const { - const uintptr_t addr = untype(ZOffset::address(offset)); - const size_t page_size = ZLargePages::is_explicit() ? ZGranuleSize : os::vm_page_size(); - os::pretouch_memory((void*)addr, (void*)(addr + size), page_size); -} - // Map virtual memory to physcial memory void ZPhysicalMemoryManager::map(zoffset offset, const ZPhysicalMemory& pmem) const { const zaddress_unsafe addr = ZOffset::address_unsafe(offset); diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.hpp b/src/hotspot/share/gc/z/zPhysicalMemory.hpp index e5e0a19d1c560..b22179987a213 100644 --- a/src/hotspot/share/gc/z/zPhysicalMemory.hpp +++ b/src/hotspot/share/gc/z/zPhysicalMemory.hpp @@ -84,10 +84,6 @@ class ZPhysicalMemoryManager { ZPhysicalMemoryBacking _backing; ZMemoryManager _manager; - void pretouch_view(zaddress addr, size_t size) const; - void map_view(zaddress_unsafe addr, const ZPhysicalMemory& pmem) const; - void unmap_view(zaddress_unsafe addr, size_t size) const; - public: ZPhysicalMemoryManager(size_t max_capacity); @@ -102,8 +98,6 @@ class ZPhysicalMemoryManager { bool commit(ZPhysicalMemory& pmem); bool uncommit(ZPhysicalMemory& pmem); - void pretouch(zoffset offset, size_t size) const; - void map(zoffset offset, const ZPhysicalMemory& pmem) const; void unmap(zoffset offset, size_t size) const; }; diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 33304bcefd37f..7f69c0752bc5a 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -411,7 +411,7 @@ static void retire_target_page(ZGeneration* generation, ZPage* page) { // relocate the remaining objects, leaving the target page empty when // relocation completed. if (page->used() == 0) { - ZHeap::heap()->free_page(page); + ZHeap::heap()->free_page(page, true /* allow_defragment */); } } @@ -1012,7 +1012,7 @@ class ZRelocateWork : public StackObj { page->log_msg(" (relocate page done normal)"); // Free page - ZHeap::heap()->free_page(page); + ZHeap::heap()->free_page(page, true /* allow_defragment */); } } }; diff --git a/src/hotspot/share/gc/z/z_globals.hpp b/src/hotspot/share/gc/z/z_globals.hpp index c3e4bde73e44c..4e3076329691b 100644 --- a/src/hotspot/share/gc/z/z_globals.hpp +++ b/src/hotspot/share/gc/z/z_globals.hpp @@ -34,6 +34,31 @@ range, \ constraint) \ \ + product(double, ZAllocationSpikeTolerance, 2.0, \ + "Allocation spike tolerance factor") \ + \ + product(double, ZFragmentationLimit, 5.0, \ + "Maximum allowed heap fragmentation") \ + range(0, 100) \ + \ + product(size_t, ZMarkStackSpaceLimit, 8*G, \ + "Maximum number of bytes allocated for mark stacks") \ + range(32*M, 1024*G) \ + \ + product(double, ZCollectionInterval, 0, \ + "Force GC at a fixed time interval (in seconds). " \ + "Backwards compatible alias for ZCollectionIntervalMajor") \ + \ + product(bool, ZProactive, true, \ + "Enable proactive GC cycles") \ + \ + product(bool, ZUncommit, true, \ + "Uncommit unused memory") \ + \ + product(uintx, ZUncommitDelay, 5 * 60, \ + "Uncommit memory if it has been unused for the specified " \ + "amount of time (in seconds)") \ + \ product(double, ZYoungCompactionLimit, 25.0, \ "Maximum allowed garbage in young pages") \ range(0, 100) \ @@ -47,6 +72,32 @@ product(bool, ZCollectionIntervalOnly, false, \ "Only use timers for GC heuristics") \ \ + product(double, ZAsyncUnmappingLimit, 100.0, DIAGNOSTIC, \ + "Specify the max amount (percentage of max heap size) of async " \ + "unmapping that can be in-flight before unmapping requests are " \ + "temporarily forced to be synchronous instead. " \ + "The default means after an amount of pages proportional to the " \ + "max capacity is enqueued, we resort to synchronous unmapping.") \ + \ + product(uint, ZStatisticsInterval, 10, DIAGNOSTIC, \ + "Time between statistics print outs (in seconds)") \ + range(1, (uint)-1) \ + \ + product(bool, ZStressRelocateInPlace, false, DIAGNOSTIC, \ + "Always relocate pages in-place") \ + \ + product(bool, ZVerifyRoots, trueInDebug, DIAGNOSTIC, \ + "Verify roots") \ + \ + product(bool, ZVerifyObjects, false, DIAGNOSTIC, \ + "Verify objects") \ + \ + product(bool, ZVerifyMarking, trueInDebug, DIAGNOSTIC, \ + "Verify marking stacks") \ + \ + product(bool, ZVerifyForwarding, false, DIAGNOSTIC, \ + "Verify forwarding tables") \ + \ product(bool, ZBufferStoreBarriers, true, DIAGNOSTIC, \ "Buffer store barriers") \ \ @@ -64,13 +115,13 @@ product(bool, ZVerifyRemembered, trueInDebug, DIAGNOSTIC, \ "Verify remembered sets") \ \ - develop(bool, ZVerifyOops, false, \ - "Verify accessed oops") \ - \ product(int, ZTenuringThreshold, -1, DIAGNOSTIC, \ "Young generation tenuring threshold, -1 for dynamic computation")\ range(-1, static_cast(ZPageAgeMax)) \ \ + develop(bool, ZVerifyOops, false, \ + "Verify accessed oops") \ + \ develop(size_t, ZForceDiscontiguousHeapReservations, 0, \ "The gc will attempt to split the heap reservation into this " \ "many reservations, subject to available virtual address space " \ diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index edad228b4e3ae..6634306636b15 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1142,9 +1142,6 @@ JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide); JNIEXPORT void JNICALL JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide); -JNIEXPORT void JNICALL -JVM_VirtualThreadHideFrames(JNIEnv* env, jclass clazz, jboolean hide); - JNIEXPORT void JNICALL JVM_VirtualThreadDisableSuspend(JNIEnv* env, jclass clazz, jboolean enter); diff --git a/src/hotspot/share/interpreter/abstractInterpreter.cpp b/src/hotspot/share/interpreter/abstractInterpreter.cpp index 9d72f9ba0edec..616ba29c62b33 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.cpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.cpp @@ -74,7 +74,9 @@ void AbstractInterpreter::print() { tty->print_cr("avg codelet size = %6d bytes", _code->used_space() / _code->number_of_stubs()); tty->cr(); } + _should_print_instructions = PrintInterpreter; _code->print(); + _should_print_instructions = false; tty->print_cr("----------------------------------------------------------------------"); tty->cr(); } @@ -91,6 +93,8 @@ address AbstractInterpreter::_slow_signature_handler; address AbstractInterpreter::_entry_table [AbstractInterpreter::number_of_method_entries]; address AbstractInterpreter::_native_abi_to_tosca [AbstractInterpreter::number_of_result_handlers]; +bool AbstractInterpreter::_should_print_instructions = false; + //------------------------------------------------------------------------------------------------------------------------ // Generation of complete interpreter diff --git a/src/hotspot/share/interpreter/abstractInterpreter.hpp b/src/hotspot/share/interpreter/abstractInterpreter.hpp index 790706c2de3cd..55fb58021a0d4 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.hpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.hpp @@ -126,6 +126,8 @@ class AbstractInterpreter: AllStatic { static address _rethrow_exception_entry; // rethrows an activation in previous frame + static bool _should_print_instructions; // only with PrintInterpreter and when printing all InterpreterCodelet + friend class AbstractInterpreterGenerator; friend class InterpreterMacroAssembler; @@ -133,6 +135,7 @@ class AbstractInterpreter: AllStatic { // Initialization/debugging static void initialize(); static StubQueue* code() { return _code; } + static bool should_print_instructions() { return _should_print_instructions; } // Method activation diff --git a/src/hotspot/share/interpreter/bytecodeTracer.cpp b/src/hotspot/share/interpreter/bytecodeTracer.cpp index e5a3e9c16f4a1..cdb53b62f8c40 100644 --- a/src/hotspot/share/interpreter/bytecodeTracer.cpp +++ b/src/hotspot/share/interpreter/bytecodeTracer.cpp @@ -105,7 +105,7 @@ class BytecodePrinter { // the incoming method. We could lose a line of trace output. // This is acceptable in a debug-only feature. st->cr(); - st->print("[%ld] ", (long) Thread::current()->osthread()->thread_id()); + st->print("[" UINTX_FORMAT "] ", Thread::current()->osthread()->thread_id_for_printing()); method->print_name(st); st->cr(); _current_method = method(); @@ -128,7 +128,7 @@ class BytecodePrinter { code == Bytecodes::_return_register_finalizer || (code >= Bytecodes::_ireturn && code <= Bytecodes::_return)) { int bci = (int)(bcp - method->code_base()); - st->print("[%ld] ", (long) Thread::current()->osthread()->thread_id()); + st->print("[" UINTX_FORMAT "] ", Thread::current()->osthread()->thread_id_for_printing()); if (Verbose) { st->print("%8d %4d " INTPTR_FORMAT " " INTPTR_FORMAT " %s", BytecodeCounter::counter_value(), bci, tos, tos2, Bytecodes::name(code)); diff --git a/src/hotspot/share/interpreter/interpreter.cpp b/src/hotspot/share/interpreter/interpreter.cpp index 3c4ff4c1749e9..cba26f5aa6a6d 100644 --- a/src/hotspot/share/interpreter/interpreter.cpp +++ b/src/hotspot/share/interpreter/interpreter.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 @@ -66,7 +66,7 @@ void InterpreterCodelet::verify() {} void InterpreterCodelet::print_on(outputStream* st) const { ttyLocker ttyl; - if (PrintInterpreter) { + if (AbstractInterpreter::should_print_instructions()) { st->cr(); st->print_cr("----------------------------------------------------------------------"); } @@ -76,7 +76,7 @@ void InterpreterCodelet::print_on(outputStream* st) const { st->print_cr("[" INTPTR_FORMAT ", " INTPTR_FORMAT "] %d bytes", p2i(code_begin()), p2i(code_end()), code_size()); - if (PrintInterpreter) { + if (AbstractInterpreter::should_print_instructions()) { st->cr(); Disassembler::decode(code_begin(), code_end(), st NOT_PRODUCT(COMMA &_asm_remarks)); } diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index 36847580d9c63..92d95b43e4068 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -1200,13 +1200,7 @@ Method* LinkResolver::linktime_resolve_special_method(const LinkInfo& link_info, Klass* current_klass = link_info.current_klass(); if (current_klass != nullptr && resolved_klass->is_interface()) { InstanceKlass* klass_to_check = InstanceKlass::cast(current_klass); - // Disable verification for the dynamically-generated reflection bytecodes - // for serialization constructor accessor. - bool is_reflect = klass_to_check->is_subclass_of( - vmClasses::reflect_SerializationConstructorAccessorImpl_klass()); - - if (!is_reflect && - !klass_to_check->is_same_or_direct_interface(resolved_klass)) { + if (!klass_to_check->is_same_or_direct_interface(resolved_klass)) { ResourceMark rm(THREAD); stringStream ss; ss.print("Interface method reference: '"); diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp index bcccff2fe82ec..b0afcb5279522 100644 --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.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 @@ -74,7 +74,7 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator { void set_safepoints_for_all_bytes(); // Helpers for generate_and_dispatch - address generate_trace_code(TosState state) PRODUCT_RETURN0; + address generate_trace_code(TosState state) PRODUCT_RETURN_NULL; void count_bytecode() PRODUCT_RETURN; void histogram_bytecode(Template* t) PRODUCT_RETURN; void histogram_bytecode_pair(Template* t) PRODUCT_RETURN; diff --git a/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp b/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp index 882d468a4a3ae..f8f975528cb47 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp @@ -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 @@ -133,7 +133,7 @@ static void log_and_throw(jvmtiError error, TRAPS) { static void check_exception_and_log(JNIEnv* env, TRAPS) { assert(env != nullptr, "invariant"); - if (env->ExceptionOccurred()) { + if (env->ExceptionCheck()) { // array index out of bound DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); ThreadInVMfromNative tvmfn(THREAD); diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 03b47bcd21dc5..1ba374ef24af9 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -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 @@ -100,6 +100,10 @@ void Jfr::on_set_current_thread(JavaThread* jt, oop thread) { JfrThreadLocal::on_set_current_thread(jt, thread); } +void Jfr::initialize_main_thread(JavaThread* jt) { + JfrThreadLocal::initialize_main_thread(jt); +} + void Jfr::on_resolution(const CallInfo& info, TRAPS) { JfrResolution::on_runtime_resolution(info, THREAD); } diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index af492f85123c9..4b34784558ef3 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,6 +71,7 @@ class Jfr : AllStatic { static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter); static bool on_start_flight_recording_option(const JavaVMOption** option, char* delimiter); static void on_backpatching(const Method* callee_method, JavaThread* jt); + static void initialize_main_thread(JavaThread* jt); }; #endif // SHARE_JFR_JFR_HPP diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp index 63c7a027373be..4b054a86ba143 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp @@ -114,7 +114,7 @@ void JfrCheckpointThreadClosure::do_thread(Thread* t) { void JfrThreadConstantSet::serialize(JfrCheckpointWriter& writer) { JfrCheckpointThreadClosure tc(writer); - JfrJavaThreadIterator javathreads(false); // include not yet live threads (_thread_new) + JfrJavaThreadIterator javathreads; while (javathreads.has_next()) { tc.do_thread(javathreads.next()); } diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index 9aebdcc0afa19..af6543e2a75ba 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -210,7 +210,7 @@ bool JfrRecorder::on_create_vm_2() { return true; } JavaThread* const thread = JavaThread::current(); - JfrThreadLocal::assign_thread_id(thread, thread->jfr_thread_local()); + assert(JfrThreadLocal::jvm_thread_id(thread) != 0, "invariant"); if (!JfrOptionSet::initialize(thread)) { return false; diff --git a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp index d133e026c4397..35e50bd6318f0 100644 --- a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp +++ b/src/hotspot/share/jfr/support/jfrThreadLocal.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 @@ -71,7 +71,6 @@ JfrThreadLocal::JfrThreadLocal() : _wallclock_time(os::javaTimeNanos()), _stackdepth(0), _entering_suspend_flag(0), - _critical_section(0), _vthread_epoch(0), _vthread_excluded(false), _jvm_thread_excluded(false), @@ -100,6 +99,14 @@ const JfrBlobHandle& JfrThreadLocal::thread_blob() const { return _thread; } +void JfrThreadLocal::initialize_main_thread(JavaThread* jt) { + assert(jt != nullptr, "invariant"); + assert(Thread::is_starting_thread(jt), "invariant"); + assert(jt->threadObj() == nullptr, "invariant"); + assert(jt->jfr_thread_local()->_jvm_thread_id == 0, "invariant"); + jt->jfr_thread_local()->_jvm_thread_id = 1; +} + static void send_java_thread_start_event(JavaThread* jt) { assert(jt != nullptr, "invariant"); assert(Thread::current() == jt, "invariant"); @@ -394,13 +401,13 @@ traceid JfrThreadLocal::thread_id(const Thread* t) { if (is_impersonating(t)) { return t->jfr_thread_local()->_thread_id_alias; } - JfrThreadLocal* const tl = t->jfr_thread_local(); + const JfrThreadLocal* const tl = t->jfr_thread_local(); if (!t->is_Java_thread()) { - return jvm_thread_id(t, tl); + return jvm_thread_id(tl); } const JavaThread* jt = JavaThread::cast(t); if (!is_vthread(jt)) { - return jvm_thread_id(t, tl); + return jvm_thread_id(tl); } // virtual thread const traceid tid = vthread_id(jt); @@ -421,19 +428,30 @@ traceid JfrThreadLocal::external_thread_id(const Thread* t) { return JfrRecorder::is_recording() ? thread_id(t) : jvm_thread_id(t); } -inline traceid load_java_thread_id(const Thread* t) { +static inline traceid load_java_thread_id(const Thread* t) { assert(t != nullptr, "invariant"); assert(t->is_Java_thread(), "invariant"); oop threadObj = JavaThread::cast(t)->threadObj(); return threadObj != nullptr ? AccessThreadTraceId::id(threadObj) : 0; } +#ifdef ASSERT +static bool can_assign(const Thread* t) { + assert(t != nullptr, "invariant"); + if (!t->is_Java_thread()) { + return true; + } + const JavaThread* jt = JavaThread::cast(t); + return jt->thread_state() == _thread_new || jt->is_attaching_via_jni(); +} +#endif + traceid JfrThreadLocal::assign_thread_id(const Thread* t, JfrThreadLocal* tl) { assert(t != nullptr, "invariant"); assert(tl != nullptr, "invariant"); - JfrSpinlockHelper spinlock(&tl->_critical_section); traceid tid = tl->_jvm_thread_id; if (tid == 0) { + assert(can_assign(t), "invariant"); if (t->is_Java_thread()) { tid = load_java_thread_id(t); tl->_jvm_thread_id = tid; @@ -446,15 +464,14 @@ traceid JfrThreadLocal::assign_thread_id(const Thread* t, JfrThreadLocal* tl) { return tid; } -traceid JfrThreadLocal::jvm_thread_id(const Thread* t, JfrThreadLocal* tl) { - assert(t != nullptr, "invariant"); +traceid JfrThreadLocal::jvm_thread_id(const JfrThreadLocal* tl) { assert(tl != nullptr, "invariant"); - return tl->_jvm_thread_id != 0 ? tl->_jvm_thread_id : JfrThreadLocal::assign_thread_id(t, tl); + return tl->_jvm_thread_id; } traceid JfrThreadLocal::jvm_thread_id(const Thread* t) { assert(t != nullptr, "invariant"); - return jvm_thread_id(t, t->jfr_thread_local()); + return jvm_thread_id(t->jfr_thread_local()); } bool JfrThreadLocal::is_vthread(const JavaThread* jt) { diff --git a/src/hotspot/share/jfr/support/jfrThreadLocal.hpp b/src/hotspot/share/jfr/support/jfrThreadLocal.hpp index 73ff226c826db..d2f6ef8d5d543 100644 --- a/src/hotspot/share/jfr/support/jfrThreadLocal.hpp +++ b/src/hotspot/share/jfr/support/jfrThreadLocal.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,6 @@ class JfrThreadLocal { friend class Jfr; friend class JfrIntrinsicSupport; friend class JfrJavaSupport; - friend class JfrRecorder; friend class JVMCIVMStructs; private: jobject _java_event_writer; @@ -65,7 +64,6 @@ class JfrThreadLocal { jlong _wallclock_time; mutable u4 _stackdepth; volatile jint _entering_suspend_flag; - mutable volatile int _critical_section; u2 _vthread_epoch; bool _vthread_excluded; bool _jvm_thread_excluded; @@ -78,11 +76,13 @@ class JfrThreadLocal { JfrStackFrame* install_stackframes() const; void release(Thread* t); static void release(JfrThreadLocal* tl, Thread* t); + static void initialize_main_thread(JavaThread* jt); static void set(bool* excluded_field, bool state); static traceid assign_thread_id(const Thread* t, JfrThreadLocal* tl); static traceid vthread_id(const Thread* t); static void set_vthread_epoch(const JavaThread* jt, traceid id, u2 epoch); + static traceid jvm_thread_id(const JfrThreadLocal* tl); bool is_vthread_excluded() const; static void exclude_vthread(const JavaThread* jt); static void include_vthread(const JavaThread* jt); @@ -175,7 +175,6 @@ class JfrThreadLocal { // Non-volatile thread id, for Java carrier threads and non-java threads. static traceid jvm_thread_id(const Thread* t); - static traceid jvm_thread_id(const Thread* t, JfrThreadLocal* tl); // To impersonate is to temporarily masquerade as another thread. // For example, when writing an event that should be attributed to some other thread. diff --git a/src/hotspot/share/jvmci/jvmci.cpp b/src/hotspot/share/jvmci/jvmci.cpp index 447792b6fcae6..6d240bc906309 100644 --- a/src/hotspot/share/jvmci/jvmci.cpp +++ b/src/hotspot/share/jvmci/jvmci.cpp @@ -50,30 +50,33 @@ char* JVMCI::_shared_library_path = nullptr; volatile bool JVMCI::_in_shutdown = false; StringEventLog* JVMCI::_events = nullptr; StringEventLog* JVMCI::_verbose_events = nullptr; -volatile intx JVMCI::_fatal_log_init_thread = -1; +volatile intx JVMCI::_first_error_tid = -1; volatile int JVMCI::_fatal_log_fd = -1; const char* JVMCI::_fatal_log_filename = nullptr; -CompilerThreadCanCallJava::CompilerThreadCanCallJava(JavaThread* current, bool new_state) { - _current = nullptr; +CompilerThread* CompilerThreadCanCallJava::update(JavaThread* current, bool new_state) { if (current->is_Compiler_thread()) { CompilerThread* ct = CompilerThread::cast(current); if (ct->_can_call_java != new_state && ct->_compiler != nullptr && ct->_compiler->is_jvmci()) { - // Only enter a new context if the ability of the + // Only update the state if the ability of the // current thread to call Java actually changes - _reset_state = ct->_can_call_java; ct->_can_call_java = new_state; - _current = ct; + return ct; } } + return nullptr; +} + +CompilerThreadCanCallJava::CompilerThreadCanCallJava(JavaThread* current, bool new_state) { + _current = CompilerThreadCanCallJava::update(current, new_state); } CompilerThreadCanCallJava::~CompilerThreadCanCallJava() { if (_current != nullptr) { - _current->_can_call_java = _reset_state; + _current->_can_call_java = !_current->_can_call_java; } } @@ -354,7 +357,7 @@ void JVMCI::fatal_log(const char* buf, size_t count) { intx current_thread_id = os::current_thread_id(); intx invalid_id = -1; int log_fd; - if (_fatal_log_init_thread == invalid_id && Atomic::cmpxchg(&_fatal_log_init_thread, invalid_id, current_thread_id) == invalid_id) { + if (_first_error_tid == invalid_id && Atomic::cmpxchg(&_first_error_tid, invalid_id, current_thread_id) == invalid_id) { if (ErrorFileToStdout) { log_fd = 1; } else if (ErrorFileToStderr) { @@ -375,14 +378,13 @@ void JVMCI::fatal_log(const char* buf, size_t count) { } } _fatal_log_fd = log_fd; - } else { - // Another thread won the race to initialize the stream. Give it time - // to complete initialization. VM locks cannot be used as the current - // thread might not be attached to the VM (e.g. a native thread started - // within libjvmci). - while (_fatal_log_fd == -1) { - os::naked_short_sleep(50); - } + } else if (_first_error_tid != current_thread_id) { + // This is not the first thread reporting a libjvmci error + tty->print_cr("[thread " INTX_FORMAT " also had an error in the JVMCI native library]", + current_thread_id); + + // Fatal error reporting is single threaded so just block this thread. + os::infinite_sleep(); } fdStream log(_fatal_log_fd); log.write(buf, count); diff --git a/src/hotspot/share/jvmci/jvmci.hpp b/src/hotspot/share/jvmci/jvmci.hpp index 1e9fa08898fc3..49240174967c3 100644 --- a/src/hotspot/share/jvmci/jvmci.hpp +++ b/src/hotspot/share/jvmci/jvmci.hpp @@ -60,14 +60,13 @@ typedef struct _jmetadata *jmetadata; class CompilerThreadCanCallJava : StackObj { private: CompilerThread* _current; // Only non-null if state of thread changed - bool _reset_state; // Value prior to state change, undefined - // if no state change. public: - // Enters a scope in which the ability of the current CompilerThread - // to call Java is specified by `new_state`. This call only makes a - // change if the current thread is a CompilerThread associated with - // a JVMCI compiler whose CompilerThread::_can_call_java is not - // currently `new_state`. + // If the current thread is a CompilerThread associated with + // a JVMCI compiler where CompilerThread::_can_call_java != new_state, + // then _can_call_java is set to `new_state` + // Returns nullptr if no change was made, otherwise the current CompilerThread + static CompilerThread* update(JavaThread* current, bool new_state); + CompilerThreadCanCallJava(JavaThread* current, bool new_state); // Resets CompilerThread::_can_call_java of the current thread if the @@ -117,8 +116,8 @@ class JVMCI : public AllStatic { // The path of the file underlying _fatal_log_fd if it is a normal file. static const char* _fatal_log_filename; - // Native thread id of thread that will initialize _fatal_log_fd. - static volatile intx _fatal_log_init_thread; + // Thread id of the first thread reporting a libjvmci error. + static volatile intx _first_error_tid; // JVMCI event log (shows up in hs_err crash logs). static StringEventLog* _events; diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 6bca2aa644e55..dc3eecd57917e 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -343,6 +343,7 @@ narrowKlass CodeInstaller::record_narrow_metadata_reference(CodeSection* section int index = _oop_recorder->find_index(klass); section->relocate(dest, metadata_Relocation::spec(index)); JVMCI_event_3("narrowKlass[%d of %d] = %s", index, _oop_recorder->metadata_count(), klass->name()->as_C_string()); + guarantee(CompressedKlassPointers::is_encodable(klass), "klass cannot be compressed: %s", klass->external_name()); return CompressedKlassPointers::encode(klass); } #endif diff --git a/src/hotspot/share/jvmci/jvmciCompiler.cpp b/src/hotspot/share/jvmci/jvmciCompiler.cpp index 2b8684f7ab85b..04cdb4b4b4fda 100644 --- a/src/hotspot/share/jvmci/jvmciCompiler.cpp +++ b/src/hotspot/share/jvmci/jvmciCompiler.cpp @@ -87,7 +87,7 @@ void JVMCICompiler::bootstrap(TRAPS) { int len = objectMethods->length(); for (int i = 0; i < len; i++) { methodHandle mh(THREAD, objectMethods->at(i)); - if (!mh->is_native() && !mh->is_static() && !mh->is_initializer()) { + if (!mh->is_native() && !mh->is_static() && !mh->is_object_initializer() && !mh->is_static_initializer()) { ResourceMark rm; int hot_count = 10; // TODO: what's the appropriate value? CompileBroker::compile_method(mh, InvocationEntryBci, CompLevel_full_optimization, mh, hot_count, CompileTask::Reason_Bootstrap, CHECK); diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index d231fbe8a6a0e..7922a6816393b 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -184,7 +184,8 @@ Handle JavaArgumentUnboxer::next_arg(BasicType expectedType) { JVMCI_VM_ENTRY_MARK; \ ResourceMark rm; \ bool __is_hotspot = env == thread->jni_environment(); \ - CompilerThreadCanCallJava ccj(thread, __is_hotspot); \ + bool __block_can_call_java = __is_hotspot || !thread->is_Compiler_thread() || CompilerThread::cast(thread)->can_call_java(); \ + CompilerThreadCanCallJava ccj(thread, __block_can_call_java); \ JVMCIENV_FROM_JNI(JVMCI::compilation_tick(thread), env); \ // Entry to native method implementation that transitions @@ -401,6 +402,11 @@ C2V_VMENTRY_NULL(jobject, asResolvedJavaMethod, (JNIEnv* env, jobject, jobject e return JVMCIENV->get_jobject(result); } +C2V_VMENTRY_PREFIX(jboolean, updateCompilerThreadCanCallJava, (JNIEnv* env, jobject, jboolean newState)) + return CompilerThreadCanCallJava::update(thread, newState) != nullptr; +C2V_END + + C2V_VMENTRY_NULL(jobject, getResolvedJavaMethod, (JNIEnv* env, jobject, jobject base, jlong offset)) Method* method = nullptr; JVMCIObject base_object = JVMCIENV->wrap(base); @@ -2178,7 +2184,7 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, A GrowableArray constructors_array; for (int i = 0; i < iklass->methods()->length(); i++) { Method* m = iklass->methods()->at(i); - if (m->is_initializer() && !m->is_static()) { + if (m->is_object_initializer()) { constructors_array.append(m); } } @@ -2205,7 +2211,7 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, ARGUME GrowableArray methods_array; for (int i = 0; i < iklass->methods()->length(); i++) { Method* m = iklass->methods()->at(i); - if (!m->is_initializer() && !m->is_overpass()) { + if (!m->is_object_initializer() && !m->is_static_initializer() && !m->is_overpass()) { methods_array.append(m); } } @@ -2921,12 +2927,11 @@ C2V_VMENTRY_NULL(jobject, asReflectionExecutable, (JNIEnv* env, jobject, ARGUMEN requireInHotSpot("asReflectionExecutable", JVMCI_CHECK_NULL); methodHandle m(THREAD, UNPACK_PAIR(Method, method)); oop executable; - if (m->is_initializer()) { - if (m->is_static_initializer()) { - JVMCI_THROW_MSG_NULL(IllegalArgumentException, - "Cannot create java.lang.reflect.Method for class initializer"); - } + if (m->is_object_initializer()) { executable = Reflection::new_constructor(m, CHECK_NULL); + } else if (m->is_static_initializer()) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, + "Cannot create java.lang.reflect.Method for class initializer"); } else { executable = Reflection::new_method(m, false, CHECK_NULL); } @@ -3387,6 +3392,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "notifyCompilerPhaseEvent", CC "(JIII)V", FN_PTR(notifyCompilerPhaseEvent)}, {CC "notifyCompilerInliningEvent", CC "(I" HS_METHOD2 HS_METHOD2 "ZLjava/lang/String;I)V", FN_PTR(notifyCompilerInliningEvent)}, {CC "getOopMapAt", CC "(" HS_METHOD2 "I[J)V", FN_PTR(getOopMapAt)}, + {CC "updateCompilerThreadCanCallJava", CC "(Z)Z", FN_PTR(updateCompilerThreadCanCallJava)}, }; int CompilerToVM::methods_count() { diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 1612038008a32..ab536a81e6e1b 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -36,8 +36,6 @@ #include "gc/shared/gc_globals.hpp" #include "gc/shared/tlab_globals.hpp" #if INCLUDE_ZGC -#include "gc/x/xBarrierSetRuntime.hpp" -#include "gc/x/xThreadLocalData.hpp" #include "gc/z/zBarrierSetRuntime.hpp" #include "gc/z/zThreadLocalData.hpp" #endif @@ -173,23 +171,9 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) { #if INCLUDE_ZGC if (UseZGC) { - if (ZGenerational) { - ZPointerVectorLoadBadMask_address = (address) &ZPointerVectorLoadBadMask; - ZPointerVectorStoreBadMask_address = (address) &ZPointerVectorStoreBadMask; - ZPointerVectorStoreGoodMask_address = (address) &ZPointerVectorStoreGoodMask; - } else { - thread_address_bad_mask_offset = in_bytes(XThreadLocalData::address_bad_mask_offset()); - // Initialize the old names for compatibility. The proper XBarrierSetRuntime names are - // exported as addresses in vmStructs_jvmci.cpp as are the new ZBarrierSetRuntime names. - ZBarrierSetRuntime_load_barrier_on_oop_field_preloaded = XBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(); - ZBarrierSetRuntime_load_barrier_on_weak_oop_field_preloaded = XBarrierSetRuntime::load_barrier_on_weak_oop_field_preloaded_addr(); - ZBarrierSetRuntime_load_barrier_on_phantom_oop_field_preloaded = XBarrierSetRuntime::load_barrier_on_phantom_oop_field_preloaded_addr(); - ZBarrierSetRuntime_weak_load_barrier_on_oop_field_preloaded = XBarrierSetRuntime::weak_load_barrier_on_oop_field_preloaded_addr(); - ZBarrierSetRuntime_weak_load_barrier_on_weak_oop_field_preloaded = XBarrierSetRuntime::weak_load_barrier_on_weak_oop_field_preloaded_addr(); - ZBarrierSetRuntime_weak_load_barrier_on_phantom_oop_field_preloaded = XBarrierSetRuntime::weak_load_barrier_on_phantom_oop_field_preloaded_addr(); - ZBarrierSetRuntime_load_barrier_on_oop_array = XBarrierSetRuntime::load_barrier_on_oop_array_addr(); - ZBarrierSetRuntime_clone = XBarrierSetRuntime::clone_addr(); - } + ZPointerVectorLoadBadMask_address = (address) &ZPointerVectorLoadBadMask; + ZPointerVectorStoreBadMask_address = (address) &ZPointerVectorStoreBadMask; + ZPointerVectorStoreGoodMask_address = (address) &ZPointerVectorStoreGoodMask; } #endif diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 13b208932199a..45ad1f577be3b 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -38,6 +38,7 @@ #include "runtime/continuationEntry.hpp" #include "runtime/deoptimization.hpp" #include "runtime/flags/jvmFlag.hpp" +#include "runtime/objectMonitor.hpp" #include "runtime/osThread.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" @@ -49,7 +50,6 @@ #include "gc/g1/g1ThreadLocalData.hpp" #endif #if INCLUDE_ZGC -#include "gc/x/xBarrierSetRuntime.hpp" #include "gc/z/zBarrierSetAssembler.hpp" #include "gc/z/zBarrierSetRuntime.hpp" #include "gc/z/zThreadLocalData.hpp" @@ -131,6 +131,7 @@ static_field(CompilerToVM::Data, dsin, address) \ static_field(CompilerToVM::Data, dcos, address) \ static_field(CompilerToVM::Data, dtan, address) \ + static_field(CompilerToVM::Data, dtanh, address) \ static_field(CompilerToVM::Data, dexp, address) \ static_field(CompilerToVM::Data, dlog, address) \ static_field(CompilerToVM::Data, dlog10, address) \ @@ -240,7 +241,6 @@ nonstatic_field(JavaThread, _jvmci_reserved_oop0, oop) \ nonstatic_field(JavaThread, _should_post_on_exceptions_flag, int) \ nonstatic_field(JavaThread, _jni_environment, JNIEnv) \ - nonstatic_field(JavaThread, _poll_data, SafepointMechanism::ThreadData) \ nonstatic_field(JavaThread, _stack_overflow_state._reserved_stack_activation, address) \ nonstatic_field(JavaThread, _held_monitor_count, intx) \ nonstatic_field(JavaThread, _lock_stack, LockStack) \ @@ -248,7 +248,6 @@ nonstatic_field(JavaThread, _cont_entry, ContinuationEntry*) \ nonstatic_field(JavaThread, _unlocked_inflated_monitor, ObjectMonitor*) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \ - JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_tmp_VTMS_transition, bool)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \ \ nonstatic_field(ContinuationEntry, _pin_count, uint32_t) \ @@ -408,6 +407,7 @@ static_field(StubRoutines, _cont_thaw, address) \ static_field(StubRoutines, _lookup_secondary_supers_table_slow_path_stub, address) \ \ + nonstatic_field(Thread, _poll_data, SafepointMechanism::ThreadData) \ nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \ nonstatic_field(Thread, _allocated_bytes, jlong) \ JFR_ONLY(nonstatic_field(Thread, _jfr_thread_local, JfrThreadLocal)) \ @@ -831,21 +831,13 @@ declare_function(os::javaTimeMillis) \ declare_function(os::javaTimeNanos) \ \ - ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, XBarrierSetRuntime::load_barrier_on_oop_field_preloaded)) \ - ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, XBarrierSetRuntime::load_barrier_on_weak_oop_field_preloaded)) \ - ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, XBarrierSetRuntime::load_barrier_on_phantom_oop_field_preloaded)) \ - ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, XBarrierSetRuntime::weak_load_barrier_on_oop_field_preloaded)) \ - ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, XBarrierSetRuntime::weak_load_barrier_on_weak_oop_field_preloaded)) \ - ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, XBarrierSetRuntime::weak_load_barrier_on_phantom_oop_field_preloaded)) \ - ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, XBarrierSetRuntime::load_barrier_on_oop_array)) \ - ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, XBarrierSetRuntime::clone)) \ - \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::load_barrier_on_weak_oop_field_preloaded)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::load_barrier_on_phantom_oop_field_preloaded)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_store_good)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::no_keepalive_load_barrier_on_weak_oop_field_preloaded)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::no_keepalive_load_barrier_on_phantom_oop_field_preloaded)) \ + ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing)) \ diff --git a/src/hotspot/share/libadt/vectset.cpp b/src/hotspot/share/libadt/vectset.cpp index b0d5d100400e7..e2eb08b1a3499 100644 --- a/src/hotspot/share/libadt/vectset.cpp +++ b/src/hotspot/share/libadt/vectset.cpp @@ -49,9 +49,7 @@ void VectorSet::init(Arena* arena) { // Expand the existing set to a bigger size void VectorSet::grow(uint new_word_capacity) { _nesting.check(_set_arena); // Check if a potential reallocation in the arena is safe - if (new_word_capacity < _size) { - return; // No need to grow - } + assert(new_word_capacity >= _size, "Should have been checked before, use maybe_grow?"); assert(new_word_capacity < (1U << 30), ""); uint x = next_power_of_2(new_word_capacity); if (x > _data_size) { @@ -66,9 +64,7 @@ void VectorSet::grow(uint new_word_capacity) { void VectorSet::insert(uint elem) { uint32_t word = elem >> word_bits; uint32_t mask = 1U << (elem & bit_mask); - if (word >= _size) { - grow(word); - } + maybe_grow(word); _data[word] |= mask; } diff --git a/src/hotspot/share/libadt/vectset.hpp b/src/hotspot/share/libadt/vectset.hpp index eafa60db1fee2..fee15566f2435 100644 --- a/src/hotspot/share/libadt/vectset.hpp +++ b/src/hotspot/share/libadt/vectset.hpp @@ -49,8 +49,15 @@ class VectorSet : public AnyObj { ReallocMark _nesting; // Safety checks for arena reallocation void init(Arena* arena); + // Grow vector to required word capacity + void maybe_grow(uint new_word_capacity) { + if (new_word_capacity >= _size) { + grow(new_word_capacity); + } + } void grow(uint new_word_capacity); + public: VectorSet(); VectorSet(Arena* arena); @@ -78,7 +85,7 @@ class VectorSet : public AnyObj { // bool test_set(uint elem) { uint32_t word = elem >> word_bits; - grow(word); + maybe_grow(word); uint32_t mask = 1U << (elem & bit_mask); uint32_t data = _data[word]; _data[word] = data | mask; @@ -107,7 +114,7 @@ class VectorSet : public AnyObj { // Fast inlined set void set(uint elem) { uint32_t word = elem >> word_bits; - grow(word); + maybe_grow(word); uint32_t mask = 1U << (elem & bit_mask); _data[word] |= mask; } diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp index 87b195f4fbfdd..dfddfff2f05c0 100644 --- a/src/hotspot/share/logging/logConfiguration.cpp +++ b/src/hotspot/share/logging/logConfiguration.cpp @@ -491,7 +491,7 @@ bool LogConfiguration::parse_log_arguments(const char* outputstr, return false; } - LogDecorators decorators; + LogDecorators decorators = selections.get_default_decorators(); if (!decorators.parse(decoratorstr, errstream)) { return false; } diff --git a/src/hotspot/share/logging/logDecorators.cpp b/src/hotspot/share/logging/logDecorators.cpp index 91677b35d9f95..6c06bd4571627 100644 --- a/src/hotspot/share/logging/logDecorators.cpp +++ b/src/hotspot/share/logging/logDecorators.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ #include "logging/logDecorators.hpp" #include "runtime/os.hpp" +const LogLevelType AnyLevel = LogLevelType::NotMentioned; + template struct AllBitmask { // Use recursive template deduction to calculate the bitmask of all decorations. @@ -45,6 +47,19 @@ const char* LogDecorators::_name[][2] = { #undef DECORATOR }; +#define UNDECORATED_DEFAULTS \ + UNDECORATED_DEFAULT(AnyLevel, LOG_TAGS(jit, inlining)) + +const LogDecorators::DefaultUndecoratedSelection LogDecorators::default_decorators[] = { +#define UNDECORATED_DEFAULT(level, ...) LogDecorators::DefaultUndecoratedSelection::make(), + UNDECORATED_DEFAULTS +#undef UNDECORATED_DEFAULT +}; + +#undef UNDERCORATED_DEFAULTS + +const size_t LogDecorators::number_of_default_decorators = ARRAY_SIZE(default_decorators); + LogDecorators::Decorator LogDecorators::from_string(const char* str) { for (size_t i = 0; i < Count; i++) { Decorator d = static_cast(i); @@ -57,7 +72,7 @@ LogDecorators::Decorator LogDecorators::from_string(const char* str) { bool LogDecorators::parse(const char* decorator_args, outputStream* errstream) { if (decorator_args == nullptr || strlen(decorator_args) == 0) { - _decorators = DefaultDecoratorsMask; + // No decorators supplied, keep default decorators return true; } @@ -93,3 +108,16 @@ bool LogDecorators::parse(const char* decorator_args, outputStream* errstream) { } return result; } + +bool LogDecorators::has_disabled_default_decorators(const LogSelection& selection, const DefaultUndecoratedSelection* defaults, size_t defaults_count) { + for (size_t i = 0; i < defaults_count; ++i) { + DefaultUndecoratedSelection current_default = defaults[i]; + const bool ignore_level = current_default.selection().level() == AnyLevel; + const bool level_matches = ignore_level || selection.level() == current_default.selection().level(); + if (!level_matches) continue; + if (selection.superset_of(current_default.selection())) { + return true; + } + } + return false; +} diff --git a/src/hotspot/share/logging/logDecorators.hpp b/src/hotspot/share/logging/logDecorators.hpp index b92de0fdb98ce..9e38f429974a1 100644 --- a/src/hotspot/share/logging/logDecorators.hpp +++ b/src/hotspot/share/logging/logDecorators.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #define SHARE_LOGGING_LOGDECORATORS_HPP #include "utilities/globalDefinitions.hpp" +#include "logging/logSelection.hpp" class outputStream; @@ -59,6 +60,7 @@ class outputStream; // declared above. For example, logging with 'uptime, level, tags' decorators results in: // [0,943s][info ][logging] message. class LogDecorators { + friend class TestLogDecorators; public: enum Decorator { #define DECORATOR(name, abbr) name##_decorator, @@ -68,24 +70,48 @@ class LogDecorators { Invalid }; + class DefaultUndecoratedSelection { + friend class TestLogDecorators; + LogSelection _selection; + + DefaultUndecoratedSelection() : _selection(LogSelection::Invalid) {} + + DefaultUndecoratedSelection(LogLevelType level, LogTagType t0, LogTagType t1, LogTagType t2, + LogTagType t3, LogTagType t4) : _selection(LogSelection::Invalid) { + LogTagType tag_arr[LogTag::MaxTags] = { t0, t1, t2, t3, t4 }; + _selection = LogSelection(tag_arr, false, level); + } + + public: + template + static DefaultUndecoratedSelection make() { + STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); + return DefaultUndecoratedSelection(Level, T0, T1, T2, T3, T4); + } + + const LogSelection& selection() const { return _selection; } + }; + private: uint _decorators; static const char* _name[][2]; - static const uint DefaultDecoratorsMask = (1 << uptime_decorator) | (1 << level_decorator) | (1 << tags_decorator); + static const uint defaultsMask = (1 << uptime_decorator) | (1 << level_decorator) | (1 << tags_decorator); + static const LogDecorators::DefaultUndecoratedSelection default_decorators[]; + static const size_t number_of_default_decorators; static uint mask(LogDecorators::Decorator decorator) { return 1 << decorator; } - constexpr LogDecorators(uint mask) : _decorators(mask) { - } public: static const LogDecorators None; static const LogDecorators All; - LogDecorators() : _decorators(DefaultDecoratorsMask) { - } + constexpr LogDecorators(uint mask) : _decorators(mask) {} + + LogDecorators() : _decorators(defaultsMask) {} void clear() { _decorators = 0; @@ -99,6 +125,20 @@ class LogDecorators { return _name[decorator][1]; } + template + static uint mask_from_decorators(LogDecorators::Decorator first, Decorators... rest) { + uint bitmask = 0; + LogDecorators::Decorator decorators[1 + sizeof...(rest)] = { first, rest... }; + for (const LogDecorators::Decorator decorator : decorators) { + bitmask |= mask(decorator); + } + return bitmask; + } + + // Check if we have some default decorators for a given LogSelection. If that is the case, + // the output parameter mask will contain the defaults-specified decorators mask + static bool has_disabled_default_decorators(const LogSelection& selection, const DefaultUndecoratedSelection* defaults = default_decorators, size_t defaults_count = number_of_default_decorators); + static LogDecorators::Decorator from_string(const char* str); void combine_with(const LogDecorators &source) { diff --git a/src/hotspot/share/logging/logSelection.cpp b/src/hotspot/share/logging/logSelection.cpp index 1e7ba3a887848..99ecc9f87f272 100644 --- a/src/hotspot/share/logging/logSelection.cpp +++ b/src/hotspot/share/logging/logSelection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,6 +69,23 @@ bool LogSelection::operator!=(const LogSelection& ref) const { return !operator==(ref); } +bool LogSelection::superset_of(const LogSelection& other) const { + bool match; + for (size_t i = 0; i < other.ntags(); ++i) { + match = false; + for (size_t j = 0; j < _ntags; ++j) { + if (other._tags[i] == _tags[j]) { + match = true; + break; + } + } + + if (!match) return false; + } + + return true; +} + static LogSelection parse_internal(char *str, outputStream* errstream) { // Parse the level, if specified LogLevelType level = LogLevel::Unspecified; diff --git a/src/hotspot/share/logging/logSelection.hpp b/src/hotspot/share/logging/logSelection.hpp index 7f4c1fb8e95e3..4555590295a5d 100644 --- a/src/hotspot/share/logging/logSelection.hpp +++ b/src/hotspot/share/logging/logSelection.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,8 @@ class LogSelection : public StackObj { bool operator==(const LogSelection& ref) const; bool operator!=(const LogSelection& ref) const; + bool superset_of(const LogSelection& ref) const; + size_t ntags() const; LogLevelType level() const; size_t tag_sets_selected() const; diff --git a/src/hotspot/share/logging/logSelectionList.cpp b/src/hotspot/share/logging/logSelectionList.cpp index 1eb4cca0c3e50..ac63f20512c2a 100644 --- a/src/hotspot/share/logging/logSelectionList.cpp +++ b/src/hotspot/share/logging/logSelectionList.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,14 @@ bool LogSelectionList::verify_selections(outputStream* out) const { return valid; } +LogDecorators LogSelectionList::get_default_decorators() const { + for (size_t i = 0; i < _nselections; ++i) { + if (!LogDecorators::has_disabled_default_decorators(_selections[i])) { + return LogDecorators(); + } + } + return LogDecorators::None; +} bool LogSelectionList::parse(const char* str, outputStream* errstream) { bool success = true; @@ -91,7 +99,7 @@ bool LogSelectionList::parse(const char* str, outputStream* errstream) { LogLevelType LogSelectionList::level_for(const LogTagSet& ts) const { // Return NotMentioned if the given tagset isn't covered by this expression. LogLevelType level = LogLevel::NotMentioned; - for (size_t i= 0; i < _nselections; i++) { + for (size_t i = 0; i < _nselections; i++) { if (_selections[i].selects(ts)) { level = _selections[i].level(); } diff --git a/src/hotspot/share/logging/logSelectionList.hpp b/src/hotspot/share/logging/logSelectionList.hpp index 6bd2c6608bc87..0852348cc1463 100644 --- a/src/hotspot/share/logging/logSelectionList.hpp +++ b/src/hotspot/share/logging/logSelectionList.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,6 +60,8 @@ class LogSelectionList : public StackObj { // Returns false if some invalid selection was found. If given an outputstream, // this function will list all the invalid selections on the stream. bool verify_selections(outputStream* out = nullptr) const; + + LogDecorators get_default_decorators() const; }; #endif // SHARE_LOGGING_LOGSELECTIONLIST_HPP diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp index fc405a389ee85..7076a6a09bbfe 100644 --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -56,7 +56,6 @@ class Metaspace : public AllStatic { StandardMetaspaceType = ZeroMetaspaceType, BootMetaspaceType = StandardMetaspaceType + 1, ClassMirrorHolderMetaspaceType = BootMetaspaceType + 1, - ReflectionMetaspaceType = ClassMirrorHolderMetaspaceType + 1, MetaspaceTypeCount }; diff --git a/src/hotspot/share/memory/metaspace/metaspaceArenaGrowthPolicy.cpp b/src/hotspot/share/memory/metaspace/metaspaceArenaGrowthPolicy.cpp index 592624c25f081..0698c1509cf38 100644 --- a/src/hotspot/share/memory/metaspace/metaspaceArenaGrowthPolicy.cpp +++ b/src/hotspot/share/memory/metaspace/metaspaceArenaGrowthPolicy.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. * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -61,17 +61,6 @@ static const chunklevel_t g_sequ_anon_class[] = { // .. repeat last }; -static const chunklevel_t g_sequ_refl_non_class[] = { - chunklevel::CHUNK_LEVEL_2K, - chunklevel::CHUNK_LEVEL_1K - // .. repeat last -}; - -static const chunklevel_t g_sequ_refl_class[] = { - chunklevel::CHUNK_LEVEL_1K, - // .. repeat last -}; - // Boot class loader: give it large chunks: beyond commit granule size // (typically 64K) the costs for large chunks largely diminishes since // they are committed on the fly. @@ -95,15 +84,12 @@ const ArenaGrowthPolicy* ArenaGrowthPolicy::policy_for_space_type(Metaspace::Met DEFINE_CLASS_FOR_ARRAY(standard_class) DEFINE_CLASS_FOR_ARRAY(anon_non_class) DEFINE_CLASS_FOR_ARRAY(anon_class) - DEFINE_CLASS_FOR_ARRAY(refl_non_class) - DEFINE_CLASS_FOR_ARRAY(refl_class) DEFINE_CLASS_FOR_ARRAY(boot_non_class) DEFINE_CLASS_FOR_ARRAY(boot_class) if (is_class) { switch(space_type) { case Metaspace::StandardMetaspaceType: return &chunk_alloc_sequence_standard_class; - case Metaspace::ReflectionMetaspaceType: return &chunk_alloc_sequence_refl_class; case Metaspace::ClassMirrorHolderMetaspaceType: return &chunk_alloc_sequence_anon_class; case Metaspace::BootMetaspaceType: return &chunk_alloc_sequence_boot_class; default: ShouldNotReachHere(); @@ -111,7 +97,6 @@ const ArenaGrowthPolicy* ArenaGrowthPolicy::policy_for_space_type(Metaspace::Met } else { switch(space_type) { case Metaspace::StandardMetaspaceType: return &chunk_alloc_sequence_standard_non_class; - case Metaspace::ReflectionMetaspaceType: return &chunk_alloc_sequence_refl_non_class; case Metaspace::ClassMirrorHolderMetaspaceType: return &chunk_alloc_sequence_anon_non_class; case Metaspace::BootMetaspaceType: return &chunk_alloc_sequence_boot_non_class; default: ShouldNotReachHere(); diff --git a/src/hotspot/share/memory/metaspace/metaspaceReporter.cpp b/src/hotspot/share/memory/metaspace/metaspaceReporter.cpp index c154fd1db2557..3cd9ba5ab87ae 100644 --- a/src/hotspot/share/memory/metaspace/metaspaceReporter.cpp +++ b/src/hotspot/share/memory/metaspace/metaspaceReporter.cpp @@ -49,7 +49,6 @@ static const char* describe_spacetype(Metaspace::MetaspaceType st) { case Metaspace::StandardMetaspaceType: s = "Standard"; break; case Metaspace::BootMetaspaceType: s = "Boot"; break; case Metaspace::ClassMirrorHolderMetaspaceType: s = "ClassMirrorHolder"; break; - case Metaspace::ReflectionMetaspaceType: s = "Reflection"; break; default: ShouldNotReachHere(); } return s; diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp index 0cc81ce85a617..614a3ab784bbb 100644 --- a/src/hotspot/share/memory/virtualspace.cpp +++ b/src/hotspot/share/memory/virtualspace.cpp @@ -369,6 +369,9 @@ ReservedSpace ReservedSpace::space_for_range(char* base, size_t size, size_t ali return space; } +// Compressed oop support is not relevant in 32bit builds. +#ifdef _LP64 + static size_t noaccess_prefix_size(size_t alignment) { return lcm(os::vm_page_size(), alignment); } @@ -594,8 +597,8 @@ void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t ali // Try to attach at addresses that are aligned to OopEncodingHeapMax. Disjointbase mode. char** addresses = get_attach_addresses_for_disjoint_mode(); int i = 0; - while (addresses[i] && // End of array not yet reached. - ((_base == nullptr) || // No previous try succeeded. + while ((addresses[i] != nullptr) && // End of array not yet reached. + ((_base == nullptr) || // No previous try succeeded. (_base + size > (char *)OopEncodingHeapMax && // Not zerobased or unscaled address. !CompressedOops::is_disjoint_heap_base_address((address)_base)))) { // Not disjoint address. char* const attach_point = addresses[i]; @@ -612,6 +615,8 @@ void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t ali } } +#endif // _LP64 + ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, size_t page_size, const char* heap_allocation_directory) : ReservedSpace() { if (size == 0) { @@ -636,6 +641,7 @@ ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, size_t page_ guarantee(is_aligned(size, alignment), "set by caller"); if (UseCompressedOops) { +#ifdef _LP64 initialize_compressed_heap(size, alignment, page_size); if (_size > size) { // We allocated heap with noaccess prefix. @@ -643,6 +649,9 @@ ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, size_t page_ // if we had to try at arbitrary address. establish_noaccess_prefix(); } +#else + ShouldNotReachHere(); +#endif // _LP64 } else { initialize(size, alignment, page_size, nullptr, false); } diff --git a/src/hotspot/share/memory/virtualspace.hpp b/src/hotspot/share/memory/virtualspace.hpp index 046ad0cf7a420..022bcabe7536f 100644 --- a/src/hotspot/share/memory/virtualspace.hpp +++ b/src/hotspot/share/memory/virtualspace.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 @@ -133,6 +133,10 @@ ReservedSpace ReservedSpace::partition(size_t offset, size_t partition_size) // Class encapsulating behavior specific of memory space reserved for Java heap. class ReservedHeapSpace : public ReservedSpace { private: + + // Compressed oop support is not relevant in 32bit builds. +#ifdef _LP64 + void try_reserve_heap(size_t size, size_t alignment, size_t page_size, char *requested_address); void try_reserve_range(char *highest_start, char *lowest_start, @@ -141,6 +145,9 @@ class ReservedHeapSpace : public ReservedSpace { void initialize_compressed_heap(const size_t size, size_t alignment, size_t page_size); // Create protection page at the beginning of the space. void establish_noaccess_prefix(); + +#endif // _LP64 + public: // Constructor. Tries to find a heap that is good for compressed oops. // heap_allocation_directory is the path to the backing memory for Java heap. When set, Java heap will be allocated diff --git a/src/hotspot/share/nmt/memBaseline.cpp b/src/hotspot/share/nmt/memBaseline.cpp index 6f82b2de9f106..270601e9c057b 100644 --- a/src/hotspot/share/nmt/memBaseline.cpp +++ b/src/hotspot/share/nmt/memBaseline.cpp @@ -141,7 +141,7 @@ void MemBaseline::baseline_summary() { MallocMemorySummary::snapshot(&_malloc_memory_snapshot); VirtualMemorySummary::snapshot(&_virtual_memory_snapshot); { - MemoryFileTracker::Instance::Locker lock; + NmtVirtualMemoryLocker ml; MemoryFileTracker::Instance::summary_snapshot(&_virtual_memory_snapshot); } diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index 6ce6206ebcc2a..15767da276c1b 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -465,7 +465,7 @@ void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* void MemDetailReporter::report_memory_file_allocations() { stringStream st; { - MemoryFileTracker::Instance::Locker lock; + NmtVirtualMemoryLocker ml; MemoryFileTracker::Instance::print_all_reports_on(&st, scale()); } output()->print_raw(st.freeze()); diff --git a/src/hotspot/share/nmt/memTracker.hpp b/src/hotspot/share/nmt/memTracker.hpp index 6ba1db2e7ffe6..92640430e1c7b 100644 --- a/src/hotspot/share/nmt/memTracker.hpp +++ b/src/hotspot/share/nmt/memTracker.hpp @@ -31,7 +31,6 @@ #include "nmt/threadStackTracker.hpp" #include "nmt/virtualMemoryTracker.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/threadCritical.hpp" #include "utilities/debug.hpp" #include "utilities/nativeCallStack.hpp" @@ -125,7 +124,7 @@ class MemTracker : AllStatic { assert_post_init(); if (!enabled()) return; if (addr != nullptr) { - ThreadCritical tc; + NmtVirtualMemoryLocker ml; VirtualMemoryTracker::add_reserved_region((address)addr, size, stack, mem_tag); } } @@ -151,7 +150,7 @@ class MemTracker : AllStatic { assert_post_init(); if (!enabled()) return; if (addr != nullptr) { - ThreadCritical tc; + NmtVirtualMemoryLocker ml; VirtualMemoryTracker::add_reserved_region((address)addr, size, stack, mem_tag); VirtualMemoryTracker::add_committed_region((address)addr, size, stack); } @@ -162,7 +161,7 @@ class MemTracker : AllStatic { assert_post_init(); if (!enabled()) return; if (addr != nullptr) { - ThreadCritical tc; + NmtVirtualMemoryLocker ml; VirtualMemoryTracker::add_committed_region((address)addr, size, stack); } } @@ -170,7 +169,7 @@ class MemTracker : AllStatic { static inline MemoryFileTracker::MemoryFile* register_file(const char* descriptive_name) { assert_post_init(); if (!enabled()) return nullptr; - MemoryFileTracker::Instance::Locker lock; + NmtVirtualMemoryLocker ml; return MemoryFileTracker::Instance::make_file(descriptive_name); } @@ -178,7 +177,7 @@ class MemTracker : AllStatic { assert_post_init(); if (!enabled()) return; assert(file != nullptr, "must be"); - MemoryFileTracker::Instance::Locker lock; + NmtVirtualMemoryLocker ml; MemoryFileTracker::Instance::free_file(file); } @@ -187,7 +186,7 @@ class MemTracker : AllStatic { assert_post_init(); if (!enabled()) return; assert(file != nullptr, "must be"); - MemoryFileTracker::Instance::Locker lock; + NmtVirtualMemoryLocker ml; MemoryFileTracker::Instance::allocate_memory(file, offset, size, stack, mem_tag); } @@ -196,7 +195,7 @@ class MemTracker : AllStatic { assert_post_init(); if (!enabled()) return; assert(file != nullptr, "must be"); - MemoryFileTracker::Instance::Locker lock; + NmtVirtualMemoryLocker ml; MemoryFileTracker::Instance::free_memory(file, offset, size); } @@ -210,7 +209,7 @@ class MemTracker : AllStatic { assert_post_init(); if (!enabled()) return; if (addr != nullptr) { - ThreadCritical tc; + NmtVirtualMemoryLocker ml; VirtualMemoryTracker::split_reserved_region((address)addr, size, split, mem_tag, split_tag); } } @@ -219,7 +218,7 @@ class MemTracker : AllStatic { assert_post_init(); if (!enabled()) return; if (addr != nullptr) { - ThreadCritical tc; + NmtVirtualMemoryLocker ml; VirtualMemoryTracker::set_reserved_region_type((address)addr, mem_tag); } } diff --git a/src/hotspot/share/nmt/memoryFileTracker.cpp b/src/hotspot/share/nmt/memoryFileTracker.cpp index ede483ed33727..ab4f8b6d1f3c6 100644 --- a/src/hotspot/share/nmt/memoryFileTracker.cpp +++ b/src/hotspot/share/nmt/memoryFileTracker.cpp @@ -29,13 +29,11 @@ #include "nmt/nmtCommon.hpp" #include "nmt/nmtNativeCallStackStorage.hpp" #include "nmt/vmatree.hpp" -#include "runtime/mutex.hpp" #include "utilities/growableArray.hpp" #include "utilities/nativeCallStack.hpp" #include "utilities/ostream.hpp" MemoryFileTracker* MemoryFileTracker::Instance::_tracker = nullptr; -PlatformMutex* MemoryFileTracker::Instance::_mutex = nullptr; MemoryFileTracker::MemoryFileTracker(bool is_detailed_mode) : _stack_storage(is_detailed_mode), _files() {} @@ -132,7 +130,6 @@ bool MemoryFileTracker::Instance::initialize(NMT_TrackingLevel tracking_level) { _tracker = static_cast(os::malloc(sizeof(MemoryFileTracker), mtNMT)); if (_tracker == nullptr) return false; new (_tracker) MemoryFileTracker(tracking_level == NMT_TrackingLevel::NMT_detail); - _mutex = new PlatformMutex(); return true; } @@ -193,11 +190,3 @@ void MemoryFileTracker::summary_snapshot(VirtualMemorySnapshot* snapshot) const void MemoryFileTracker::Instance::summary_snapshot(VirtualMemorySnapshot* snapshot) { _tracker->summary_snapshot(snapshot); } - -MemoryFileTracker::Instance::Locker::Locker() { - MemoryFileTracker::Instance::_mutex->lock(); -} - -MemoryFileTracker::Instance::Locker::~Locker() { - MemoryFileTracker::Instance::_mutex->unlock(); -} diff --git a/src/hotspot/share/nmt/memoryFileTracker.hpp b/src/hotspot/share/nmt/memoryFileTracker.hpp index 42902701a16df..911f10baf9806 100644 --- a/src/hotspot/share/nmt/memoryFileTracker.hpp +++ b/src/hotspot/share/nmt/memoryFileTracker.hpp @@ -30,7 +30,6 @@ #include "nmt/nmtNativeCallStackStorage.hpp" #include "nmt/virtualMemoryTracker.hpp" #include "nmt/vmatree.hpp" -#include "runtime/mutex.hpp" #include "runtime/os.inline.hpp" #include "utilities/growableArray.hpp" #include "utilities/nativeCallStack.hpp" @@ -81,14 +80,8 @@ class MemoryFileTracker { class Instance : public AllStatic { static MemoryFileTracker* _tracker; - static PlatformMutex* _mutex; public: - class Locker : public StackObj { - public: - Locker(); - ~Locker(); - }; static bool initialize(NMT_TrackingLevel tracking_level); diff --git a/src/hotspot/share/nmt/nmtCommon.hpp b/src/hotspot/share/nmt/nmtCommon.hpp index 3f72960f21fde..4422d34063456 100644 --- a/src/hotspot/share/nmt/nmtCommon.hpp +++ b/src/hotspot/share/nmt/nmtCommon.hpp @@ -29,6 +29,7 @@ #include "memory/allStatic.hpp" #include "nmt/memTag.hpp" +#include "runtime/mutexLocker.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" @@ -137,5 +138,13 @@ class NMTUtil : AllStatic { static S _strings[mt_number_of_tags]; }; +// Same as MutexLocker but can be used during VM init. +// Performs no action if given a null mutex or with detached threads. +class NmtVirtualMemoryLocker: public ConditionalMutexLocker { +public: + NmtVirtualMemoryLocker() : + ConditionalMutexLocker(NmtVirtualMemory_lock, Thread::current_or_null_safe() != nullptr, Mutex::_no_safepoint_check_flag) { + } +}; #endif // SHARE_NMT_NMTCOMMON_HPP diff --git a/src/hotspot/share/nmt/threadStackTracker.cpp b/src/hotspot/share/nmt/threadStackTracker.cpp index 6f112fa8fc5c2..42af67d64649b 100644 --- a/src/hotspot/share/nmt/threadStackTracker.cpp +++ b/src/hotspot/share/nmt/threadStackTracker.cpp @@ -29,7 +29,6 @@ #include "nmt/threadStackTracker.hpp" #include "nmt/virtualMemoryTracker.hpp" #include "runtime/os.hpp" -#include "runtime/threadCritical.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -53,7 +52,7 @@ void ThreadStackTracker::new_thread_stack(void* base, size_t size, const NativeC assert(base != nullptr, "Should have been filtered"); align_thread_stack_boundaries_inward(base, size); - ThreadCritical tc; + NmtVirtualMemoryLocker ml; VirtualMemoryTracker::add_reserved_region((address)base, size, stack, mtThreadStack); _thread_count++; } @@ -63,7 +62,7 @@ void ThreadStackTracker::delete_thread_stack(void* base, size_t size) { assert(base != nullptr, "Should have been filtered"); align_thread_stack_boundaries_inward(base, size); - ThreadCritical tc; + NmtVirtualMemoryLocker ml; VirtualMemoryTracker::remove_released_region((address)base, size); _thread_count--; } diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.cpp b/src/hotspot/share/nmt/virtualMemoryTracker.cpp index d298381f1038f..8b0f2f4d7a4c3 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.cpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.cpp @@ -30,7 +30,6 @@ #include "nmt/threadStackTracker.hpp" #include "nmt/virtualMemoryTracker.hpp" #include "runtime/os.hpp" -#include "runtime/threadCritical.hpp" #include "utilities/ostream.hpp" VirtualMemorySnapshot VirtualMemorySummary::_snapshot; @@ -621,6 +620,7 @@ class SnapshotThreadStackWalker : public VirtualMemoryWalker { SnapshotThreadStackWalker() {} bool do_allocation_site(const ReservedMemoryRegion* rgn) { + assert_lock_strong(NmtVirtualMemory_lock); if (rgn->mem_tag() == mtThreadStack) { address stack_bottom = rgn->thread_stack_uncommitted_bottom(); address committed_start; @@ -661,7 +661,7 @@ void VirtualMemoryTracker::snapshot_thread_stacks() { bool VirtualMemoryTracker::walk_virtual_memory(VirtualMemoryWalker* walker) { assert(_reserved_regions != nullptr, "Sanity check"); - ThreadCritical tc; + NmtVirtualMemoryLocker ml; // Check that the _reserved_regions haven't been deleted. if (_reserved_regions != nullptr) { LinkedListNode* head = _reserved_regions->head(); diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 3795376d4768d..65a5bdb94aef0 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -24,6 +24,7 @@ */ #include "precompiled.hpp" +#include "logging/log.hpp" #include "nmt/vmatree.hpp" #include "utilities/growableArray.hpp" @@ -34,7 +35,9 @@ const char* VMATree::statetype_strings[3] = { }; VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType state, - const RegionData& metadata) { + const RegionData& metadata, bool use_tag_inplace) { + assert(!use_tag_inplace || metadata.mem_tag == mtNone, + "If using use_tag_inplace, then the supplied tag should be mtNone, was instead: %s", NMTUtil::tag_to_name(metadata.mem_tag)); if (A == B) { // A 0-sized mapping isn't worth recording. return SummaryDiff(); @@ -55,6 +58,10 @@ VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType AddressState LEQ_A; TreapNode* leqA_n = _tree.closest_leq(A); if (leqA_n == nullptr) { + assert(!use_tag_inplace, "Cannot use the tag inplace if no pre-existing tag exists. From: " PTR_FORMAT " To: " PTR_FORMAT, A, B); + if (use_tag_inplace) { + log_debug(nmt)("Cannot use the tag inplace if no pre-existing tag exists. From: " PTR_FORMAT " To: " PTR_FORMAT, A, B); + } // No match. We add the A node directly, unless it would have no effect. if (!stA.is_noop()) { _tree.upsert(A, stA); @@ -62,6 +69,17 @@ VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType } else { LEQ_A_found = true; LEQ_A = AddressState{leqA_n->key(), leqA_n->val()}; + StateType leqA_state = leqA_n->val().out.type(); + StateType new_state = stA.out.type(); + // If we specify use_tag_inplace then the new region takes over the current tag instead of the tag in metadata. + // This is important because the VirtualMemoryTracker API doesn't require supplying the tag for some operations. + if (use_tag_inplace) { + assert(leqA_n->val().out.type() != StateType::Released, "Should not use inplace the tag of a released region"); + MemTag tag = leqA_n->val().out.mem_tag(); + stA.out.set_tag(tag); + stB.in.set_tag(tag); + } + // Unless we know better, let B's outgoing state be the outgoing state of the node at or preceding A. // Consider the case where the found node is the start of a region enclosing [A,B) stB.out = leqA_n->val().out; diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index 55399e51b9d22..cfb3c8ab5246d 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -66,7 +66,7 @@ class VMATree { return statetype_strings[static_cast(type)]; } - // Each point has some stack and a flag associated with it. + // Each point has some stack and a tag associated with it. struct RegionData { const NativeCallStackStorage::StackIndex stack_idx; const MemTag mem_tag; @@ -88,30 +88,34 @@ class VMATree { struct IntervalState { private: // Store the type and mem_tag as two bytes - uint8_t type_flag[2]; + uint8_t type_tag[2]; NativeCallStackStorage::StackIndex sidx; public: - IntervalState() : type_flag{0,0}, sidx() {} + IntervalState() : type_tag{0,0}, sidx() {} IntervalState(const StateType type, const RegionData data) { assert(!(type == StateType::Released) || data.mem_tag == mtNone, "Released type must have memory tag mtNone"); - type_flag[0] = static_cast(type); - type_flag[1] = static_cast(data.mem_tag); + type_tag[0] = static_cast(type); + type_tag[1] = static_cast(data.mem_tag); sidx = data.stack_idx; } StateType type() const { - return static_cast(type_flag[0]); + return static_cast(type_tag[0]); } MemTag mem_tag() const { - return static_cast(type_flag[1]); + return static_cast(type_tag[1]); } RegionData regiondata() const { return RegionData{sidx, mem_tag()}; } + void set_tag(MemTag tag) { + type_tag[1] = static_cast(tag); + } + NativeCallStackStorage::StackIndex stack() const { return sidx; } @@ -167,14 +171,20 @@ class VMATree { } }; - SummaryDiff register_mapping(position A, position B, StateType state, const RegionData& metadata); + private: + SummaryDiff register_mapping(position A, position B, StateType state, const RegionData& metadata, bool use_tag_inplace = false); + public: SummaryDiff reserve_mapping(position from, position sz, const RegionData& metadata) { - return register_mapping(from, from + sz, StateType::Reserved, metadata); + return register_mapping(from, from + sz, StateType::Reserved, metadata, false); + } + + SummaryDiff commit_mapping(position from, position sz, const RegionData& metadata, bool use_tag_inplace = false) { + return register_mapping(from, from + sz, StateType::Committed, metadata, use_tag_inplace); } - SummaryDiff commit_mapping(position from, position sz, const RegionData& metadata) { - return register_mapping(from, from + sz, StateType::Committed, metadata); + SummaryDiff uncommit_mapping(position from, position sz, const RegionData& metadata) { + return register_mapping(from, from + sz, StateType::Reserved, metadata, true); } SummaryDiff release_mapping(position from, position sz) { diff --git a/src/hotspot/share/oops/constMethodFlags.hpp b/src/hotspot/share/oops/constMethodFlags.hpp index 236f25ea746fa..031ebe44a9654 100644 --- a/src/hotspot/share/oops/constMethodFlags.hpp +++ b/src/hotspot/share/oops/constMethodFlags.hpp @@ -60,6 +60,7 @@ class ConstMethodFlags { flag(jvmti_mount_transition , 1 << 18) \ flag(deprecated , 1 << 19) \ flag(deprecated_for_removal , 1 << 20) \ + flag(jvmti_hide_events , 1 << 21) \ /* end of list */ #define CM_FLAGS_ENUM_NAME(name, value) _misc_##name = value, diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp index 7a17c62ddaf99..bcc9a08dd6ca0 100644 --- a/src/hotspot/share/oops/constantPool.hpp +++ b/src/hotspot/share/oops/constantPool.hpp @@ -37,6 +37,7 @@ #include "utilities/align.hpp" #include "utilities/bytes.hpp" #include "utilities/constantTag.hpp" +#include "utilities/macros.hpp" #include "utilities/resourceHash.hpp" // A ConstantPool is an array containing class constants as described in the @@ -781,7 +782,7 @@ class ConstantPool : public Metadata { int pre_resolve_shared_klasses(TRAPS); // Debugging - const char* printable_name_at(int cp_index) PRODUCT_RETURN0; + const char* printable_name_at(int cp_index) PRODUCT_RETURN_NULL; private: diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 5e226a90764ee..b522a3948b533 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2452,11 +2452,11 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) { #endif #if INCLUDE_CDS // For "old" classes with methods containing the jsr bytecode, the _methods array will - // be rewritten during runtime (see Rewriter::rewrite_jsrs()). So setting the _methods to - // be writable. The length check on the _methods is necessary because classes which - // don't have any methods share the Universe::_the_empty_method_array which is in the RO region. - if (_methods != nullptr && _methods->length() > 0 && - !can_be_verified_at_dumptime() && methods_contain_jsr_bytecode()) { + // be rewritten during runtime (see Rewriter::rewrite_jsrs()) but they cannot be safely + // checked here with ByteCodeStream. All methods that can't be verified are made writable. + // The length check on the _methods is necessary because classes which don't have any + // methods share the Universe::_the_empty_method_array which is in the RO region. + if (_methods != nullptr && _methods->length() > 0 && !can_be_verified_at_dumptime()) { // To handle jsr bytecode, new Method* maybe stored into _methods it->push(&_methods, MetaspaceClosure::_writable); } else { @@ -2697,21 +2697,6 @@ bool InstanceKlass::can_be_verified_at_dumptime() const { } return true; } - -bool InstanceKlass::methods_contain_jsr_bytecode() const { - Thread* thread = Thread::current(); - for (int i = 0; i < _methods->length(); i++) { - methodHandle m(thread, _methods->at(i)); - BytecodeStream bcs(m); - while (!bcs.is_last_bytecode()) { - Bytecodes::Code opcode = bcs.next(); - if (opcode == Bytecodes::_jsr || opcode == Bytecodes::_jsr_w) { - return true; - } - } - } - return false; -} #endif // INCLUDE_CDS #if INCLUDE_JVMTI @@ -4103,7 +4088,7 @@ void InstanceKlass::set_init_state(ClassState state) { assert(good_state || state == allocated, "illegal state transition"); #endif assert(_init_thread == nullptr, "should be cleared before state change"); - _init_state = state; + Atomic::release_store(&_init_state, state); } #if INCLUDE_JVMTI diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index eaffa0250d133..daaa16f2059c3 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -507,14 +507,14 @@ class InstanceKlass: public Klass { public: // initialization 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_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; } + ClassState init_state() const { return Atomic::load_acquire(&_init_state); } const char* init_state_name() const; bool is_rewritten() const { return _misc_flags.rewritten(); } @@ -1116,7 +1116,6 @@ class InstanceKlass: public Klass { void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, PackageEntry* pkg_entry, TRAPS); void init_shared_package_entry(); bool can_be_verified_at_dumptime() const; - bool methods_contain_jsr_bytecode() const; void compute_has_loops_flag_for_methods(); #endif diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index cbc379709f1f4..e1bffc90d5129 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -1230,9 +1230,10 @@ void klassItable::initialize_itable_and_check_constraints(TRAPS) { } inline bool interface_method_needs_itable_index(Method* m) { - if (m->is_static()) return false; // e.g., Stream.empty - if (m->is_initializer()) return false; // or - if (m->is_private()) return false; // uses direct call + if (m->is_static()) return false; // e.g., Stream.empty + if (m->is_object_initializer()) return false; // + if (m->is_static_initializer()) return false; // + if (m->is_private()) return false; // uses direct call // If an interface redeclares a method from java.lang.Object, // it should already have a vtable index, don't touch it. // e.g., CharSequence.toString (from initialize_vtable) diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index f4dcd4f149302..a1b380d364655 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -846,10 +846,6 @@ bool Method::is_constant_getter() const { Bytecodes::is_return(java_code_at(last_index))); } -bool Method::is_initializer() const { - return is_object_initializer() || is_static_initializer(); -} - bool Method::has_valid_initializer_flags() const { return (is_static() || method_holder()->major_version() < 51); diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 905c53a4ea38b..d42089d3a5cc9 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -576,9 +576,6 @@ class Method : public Metadata { // returns true if the method does nothing but return a constant of primitive type bool is_constant_getter() const; - // returns true if the method is an initializer ( or ). - bool is_initializer() const; - // returns true if the method is static OR if the classfile version < 51 bool has_valid_initializer_flags() const; @@ -749,6 +746,9 @@ class Method : public Metadata { bool changes_current_thread() const { return constMethod()->changes_current_thread(); } void set_changes_current_thread() { constMethod()->set_changes_current_thread(); } + bool jvmti_hide_events() const { return constMethod()->jvmti_hide_events(); } + void set_jvmti_hide_events() { constMethod()->set_jvmti_hide_events(); } + bool jvmti_mount_transition() const { return constMethod()->jvmti_mount_transition(); } void set_jvmti_mount_transition() { constMethod()->set_jvmti_mount_transition(); } diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index 38dee491a103e..acb47d4c7cf25 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -178,7 +178,7 @@ void* oopDesc::load_oop_raw(oop obj, int offset) { oop oopDesc::obj_field_acquire(int offset) const { return HeapAccess::oop_load_at(as_oop(), offset); } -void oopDesc::obj_field_put_raw(int offset, oop value) { assert(!(UseZGC && ZGenerational), "Generational ZGC must use store barriers"); +void oopDesc::obj_field_put_raw(int offset, oop value) { assert(!UseZGC, "ZGC must use store barriers"); RawAccess<>::oop_store_at(as_oop(), offset, value); } void oopDesc::release_obj_field_put(int offset, oop value) { HeapAccess::oop_store_at(as_oop(), offset, value); } void oopDesc::obj_field_put_volatile(int offset, oop value) { HeapAccess::oop_store_at(as_oop(), offset, value); } diff --git a/src/hotspot/share/oops/stackChunkOop.inline.hpp b/src/hotspot/share/oops/stackChunkOop.inline.hpp index a54b8159e7ef5..7b955d551d7ae 100644 --- a/src/hotspot/share/oops/stackChunkOop.inline.hpp +++ b/src/hotspot/share/oops/stackChunkOop.inline.hpp @@ -88,20 +88,7 @@ inline void stackChunkOopDesc::set_max_thawing_size(int value) { jdk_internal_vm_StackChunk::set_maxThawingSize(this, (jint)value); } -inline oop stackChunkOopDesc::cont() const { - if (UseZGC && !ZGenerational) { - assert(!UseCompressedOops, "Non-generational ZGC does not support compressed oops"); - // The state of the cont oop is used by XCollectedHeap::requires_barriers, - // to determine the age of the stackChunkOopDesc. For that to work, it is - // only the GC that is allowed to perform a load barrier on the oop. - // This function is used by non-GC code and therfore create a stack-local - // copy on the oop and perform the load barrier on that copy instead. - oop obj = jdk_internal_vm_StackChunk::cont_raw(as_oop()); - obj = (oop)NativeAccess<>::oop_load(&obj); - return obj; - } - return jdk_internal_vm_StackChunk::cont(as_oop()); -} +inline oop stackChunkOopDesc::cont() const { return jdk_internal_vm_StackChunk::cont(as_oop()); } inline void stackChunkOopDesc::set_cont(oop value) { jdk_internal_vm_StackChunk::set_cont(this, value); } template inline void stackChunkOopDesc::set_cont_raw(oop value) { jdk_internal_vm_StackChunk::set_cont_raw

    (this, value); } diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 9a7d93dc469ba..802af20adae12 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -395,9 +395,159 @@ Node* AddNode::IdealIL(PhaseGVN* phase, bool can_reshape, BasicType bt) { } } + // Convert a + a + ... + a into a*n + Node* serial_additions = convert_serial_additions(phase, bt); + if (serial_additions != nullptr) { + return serial_additions; + } + return AddNode::Ideal(phase, can_reshape); } +// Try to convert a serial of additions into a single multiplication. Also convert `(a * CON) + a` to `(CON + 1) * a` as +// a side effect. On success, a new MulNode is returned. +Node* AddNode::convert_serial_additions(PhaseGVN* phase, BasicType bt) { + // We need to make sure that the current AddNode is not part of a MulNode that has already been optimized to a + // power-of-2 addition (e.g., 3 * a => (a << 2) + a). Without this check, GVN would keep trying to optimize the same + // node and can't progress. For example, 3 * a => (a << 2) + a => 3 * a => (a << 2) + a => ... + if (find_power_of_two_addition_pattern(this, bt, nullptr) != nullptr) { + return nullptr; + } + + Node* in1 = in(1); + Node* in2 = in(2); + jlong multiplier; + + // While multiplications can be potentially optimized to power-of-2 subtractions (e.g., a * 7 => (a << 3) - a), + // (x - y) + y => x is already handled by the Identity() methods. So, we don't need to check for that pattern here. + if (find_simple_addition_pattern(in1, bt, &multiplier) == in2 + || find_simple_lshift_pattern(in1, bt, &multiplier) == in2 + || find_simple_multiplication_pattern(in1, bt, &multiplier) == in2 + || find_power_of_two_addition_pattern(in1, bt, &multiplier) == in2) { + multiplier++; // +1 for the in2 term + + Node* con = (bt == T_INT) + ? (Node*) phase->intcon((jint) multiplier) // intentional type narrowing to allow overflow at max_jint + : (Node*) phase->longcon(multiplier); + return MulNode::make(con, in2, bt); + } + + return nullptr; +} + +// Try to match `a + a`. On success, return `a` and set `2` as `multiplier`. +// The method matches `n` for pattern: AddNode(a, a). +Node* AddNode::find_simple_addition_pattern(Node* n, BasicType bt, jlong* multiplier) { + if (n->Opcode() == Op_Add(bt) && n->in(1) == n->in(2)) { + *multiplier = 2; + return n->in(1); + } + + return nullptr; +} + +// Try to match `a << CON`. On success, return `a` and set `1 << CON` as `multiplier`. +// Match `n` for pattern: LShiftNode(a, CON). +// Note that the power-of-2 multiplication optimization could potentially convert a MulNode to this pattern. +Node* AddNode::find_simple_lshift_pattern(Node* n, BasicType bt, jlong* multiplier) { + // Note that power-of-2 multiplication optimization could potentially convert a MulNode to this pattern + if (n->Opcode() == Op_LShift(bt) && n->in(2)->is_Con()) { + Node* con = n->in(2); + if (con->is_top()) { + return nullptr; + } + + *multiplier = ((jlong) 1 << con->get_int()); + return n->in(1); + } + + return nullptr; +} + +// Try to match `CON * a`. On success, return `a` and set `CON` as `multiplier`. +// Match `n` for patterns: +// - MulNode(CON, a) +// - MulNode(a, CON) +Node* AddNode::find_simple_multiplication_pattern(Node* n, BasicType bt, jlong* multiplier) { + // This optimization technically only produces MulNode(CON, a), but we might as match MulNode(a, CON), too. + if (n->Opcode() == Op_Mul(bt) && (n->in(1)->is_Con() || n->in(2)->is_Con())) { + Node* con = n->in(1); + Node* base = n->in(2); + + // swap ConNode to lhs for easier matching + if (!con->is_Con()) { + swap(con, base); + } + + if (con->is_top()) { + return nullptr; + } + + *multiplier = con->get_integer_as_long(bt); + return base; + } + + return nullptr; +} + +// Try to match `(a << CON1) + (a << CON2)`. On success, return `a` and set `(1 << CON1) + (1 << CON2)` as `multiplier`. +// Match `n` for patterns: +// - AddNode(LShiftNode(a, CON), LShiftNode(a, CON)/a) +// - AddNode(LShiftNode(a, CON)/a, LShiftNode(a, CON)) +// given that lhs is different from rhs. +// Note that one of the term of the addition could simply be `a` (i.e., a << 0). Calling this function with `multiplier` +// being null is safe. +Node* AddNode::find_power_of_two_addition_pattern(Node* n, BasicType bt, jlong* multiplier) { + if (n->Opcode() == Op_Add(bt) && n->in(1) != n->in(2)) { + Node* lhs = n->in(1); + Node* rhs = n->in(2); + + // swap LShiftNode to lhs for easier matching + if (lhs->Opcode() != Op_LShift(bt)) { + swap(lhs, rhs); + } + + // AddNode(LShiftNode(a, CON), *)? + if (lhs->Opcode() != Op_LShift(bt) || !lhs->in(2)->is_Con()) { + return nullptr; + } + + jlong lhs_multiplier = 0; + if (multiplier != nullptr) { + Node* con = lhs->in(2); + if (con->is_top()) { + return nullptr; + } + + lhs_multiplier = (jlong) 1 << con->get_int(); + } + + // AddNode(LShiftNode(a, CON), a)? + if (lhs->in(1) == rhs) { + if (multiplier != nullptr) { + *multiplier = lhs_multiplier + 1; + } + + return rhs; + } + + // AddNode(LShiftNode(a, CON), LShiftNode(a, CON2))? + if (rhs->Opcode() == Op_LShift(bt) && lhs->in(1) == rhs->in(1) && rhs->in(2)->is_Con()) { + if (multiplier != nullptr) { + Node* con = rhs->in(2); + if (con->is_top()) { + return nullptr; + } + + *multiplier = lhs_multiplier + ((jlong) 1 << con->get_int()); + } + + return lhs->in(1); + } + return nullptr; + } + return nullptr; +} Node* AddINode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* in1 = in(1); diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index 8879606954a52..8afbb440572bf 100644 --- a/src/hotspot/share/opto/addnode.hpp +++ b/src/hotspot/share/opto/addnode.hpp @@ -42,6 +42,13 @@ typedef const Pair ConstAddOperands; // by virtual functions. class AddNode : public Node { virtual uint hash() const; + + Node* convert_serial_additions(PhaseGVN* phase, BasicType bt); + static Node* find_simple_addition_pattern(Node* n, BasicType bt, jlong* multiplier); + static Node* find_simple_lshift_pattern(Node* n, BasicType bt, jlong* multiplier); + static Node* find_simple_multiplication_pattern(Node* n, BasicType bt, jlong* multiplier); + static Node* find_power_of_two_addition_pattern(Node* n, BasicType bt, jlong* multiplier); + public: AddNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) { init_class_id(Class_Add); diff --git a/src/hotspot/share/opto/block.cpp b/src/hotspot/share/opto/block.cpp index 1af085cd1282d..b39db528691de 100644 --- a/src/hotspot/share/opto/block.cpp +++ b/src/hotspot/share/opto/block.cpp @@ -398,7 +398,10 @@ PhaseCFG::PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher) Node *x = new GotoNode(nullptr); x->init_req(0, x); _goto = matcher.match_tree(x); - assert(_goto != nullptr, ""); + assert(_goto != nullptr || C->failure_is_artificial(), ""); + if (C->failing()) { + return; + } _goto->set_req(0,_goto); // Build the CFG in Reverse Post Order diff --git a/src/hotspot/share/opto/buildOopMap.cpp b/src/hotspot/share/opto/buildOopMap.cpp index 4591e87da2d14..b553cc6ea6949 100644 --- a/src/hotspot/share/opto/buildOopMap.cpp +++ b/src/hotspot/share/opto/buildOopMap.cpp @@ -235,6 +235,13 @@ OopMap *OopFlow::build_oop_map( Node *n, int max_reg, PhaseRegAlloc *regalloc, i Node *def = _defs[reg]; // Get reaching def assert( def, "since live better have reaching def" ); + if (def->is_MachTemp()) { + assert(!def->bottom_type()->isa_oop_ptr(), + "ADLC only assigns OOP types to MachTemp defs corresponding to xRegN operands"); + // Exclude MachTemp definitions even if they are typed as oops. + continue; + } + // Classify the reaching def as oop, derived, callee-save, dead, or other const Type *t = def->bottom_type(); if( t->isa_oop_ptr() ) { // Oop or derived? diff --git a/src/hotspot/share/opto/c2_CodeStubs.hpp b/src/hotspot/share/opto/c2_CodeStubs.hpp index 318bc2f45fc76..e778cfcde47e6 100644 --- a/src/hotspot/share/opto/c2_CodeStubs.hpp +++ b/src/hotspot/share/opto/c2_CodeStubs.hpp @@ -117,21 +117,6 @@ class C2FastUnlockLightweightStub : public C2CodeStub { Label& slow_path_continuation() { return continuation(); } }; -#ifdef _LP64 -class C2HandleAnonOMOwnerStub : public C2CodeStub { -private: - Register _monitor; - Register _tmp; -public: - C2HandleAnonOMOwnerStub(Register monitor, Register tmp = noreg) : C2CodeStub(), - _monitor(monitor), _tmp(tmp) {} - Register monitor() { return _monitor; } - Register tmp() { return _tmp; } - int max_size() const; - void emit(C2_MacroAssembler& masm); -}; -#endif - //-----------------------------C2GeneralStub----------------------------------- // A generalized stub that can be used to implement an arbitrary stub in a // type-safe manner. An example: diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 42de77acca931..c14162ddf6eed 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -70,6 +70,14 @@ develop(bool, StressMethodHandleLinkerInlining, false, \ "Stress inlining through method handle linkers") \ \ + develop(bool, StressBailout, false, \ + "Perform bailouts randomly at C2 failing() checks") \ + \ + develop(uint, StressBailoutMean, 100000, \ + "The expected number of failing() checks made until " \ + "a random bailout.") \ + range(1, max_juint) \ + \ develop(intx, OptoPrologueNops, 0, \ "Insert this many extra nop instructions " \ "in the prologue of every nmethod") \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 151c320cadde6..138fd38bfa4eb 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -766,6 +766,8 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_Reference_get: case vmIntrinsics::_Reference_refersTo0: case vmIntrinsics::_PhantomReference_refersTo0: + case vmIntrinsics::_Reference_clear0: + case vmIntrinsics::_PhantomReference_clear0: case vmIntrinsics::_Class_cast: case vmIntrinsics::_aescrypt_encryptBlock: case vmIntrinsics::_aescrypt_decryptBlock: @@ -816,6 +818,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_VectorLoadMaskedOp: case vmIntrinsics::_VectorStoreOp: case vmIntrinsics::_VectorStoreMaskedOp: + case vmIntrinsics::_VectorSelectFromTwoVectorOp: case vmIntrinsics::_VectorGatherOp: case vmIntrinsics::_VectorScatterOp: case vmIntrinsics::_VectorReductionCoerced: @@ -838,7 +841,6 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_notifyJvmtiVThreadEnd: case vmIntrinsics::_notifyJvmtiVThreadMount: case vmIntrinsics::_notifyJvmtiVThreadUnmount: - case vmIntrinsics::_notifyJvmtiVThreadHideFrames: case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: #endif break; diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index afd9ca25a56fe..36fca9f61b691 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -623,7 +623,10 @@ void CallGenerator::do_late_inline_helper() { // check for unreachable loop CallProjections callprojs; - call->extract_projections(&callprojs, true); + // Similar to incremental inlining, don't assert that all call + // projections are still there for post-parse call devirtualization. + bool do_asserts = !is_mh_late_inline() && !is_virtual_late_inline(); + call->extract_projections(&callprojs, true, do_asserts); if ((callprojs.fallthrough_catchproj == call->in(0)) || (callprojs.catchall_catchproj == call->in(0)) || (callprojs.fallthrough_memproj == call->in(TypeFunc::Memory)) || @@ -647,7 +650,7 @@ void CallGenerator::do_late_inline_helper() { if (is_pure_call() && result_not_used) { GraphKit kit(call->jvms()); - kit.replace_call(call, C->top(), true); + kit.replace_call(call, C->top(), true, do_asserts); } else { // Make a clone of the JVMState that appropriate to use for driving a parse JVMState* old_jvms = call->jvms(); @@ -729,7 +732,7 @@ void CallGenerator::do_late_inline_helper() { } C->set_inlining_progress(true); C->set_do_cleanup(kit.stopped()); // path is dead; needs cleanup - kit.replace_call(call, result, true); + kit.replace_call(call, result, true, do_asserts); } } diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index d715e6533432e..e800b3c736bf2 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -755,7 +755,7 @@ Node *CallNode::match( const ProjNode *proj, const Matcher *match ) { if (Opcode() == Op_CallLeafVector) { // If the return is in vector, compute appropriate regmask taking into account the whole range - if(ideal_reg >= Op_VecS && ideal_reg <= Op_VecZ) { + if(ideal_reg >= Op_VecA && ideal_reg <= Op_VecZ) { if(OptoReg::is_valid(regs.second())) { for (OptoReg::Name r = regs.first(); r <= regs.second(); r = OptoReg::add(r, 1)) { rm.Insert(r); diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp index 220b916436ea8..be0aadacbc2b9 100644 --- a/src/hotspot/share/opto/chaitin.cpp +++ b/src/hotspot/share/opto/chaitin.cpp @@ -479,6 +479,9 @@ void PhaseChaitin::Register_Allocate() { } uint new_max_lrg_id = Split(_lrg_map.max_lrg_id(), &split_arena); // Split spilling LRG everywhere + if (C->failing()) { + return; + } _lrg_map.set_max_lrg_id(new_max_lrg_id); // Bail out if unique gets too large (ie - unique > MaxNodeLimit - 2*NodeLimitFudgeFactor) // or we failed to split @@ -551,6 +554,9 @@ void PhaseChaitin::Register_Allocate() { return; } uint new_max_lrg_id = Split(_lrg_map.max_lrg_id(), &split_arena); // Split spilling LRG everywhere + if (C->failing()) { + return; + } _lrg_map.set_max_lrg_id(new_max_lrg_id); // Bail out if unique gets too large (ie - unique > MaxNodeLimit - 2*NodeLimitFudgeFactor) C->check_node_count(2 * NodeLimitFudgeFactor, "out of nodes after split"); diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index 8bee6279446ef..60ee3e01137b0 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -270,8 +270,9 @@ macro(Opaque1) macro(OpaqueLoopInit) macro(OpaqueLoopStride) macro(OpaqueZeroTripGuard) -macro(Opaque4) +macro(OpaqueNotNull) macro(OpaqueInitializedAssertionPredicate) +macro(OpaqueTemplateAssertionPredicate) macro(ProfileBoolean) macro(OrI) macro(OrL) @@ -329,6 +330,8 @@ shmacro(ShenandoahLoadReferenceBarrier) macro(SCMemProj) macro(CopySignD) macro(CopySignF) +macro(SaturatingAddV) +macro(SaturatingSubV) macro(SignumD) macro(SignumF) macro(SignumVF) @@ -341,7 +344,6 @@ macro(Start) macro(StartOSR) macro(StoreB) macro(StoreC) -macro(StoreCM) macro(StoreD) macro(StoreF) macro(StoreI) @@ -436,6 +438,8 @@ macro(XorV) macro(XorReductionV) macro(MinV) macro(MaxV) +macro(UMinV) +macro(UMaxV) macro(MinReductionV) macro(MaxReductionV) macro(CompressV) @@ -483,6 +487,7 @@ macro(Digit) macro(LowerCase) macro(UpperCase) macro(Whitespace) +macro(SelectFromTwoVector) macro(VectorBox) macro(VectorBoxAllocate) macro(VectorUnbox) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 5abc398cb8ce2..a452d439a540b 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -393,7 +393,7 @@ void Compile::remove_useless_node(Node* dead) { if (dead->is_expensive()) { remove_expensive_node(dead); } - if (dead->Opcode() == Op_Opaque4) { + if (dead->is_OpaqueTemplateAssertionPredicate()) { remove_template_assertion_predicate_opaq(dead); } if (dead->is_ParsePredicate()) { @@ -720,7 +720,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, } if (StressLCM || StressGCM || StressIGVN || StressCCP || - StressIncrementalInlining || StressMacroExpansion || StressUnstableIfTraps) { + StressIncrementalInlining || StressMacroExpansion || StressUnstableIfTraps || StressBailout) { initialize_stress_seed(directive); } @@ -798,7 +798,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, assert(failure_reason() != nullptr, "expect reason for parse failure"); stringStream ss; ss.print("method parse failed: %s", failure_reason()); - record_method_not_compilable(ss.as_string()); + record_method_not_compilable(ss.as_string() DEBUG_ONLY(COMMA true)); return; } GraphKit kit(jvms); @@ -973,7 +973,7 @@ Compile::Compile( ciEnv* ci_env, _types = new (comp_arena()) Type_Array(comp_arena()); _node_hash = new (comp_arena()) NodeHash(comp_arena(), 255); - if (StressLCM || StressGCM) { + if (StressLCM || StressGCM || StressBailout) { initialize_stress_seed(directive); } @@ -1018,6 +1018,7 @@ void Compile::Init(bool aliasing) { #ifdef ASSERT _phase_optimize_finished = false; + _phase_verify_ideal_loop = false; _exception_backedge = false; _type_verify = nullptr; #endif @@ -1108,7 +1109,7 @@ void Compile::Init(bool aliasing) { #ifdef ASSERT // Verify that the current StartNode is valid. void Compile::verify_start(StartNode* s) const { - assert(failing() || s == start(), "should be StartNode"); + assert(failing_internal() || s == start(), "should be StartNode"); } #endif @@ -1118,7 +1119,7 @@ void Compile::verify_start(StartNode* s) const { * the ideal graph. */ StartNode* Compile::start() const { - assert (!failing(), "Must not have pending failure. Reason is: %s", failure_reason()); + assert (!failing_internal() || C->failure_is_artificial(), "Must not have pending failure. Reason is: %s", failure_reason()); for (DUIterator_Fast imax, i = root()->fast_outs(imax); i < imax; i++) { Node* start = root()->fast_out(i); if (start->is_Start()) { @@ -1465,12 +1466,18 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const { } else { ciInstanceKlass *canonical_holder = ik->get_canonical_holder(offset); assert(offset < canonical_holder->layout_helper_size_in_bytes(), ""); - if (!ik->equals(canonical_holder) || tj->offset() != offset) { - if( is_known_inst ) { - tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, true, nullptr, offset, to->instance_id()); - } else { - tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, nullptr, offset); - } + assert(tj->offset() == offset, "no change to offset expected"); + bool xk = to->klass_is_exact(); + int instance_id = to->instance_id(); + + // If the input type's class is the holder: if exact, the type only includes interfaces implemented by the holder + // but if not exact, it may include extra interfaces: build new type from the holder class to make sure only + // its interfaces are included. + if (xk && ik->equals(canonical_holder)) { + assert(tj == TypeInstPtr::make(to->ptr(), canonical_holder, is_known_inst, nullptr, offset, instance_id), "exact type should be canonical type"); + } else { + assert(xk || !is_known_inst, "Known instance should be exact type"); + tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, is_known_inst, nullptr, offset, instance_id); } } } @@ -2114,7 +2121,7 @@ void Compile::inline_incrementally(PhaseIterGVN& igvn) { igvn_worklist()->ensure_empty(); // should be done with igvn while (inline_incrementally_one()) { - assert(!failing(), "inconsistent"); + assert(!failing_internal() || failure_is_artificial(), "inconsistent"); } if (failing()) return; @@ -2157,7 +2164,7 @@ void Compile::process_late_inline_calls_no_inline(PhaseIterGVN& igvn) { igvn_worklist()->ensure_empty(); // should be done with igvn while (inline_incrementally_one()) { - assert(!failing(), "inconsistent"); + assert(!failing_internal() || failure_is_artificial(), "inconsistent"); } if (failing()) return; @@ -2944,6 +2951,9 @@ void Compile::Code_Gen() { // Build a proper-looking CFG PhaseCFG cfg(node_arena(), root(), matcher); + if (failing()) { + return; + } _cfg = &cfg; { TracePhase tp("scheduler", &timers[_t_scheduler]); @@ -3051,52 +3061,6 @@ struct Final_Reshape_Counts : public StackObj { int get_inner_loop_count() const { return _inner_loop_count; } }; -// Eliminate trivially redundant StoreCMs and accumulate their -// precedence edges. -void Compile::eliminate_redundant_card_marks(Node* n) { - assert(n->Opcode() == Op_StoreCM, "expected StoreCM"); - if (n->in(MemNode::Address)->outcnt() > 1) { - // There are multiple users of the same address so it might be - // possible to eliminate some of the StoreCMs - Node* mem = n->in(MemNode::Memory); - Node* adr = n->in(MemNode::Address); - Node* val = n->in(MemNode::ValueIn); - Node* prev = n; - bool done = false; - // Walk the chain of StoreCMs eliminating ones that match. As - // long as it's a chain of single users then the optimization is - // safe. Eliminating partially redundant StoreCMs would require - // cloning copies down the other paths. - while (mem->Opcode() == Op_StoreCM && mem->outcnt() == 1 && !done) { - if (adr == mem->in(MemNode::Address) && - val == mem->in(MemNode::ValueIn)) { - // redundant StoreCM - if (mem->req() > MemNode::OopStore) { - // Hasn't been processed by this code yet. - n->add_prec(mem->in(MemNode::OopStore)); - } else { - // Already converted to precedence edge - for (uint i = mem->req(); i < mem->len(); i++) { - // Accumulate any precedence edges - if (mem->in(i) != nullptr) { - n->add_prec(mem->in(i)); - } - } - // Everything above this point has been processed. - done = true; - } - // Eliminate the previous StoreCM - prev->set_req(MemNode::Memory, mem->in(MemNode::Memory)); - assert(mem->outcnt() == 0, "should be dead"); - mem->disconnect_inputs(this); - } else { - prev = mem; - } - mem = prev->in(MemNode::Memory); - } - } -} - //------------------------------final_graph_reshaping_impl---------------------- // Implement items 1-5 from final_graph_reshaping below. void Compile::final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes) { @@ -3266,18 +3230,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f } break; } - - case Op_StoreCM: - { - // Convert OopStore dependence into precedence edge - Node* prec = n->in(MemNode::OopStore); - n->del_req(MemNode::OopStore); - n->add_prec(prec); - eliminate_redundant_card_marks(n); - } - - // fall through - case Op_StoreB: case Op_StoreC: case Op_StoreI: @@ -4329,7 +4281,7 @@ void Compile::verify_graph_edges(bool no_dead_code) { // to backtrack and retry without subsuming loads. Other than this backtracking // behavior, the Compile's failure reason is quietly copied up to the ciEnv // by the logic in C2Compiler. -void Compile::record_failure(const char* reason) { +void Compile::record_failure(const char* reason DEBUG_ONLY(COMMA bool allow_multiple_failures)) { if (log() != nullptr) { log()->elem("failure reason='%s' phase='compile'", reason); } @@ -4339,6 +4291,8 @@ void Compile::record_failure(const char* reason) { if (CaptureBailoutInformation) { _first_failure_details = new CompilationFailureInfo(reason); } + } else { + assert(!StressBailout || allow_multiple_failures, "should have handled previous failure."); } if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) { @@ -4366,7 +4320,9 @@ Compile::TracePhase::TracePhase(const char* name, elapsedTimer* accumulator) } Compile::TracePhase::~TracePhase() { - if (_compile->failing()) return; + if (_compile->failing_internal()) { + return; // timing code, not stressing bailouts. + } #ifdef ASSERT if (PrintIdealNodeCount) { tty->print_cr("phase name='%s' nodes='%d' live='%d' live_graph_walk='%d'", @@ -5057,6 +5013,22 @@ bool Compile::randomized_select(int count) { return (random() & RANDOMIZED_DOMAIN_MASK) < (RANDOMIZED_DOMAIN / count); } +#ifdef ASSERT +// Failures are geometrically distributed with probability 1/StressBailoutMean. +bool Compile::fail_randomly() { + if ((random() % StressBailoutMean) != 0) { + return false; + } + record_failure("StressBailout"); + return true; +} + +bool Compile::failure_is_artificial() { + assert(failing_internal(), "should be failing"); + return C->failure_reason_is("StressBailout"); +} +#endif + CloneMap& Compile::clone_map() { return _clone_map; } void Compile::set_clone_map(Dict* d) { _clone_map._dict = d; } @@ -5144,7 +5116,7 @@ void Compile::sort_macro_nodes() { } void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) { - if (failing()) { return; } + if (failing_internal()) { return; } // failing_internal to not stress bailouts from printing code. EventCompilerPhase event(UNTIMED); if (event.should_commit()) { CompilerEvent::PhaseEvent::post(event, C->_latest_stage_start_counter, cpt, C->_compile_id, level); diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 13ad980434b79..05e24bf3f6e1f 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -370,7 +370,8 @@ class Compile : public Phase { GrowableArray _intrinsics; // List of intrinsics. GrowableArray _macro_nodes; // List of nodes which need to be expanded before matching. GrowableArray _parse_predicates; // List of Parse Predicates. - GrowableArray _template_assertion_predicate_opaqs; // List of Opaque4 nodes for Template Assertion Predicates. + // List of OpaqueTemplateAssertionPredicateNode nodes for Template Assertion Predicates. + GrowableArray _template_assertion_predicate_opaqs; GrowableArray _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common GrowableArray _for_post_loop_igvn; // List of nodes for IGVN after loop opts are over GrowableArray _unstable_if_traps; // List of ifnodes after IGVN @@ -391,6 +392,8 @@ class Compile : public Phase { DEBUG_ONLY(Unique_Node_List* _modified_nodes;) // List of nodes which inputs were modified DEBUG_ONLY(bool _phase_optimize_finished;) // Used for live node verification while creating new nodes + DEBUG_ONLY(bool _phase_verify_ideal_loop;) // Are we in PhaseIdealLoop verification? + // Arenas for new-space and old-space nodes. // Swapped between using _node_arena. // The lifetime of the old-space nodes is during xform. @@ -768,7 +771,7 @@ class Compile : public Phase { void add_template_assertion_predicate_opaq(Node* n) { assert(!_template_assertion_predicate_opaqs.contains(n), - "duplicate entry in template assertion predicate opaque4 list"); + "Duplicate entry in Template Assertion Predicate OpaqueTemplateAssertionPredicate list"); _template_assertion_predicate_opaqs.append(n); } @@ -786,6 +789,12 @@ class Compile : public Phase { void set_post_loop_opts_phase() { _post_loop_opts_phase = true; } void reset_post_loop_opts_phase() { _post_loop_opts_phase = false; } +#ifdef ASSERT + bool phase_verify_ideal_loop() const { return _phase_verify_ideal_loop; } + void set_phase_verify_ideal_loop() { _phase_verify_ideal_loop = true; } + void reset_phase_verify_ideal_loop() { _phase_verify_ideal_loop = false; } +#endif + bool allow_macro_nodes() { return _allow_macro_nodes; } void reset_allow_macro_nodes() { _allow_macro_nodes = false; } @@ -815,7 +824,7 @@ class Compile : public Phase { ciEnv* env() const { return _env; } CompileLog* log() const { return _log; } - bool failing() const { + bool failing_internal() const { return _env->failing() || _failure_reason.get() != nullptr; } @@ -827,6 +836,27 @@ class Compile : public Phase { const CompilationFailureInfo* first_failure_details() const { return _first_failure_details; } + bool failing() { + if (failing_internal()) { + return true; + } +#ifdef ASSERT + // Disable stress code for PhaseIdealLoop verification (would have cascading effects). + if (phase_verify_ideal_loop()) { + return false; + } + if (StressBailout) { + return fail_randomly(); + } +#endif + return false; + } + +#ifdef ASSERT + bool fail_randomly(); + bool failure_is_artificial(); +#endif + bool failure_reason_is(const char* r) const { return (r == _failure_reason.get()) || (r != nullptr && @@ -834,11 +864,11 @@ class Compile : public Phase { strcmp(r, _failure_reason.get()) == 0); } - void record_failure(const char* reason); - void record_method_not_compilable(const char* reason) { + void record_failure(const char* reason DEBUG_ONLY(COMMA bool allow_multiple_failures = false)); + void record_method_not_compilable(const char* reason DEBUG_ONLY(COMMA bool allow_multiple_failures = false)) { env()->record_method_not_compilable(reason); // Record failure reason. - record_failure(reason); + record_failure(reason DEBUG_ONLY(COMMA allow_multiple_failures)); } bool check_node_count(uint margin, const char* reason) { if (oom()) { @@ -1215,7 +1245,6 @@ class Compile : public Phase { void final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes); void final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& frc, uint nop, Unique_Node_List& dead_nodes); void final_graph_reshaping_walk(Node_Stack& nstack, Node* root, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes); - void eliminate_redundant_card_marks(Node* n); void handle_div_mod_op(Node* n, BasicType bt, bool is_unsigned); // Logic cone optimization. diff --git a/src/hotspot/share/opto/domgraph.cpp b/src/hotspot/share/opto/domgraph.cpp index 84f83ef131bbd..6bed1b1a2bd57 100644 --- a/src/hotspot/share/opto/domgraph.cpp +++ b/src/hotspot/share/opto/domgraph.cpp @@ -410,10 +410,9 @@ void PhaseIdealLoop::Dominators() { // Setup mappings from my Graph to Tarjan's stuff and back // Note: Tarjan uses 1-based arrays NTarjan *ntarjan = NEW_RESOURCE_ARRAY(NTarjan,C->unique()+1); - // Initialize _control field for fast reference - int i; - for( i= C->unique()-1; i>=0; i-- ) - ntarjan[i]._control = nullptr; + // Initialize all fields at once for safety and extra performance. + // Among other things, this initializes _control field for fast reference. + memset(ntarjan, 0, (C->unique() + 1)*sizeof(NTarjan)); // Store the DFS order for the main loop const uint fill_value = max_juint; @@ -429,6 +428,7 @@ void PhaseIdealLoop::Dominators() { ntarjan[0]._size = ntarjan[0]._semi = 0; ntarjan[0]._label = &ntarjan[0]; + int i; for( i = dfsnum-1; i>1; i-- ) { // For all nodes in reverse DFS order NTarjan *w = &ntarjan[i]; // Get Node from DFS assert(w->_control != nullptr,"bad DFS walk"); diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 6ab28eaa6eeba..e5f6d68ba1492 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -574,9 +574,8 @@ bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const { // CmpP/N used by the If controlling the cast. if (use->in(0)->is_IfTrue() || use->in(0)->is_IfFalse()) { Node* iff = use->in(0)->in(0); - // We may have Opaque4 node between If and Bool nodes. - // Bail out in such case - we need to preserve Opaque4 for correct - // processing predicates after loop opts. + // We may have an OpaqueNotNull node between If and Bool nodes. But we could also have a sub class of IfNode, + // for example, an OuterStripMinedLoopEnd or a Parse Predicate. Bail out in all these cases. bool can_reduce = (iff->Opcode() == Op_If) && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp(); if (can_reduce) { Node* iff_cmp = iff->in(1)->in(1); @@ -4009,10 +4008,6 @@ void ConnectionGraph::move_inst_mem(Node* n, GrowableArray &orig_phi --i; #ifdef ASSERT } else if (use->is_Mem()) { - if (use->Opcode() == Op_StoreCM && use->in(MemNode::OopStore) == n) { - // Don't move related cardmark. - continue; - } // Memory nodes should have new memory input. tp = igvn->type(use->in(MemNode::Address))->isa_ptr(); assert(tp != nullptr, "ptr type"); @@ -4564,7 +4559,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, // They overwrite memory edge corresponding to destination array, memnode_worklist.append_if_missing(use); } else if (!(op == Op_CmpP || op == Op_Conv2B || - op == Op_CastP2X || op == Op_StoreCM || + op == Op_CastP2X || op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || op == Op_CountPositives || op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || @@ -4703,9 +4698,6 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, if (use->is_Phi() || use->is_ClearArray()) { memnode_worklist.append_if_missing(use); } else if (use->is_Mem() && use->in(MemNode::Memory) == n) { - if (use->Opcode() == Op_StoreCM) { // Ignore cardmark stores - continue; - } memnode_worklist.append_if_missing(use); } else if (use->is_MemBar() || use->is_CallLeaf()) { if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index 4646e1bb9c701..c46d69058e99d 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -216,19 +216,13 @@ void PhaseCFG::schedule_pinned_nodes(VectorSet &visited) { for (uint i = node->len()-1; i >= node->req(); i--) { Node* m = node->in(i); if (m == nullptr) continue; - - // Only process precedence edges that are CFG nodes. Safepoints and control projections can be in the middle of a block - if (is_CFG(m)) { - node->rm_prec(i); - if (n == nullptr) { - n = m; - } else { - assert(is_dominator(n, m) || is_dominator(m, n), "one must dominate the other"); - n = is_dominator(n, m) ? m : n; - } + assert(is_CFG(m), "must be a CFG node"); + node->rm_prec(i); + if (n == nullptr) { + n = m; } else { - assert(node->is_Mach(), "sanity"); - assert(node->as_Mach()->ideal_Opcode() == Op_StoreCM, "must be StoreCM node"); + assert(is_dominator(n, m) || is_dominator(m, n), "one must dominate the other"); + n = is_dominator(n, m) ? m : n; } } if (n != nullptr) { @@ -746,6 +740,21 @@ Block* PhaseCFG::insert_anti_dependences(Block* LCA, Node* load, bool verify) { // The anti-dependence constraints apply only to the fringe of this tree. Node* initial_mem = load->in(MemNode::Memory); + + // We don't optimize the memory graph for pinned loads, so we may need to raise the + // root of our search tree through the corresponding slices of MergeMem nodes to + // get to the node that really creates the memory state for this slice. + if (load_alias_idx >= Compile::AliasIdxRaw) { + while (initial_mem->is_MergeMem()) { + MergeMemNode* mm = initial_mem->as_MergeMem(); + Node* p = mm->memory_at(load_alias_idx); + if (p != mm->base_memory()) { + initial_mem = p; + } else { + break; + } + } + } worklist_def_use_mem_states.push(nullptr, initial_mem); while (worklist_def_use_mem_states.is_nonempty()) { // Examine a nearby store to see if it might interfere with our load. @@ -754,7 +763,17 @@ Block* PhaseCFG::insert_anti_dependences(Block* LCA, Node* load, bool verify) { worklist_def_use_mem_states.pop(); uint op = use_mem_state->Opcode(); - assert(!use_mem_state->needs_anti_dependence_check(), "no loads"); + +#ifdef ASSERT + // CacheWB nodes are peculiar in a sense that they both are anti-dependent and produce memory. + // Allow them to be treated as a store. + bool is_cache_wb = false; + if (use_mem_state->is_Mach()) { + int ideal_op = use_mem_state->as_Mach()->ideal_Opcode(); + is_cache_wb = (ideal_op == Op_CacheWB); + } + assert(!use_mem_state->needs_anti_dependence_check() || is_cache_wb, "no loads"); +#endif // MergeMems do not directly have anti-deps. // Treat them as internal nodes in a forward tree of memory states, @@ -1512,8 +1531,8 @@ void PhaseCFG::schedule_late(VectorSet &visited, Node_Stack &stack) { C->record_failure(C2Compiler::retry_no_subsuming_loads()); } else { // Bailout without retry when (early->_dom_depth > LCA->_dom_depth) - assert(false, "graph should be schedulable"); - C->record_method_not_compilable("late schedule failed: incorrect graph"); + assert(C->failure_is_artificial(), "graph should be schedulable"); + C->record_method_not_compilable("late schedule failed: incorrect graph" DEBUG_ONLY(COMMA true)); } return; } @@ -1693,8 +1712,8 @@ void PhaseCFG::global_code_motion() { Block* block = get_block(i); if (!schedule_local(block, ready_cnt, visited, recalc_pressure_nodes)) { if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) { - assert(false, "local schedule failed"); - C->record_method_not_compilable("local schedule failed"); + assert(C->failure_is_artificial(), "local schedule failed"); + C->record_method_not_compilable("local schedule failed" DEBUG_ONLY(COMMA true)); } _regalloc = nullptr; return; diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 3bc5b9a8b2a7d..ac74abd7e556b 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -340,7 +340,9 @@ static inline void add_one_req(Node* dstphi, Node* src) { // having a control input of its exception map, rather than null. Such // regions do not appear except in this function, and in use_exception_state. void GraphKit::combine_exception_states(SafePointNode* ex_map, SafePointNode* phi_map) { - if (failing()) return; // dying anyway... + if (failing_internal()) { + return; // dying anyway... + } JVMState* ex_jvms = ex_map->_jvms; assert(ex_jvms->same_calls_as(phi_map->_jvms), "consistent call chains"); assert(ex_jvms->stkoff() == phi_map->_jvms->stkoff(), "matching locals"); @@ -446,7 +448,7 @@ void GraphKit::combine_exception_states(SafePointNode* ex_map, SafePointNode* ph //--------------------------use_exception_state-------------------------------- Node* GraphKit::use_exception_state(SafePointNode* phi_map) { - if (failing()) { stop(); return top(); } + if (failing_internal()) { stop(); return top(); } Node* region = phi_map->control(); Node* hidden_merge_mark = root(); assert(phi_map->jvms()->map() == phi_map, "sanity: 1-1 relation"); @@ -1456,7 +1458,7 @@ Node* GraphKit::cast_not_null(Node* obj, bool do_replace_in_map) { // In that case that data path will die and we need the control path // to become dead as well to keep the graph consistent. So we have to // add a check for null for which one branch can't be taken. It uses -// an Opaque4 node that will cause the check to be removed after loop +// an OpaqueNotNull node that will cause the check to be removed after loop // opts so the test goes away and the compiled code doesn't execute a // useless check. Node* GraphKit::must_be_not_null(Node* value, bool do_replace_in_map) { @@ -1464,9 +1466,9 @@ Node* GraphKit::must_be_not_null(Node* value, bool do_replace_in_map) { return value; } Node* chk = _gvn.transform(new CmpPNode(value, null())); - Node *tst = _gvn.transform(new BoolNode(chk, BoolTest::ne)); - Node* opaq = _gvn.transform(new Opaque4Node(C, tst, intcon(1))); - IfNode *iff = new IfNode(control(), opaq, PROB_MAX, COUNT_UNKNOWN); + Node* tst = _gvn.transform(new BoolNode(chk, BoolTest::ne)); + Node* opaq = _gvn.transform(new OpaqueNotNullNode(C, tst)); + IfNode* iff = new IfNode(control(), opaq, PROB_MAX, COUNT_UNKNOWN); _gvn.set_type(iff, iff->Value(&_gvn)); if (!tst->is_Con()) { record_for_igvn(iff); @@ -1556,6 +1558,7 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, bool mismatched, bool unsafe, uint8_t barrier_data) { + assert(adr_idx == C->get_alias_index(_gvn.type(adr)->isa_ptr()), "slice of address and input slice don't match"); assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" ); const TypePtr* adr_type = nullptr; // debug-mode-only argument debug_only(adr_type = C->get_adr_type(adr_idx)); @@ -1585,6 +1588,7 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt, bool unsafe, int barrier_data) { assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); + assert(adr_idx == C->get_alias_index(_gvn.type(adr)->isa_ptr()), "slice of address and input slice don't match"); const TypePtr* adr_type = nullptr; debug_only(adr_type = C->get_adr_type(adr_idx)); Node *mem = memory(adr_idx); @@ -1926,7 +1930,7 @@ static void add_mergemem_users_to_worklist(Unique_Node_List& wl, Node* mem) { } // Replace the call with the current state of the kit. -void GraphKit::replace_call(CallNode* call, Node* result, bool do_replaced_nodes) { +void GraphKit::replace_call(CallNode* call, Node* result, bool do_replaced_nodes, bool do_asserts) { JVMState* ejvms = nullptr; if (has_exceptions()) { ejvms = transfer_exceptions_into_jvms(); @@ -1940,7 +1944,7 @@ void GraphKit::replace_call(CallNode* call, Node* result, bool do_replaced_nodes // Find all the needed outputs of this call CallProjections callprojs; - call->extract_projections(&callprojs, true); + call->extract_projections(&callprojs, true, do_asserts); Unique_Node_List wl; Node* init_mem = call->in(TypeFunc::Memory); @@ -2056,7 +2060,9 @@ Node* GraphKit::uncommon_trap(int trap_request, ciKlass* klass, const char* comment, bool must_throw, bool keep_exact_action) { - if (failing()) stop(); + if (failing_internal()) { + stop(); + } if (stopped()) return nullptr; // trap reachable? // Note: If ProfileTraps is true, and if a deopt. actually @@ -3008,7 +3014,7 @@ void GraphKit::guard_klass_being_initialized(Node* klass) { Node* adr = basic_plus_adr(top(), klass, init_state_off); Node* init_state = LoadNode::make(_gvn, nullptr, immutable_memory(), adr, adr->bottom_type()->is_ptr(), TypeInt::BYTE, - T_BYTE, MemNode::unordered); + T_BYTE, MemNode::acquire); init_state = _gvn.transform(init_state); Node* being_initialized_state = makecon(TypeInt::make(InstanceKlass::being_initialized)); diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index e7f17c72a1b99..3333b7d1bd95f 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -82,7 +82,7 @@ class GraphKit : public Phase { #ifdef ASSERT ~GraphKit() { - assert(failing() || !has_exceptions(), + assert(failing_internal() || !has_exceptions(), "unless compilation failed, user must call transfer_exceptions_into_jvms"); } #endif @@ -182,6 +182,7 @@ class GraphKit : public Phase { // Tell if the compilation is failing. bool failing() const { return C->failing(); } + bool failing_internal() const { return C->failing_internal(); } // Set _map to null, signalling a stop to further bytecode execution. // Preserve the map intact for future use, and return it back to the caller. @@ -730,7 +731,7 @@ class GraphKit : public Phase { // Replace the call with the current state of the kit. Requires // that the call was generated with separate io_projs so that // exceptional control flow can be handled properly. - void replace_call(CallNode* call, Node* result, bool do_replaced_nodes = false); + void replace_call(CallNode* call, Node* result, bool do_replaced_nodes = false, bool do_asserts = true); // helper functions for statistics void increment_counter(address counter_addr); // increment a debug counter diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 4b813252ff9cf..40aec858205dd 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -509,6 +509,10 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) { print_prop("idealOpcode", (const char *)NodeClassNames[node->as_Mach()->ideal_Opcode()]); } + if (node->is_CountedLoop()) { + print_loop_kind(node->as_CountedLoop()); + } + print_field(node); buffer[0] = 0; @@ -639,6 +643,20 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) { } } +void IdealGraphPrinter::print_loop_kind(const CountedLoopNode* counted_loop) { + const char* loop_kind = nullptr; + if (counted_loop->is_pre_loop()) { + loop_kind = "pre"; + } else if (counted_loop->is_main_loop()) { + loop_kind = "main"; + } else if (counted_loop->is_post_loop()) { + loop_kind = "post"; + } + if (loop_kind != nullptr) { + print_prop("loop_kind", loop_kind); + } +} + void IdealGraphPrinter::print_bci_and_line_number(JVMState* caller) { if (caller != nullptr) { ResourceMark rm; diff --git a/src/hotspot/share/opto/idealGraphPrinter.hpp b/src/hotspot/share/opto/idealGraphPrinter.hpp index 65d7f4b547384..a06f2396f63fd 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.hpp +++ b/src/hotspot/share/opto/idealGraphPrinter.hpp @@ -34,6 +34,7 @@ #ifndef PRODUCT class Compile; +class CountedLoopNode; class PhaseIFG; class PhaseChaitin; class Matcher; @@ -124,6 +125,8 @@ class IdealGraphPrinter : public CHeapObj { IdealGraphPrinter(); ~IdealGraphPrinter(); + void print_loop_kind(const CountedLoopNode* counted_loop); + public: IdealGraphPrinter(Compile* compile, const char* file_name = nullptr, bool append = false); static void clean_up(); diff --git a/src/hotspot/share/opto/idealKit.cpp b/src/hotspot/share/opto/idealKit.cpp index 80c4791cfd5cc..baa055bc60aeb 100644 --- a/src/hotspot/share/opto/idealKit.cpp +++ b/src/hotspot/share/opto/idealKit.cpp @@ -381,26 +381,6 @@ Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt, return st; } -// Card mark store. Must be ordered so that it will come after the store of -// the oop. -Node* IdealKit::storeCM(Node* ctl, Node* adr, Node *val, Node* oop_store, int oop_adr_idx, - BasicType bt, - int adr_idx) { - assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); - const TypePtr* adr_type = nullptr; - debug_only(adr_type = C->get_adr_type(adr_idx)); - Node *mem = memory(adr_idx); - - // Add required edge to oop_store, optimizer does not support precedence edges. - // Convert required edge to precedence edge before allocation. - Node* st = new StoreCMNode(ctl, mem, adr, adr_type, val, oop_store, oop_adr_idx); - - st = transform(st); - set_memory(st, adr_idx); - - return st; -} - //---------------------------- do_memory_merge -------------------------------- // The memory from one merging cvstate needs to be merged with the memory for another // join cvstate. If the join cvstate doesn't have a merged memory yet then we diff --git a/src/hotspot/share/opto/idealKit.hpp b/src/hotspot/share/opto/idealKit.hpp index 20acec4721118..727b70129ef90 100644 --- a/src/hotspot/share/opto/idealKit.hpp +++ b/src/hotspot/share/opto/idealKit.hpp @@ -234,15 +234,6 @@ class IdealKit: public StackObj { bool require_atomic_access = false, bool mismatched = false); - // Store a card mark ordered after store_oop - Node* storeCM(Node* ctl, - Node* adr, - Node* val, - Node* oop_store, - int oop_adr_idx, - BasicType bt, - int adr_idx); - // Trivial call Node* make_leaf_call(const TypeFunc *slow_call_type, address slow_call, diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 4313b2cf907a9..093cafd1574db 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -1849,6 +1849,9 @@ void IfNode::dump_spec(outputStream* st) const { case AssertionPredicateType::LastValue: st->print("#Last Value Assertion Predicate "); break; + case AssertionPredicateType::FinalIv: + st->print("#Final IV Assertion Predicate "); + break; case AssertionPredicateType::None: // No Assertion Predicate break; diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index 9db94748ca27c..2a40cf000d849 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -161,6 +161,14 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo Node *m = val->out(i); if( !m->is_Mach() ) continue; MachNode *mach = m->as_Mach(); + if (mach->barrier_data() != 0) { + // Using memory accesses with barriers to perform implicit null checks is + // not supported. These operations might expand into multiple assembly + // instructions during code emission, including new memory accesses (e.g. + // in G1's pre-barrier), which would invalidate the implicit null + // exception table. + continue; + } was_store = false; int iop = mach->ideal_Opcode(); switch( iop ) { @@ -183,7 +191,6 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo break; case Op_StoreB: case Op_StoreC: - case Op_StoreCM: case Op_StoreD: case Op_StoreF: case Op_StoreI: @@ -715,7 +722,6 @@ void PhaseCFG::adjust_register_pressure(Node* n, Block* block, intptr_t* recalc_ switch (iop) { case Op_StoreB: case Op_StoreC: - case Op_StoreCM: case Op_StoreD: case Op_StoreF: case Op_StoreI: @@ -996,21 +1002,6 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto local++; // One more block-local input } ready_cnt.at_put(n->_idx, local); // Count em up - -#ifdef ASSERT - if (UseG1GC) { - if( n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_StoreCM ) { - // Check the precedence edges - for (uint prec = n->req(); prec < n->len(); prec++) { - Node* oop_store = n->in(prec); - if (oop_store != nullptr) { - assert(get_block_for_node(oop_store)->_dom_depth <= block->_dom_depth, "oop_store must dominate card-mark"); - } - } - } - } -#endif - // A few node types require changing a required edge to a precedence edge // before allocation. if( n->is_Mach() && n->req() > TypeFunc::Parms && @@ -1196,7 +1187,7 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto // to the Compile object, and the C2Compiler will see it and retry. C->record_failure(C2Compiler::retry_no_subsuming_loads()); } else { - assert(false, "graph should be schedulable"); + assert(C->failure_is_artificial(), "graph should be schedulable"); } // assert( phi_cnt == end_idx(), "did not schedule all" ); return false; diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 4d182e06a5657..523b1efd0c243 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -495,7 +495,6 @@ bool LibraryCallKit::try_to_inline(int predicate) { "notifyJvmtiMount", false, false); case vmIntrinsics::_notifyJvmtiVThreadUnmount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_unmount()), "notifyJvmtiUnmount", false, false); - case vmIntrinsics::_notifyJvmtiVThreadHideFrames: return inline_native_notify_jvmti_hide(); case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: return inline_native_notify_jvmti_sync(); #endif @@ -580,6 +579,8 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_Reference_get: return inline_reference_get(); case vmIntrinsics::_Reference_refersTo0: return inline_reference_refersTo0(false); case vmIntrinsics::_PhantomReference_refersTo0: return inline_reference_refersTo0(true); + case vmIntrinsics::_Reference_clear0: return inline_reference_clear0(false); + case vmIntrinsics::_PhantomReference_clear0: return inline_reference_clear0(true); case vmIntrinsics::_Class_cast: return inline_Class_cast(); @@ -753,6 +754,8 @@ bool LibraryCallKit::try_to_inline(int predicate) { return inline_vector_extract(); case vmIntrinsics::_VectorCompressExpand: return inline_vector_compress_expand(); + case vmIntrinsics::_VectorSelectFromTwoVectorOp: + return inline_vector_select_from_two_vectors(); case vmIntrinsics::_IndexVector: return inline_index_vector(); case vmIntrinsics::_IndexPartiallyInUpperRange: @@ -2904,7 +2907,7 @@ bool LibraryCallKit::inline_unsafe_allocate() { Node* insp = basic_plus_adr(kls, in_bytes(InstanceKlass::init_state_offset())); // Use T_BOOLEAN for InstanceKlass::_init_state so the compiler // can generate code to load it as unsigned byte. - Node* inst = make_load(nullptr, insp, TypeInt::UBYTE, T_BOOLEAN, MemNode::unordered); + Node* inst = make_load(nullptr, insp, TypeInt::UBYTE, T_BOOLEAN, MemNode::acquire); Node* bits = intcon(InstanceKlass::fully_initialized); test = _gvn.transform(new SubINode(inst, bits)); // The 'test' is non-zero if we need to take a slow path. @@ -2959,11 +2962,10 @@ bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const ch Node* thread = ideal.thread(); Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_VTMS_transition_offset())); Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_VTMS_transition_offset()); - const TypePtr *addr_type = _gvn.type(addr)->isa_ptr(); sync_kit(ideal); - access_store_at(nullptr, jt_addr, addr_type, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); - access_store_at(nullptr, vt_addr, addr_type, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, jt_addr, _gvn.type(jt_addr)->is_ptr(), hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, vt_addr, _gvn.type(vt_addr)->is_ptr(), hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); ideal.sync_kit(this); } ideal.end_if(); @@ -2972,29 +2974,6 @@ bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const ch return true; } -// Always update the temporary VTMS transition bit. -bool LibraryCallKit::inline_native_notify_jvmti_hide() { - if (!DoJVMTIVirtualThreadTransitions) { - return true; - } - IdealKit ideal(this); - - { - // unconditionally update the temporary VTMS transition bit in current JavaThread - Node* thread = ideal.thread(); - Node* hide = _gvn.transform(argument(0)); // hide argument for temporary VTMS transition notification - Node* addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_tmp_VTMS_transition_offset())); - const TypePtr *addr_type = _gvn.type(addr)->isa_ptr(); - - sync_kit(ideal); - access_store_at(nullptr, addr, addr_type, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); - ideal.sync_kit(this); - } - final_sync(ideal); - - return true; -} - // Always update the is_disable_suspend bit. bool LibraryCallKit::inline_native_notify_jvmti_sync() { if (!DoJVMTIVirtualThreadTransitions) { @@ -3325,7 +3304,9 @@ bool LibraryCallKit::inline_native_getEventWriter() { // Load the raw epoch value from the threadObj. Node* threadObj_epoch_offset = basic_plus_adr(threadObj, java_lang_Thread::jfr_epoch_offset()); - Node* threadObj_epoch_raw = access_load_at(threadObj, threadObj_epoch_offset, TypeRawPtr::BOTTOM, TypeInt::CHAR, T_CHAR, + Node* threadObj_epoch_raw = access_load_at(threadObj, threadObj_epoch_offset, + _gvn.type(threadObj_epoch_offset)->isa_ptr(), + TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD); // Mask off the excluded information from the epoch. @@ -3344,7 +3325,8 @@ bool LibraryCallKit::inline_native_getEventWriter() { // Load the raw epoch value from the vthread. Node* vthread_epoch_offset = basic_plus_adr(vthread, java_lang_Thread::jfr_epoch_offset()); - Node* vthread_epoch_raw = access_load_at(vthread, vthread_epoch_offset, TypeRawPtr::BOTTOM, TypeInt::CHAR, T_CHAR, + Node* vthread_epoch_raw = access_load_at(vthread, vthread_epoch_offset, _gvn.type(vthread_epoch_offset)->is_ptr(), + TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD); // Mask off the excluded information from the epoch. @@ -3590,7 +3572,7 @@ void LibraryCallKit::extend_setCurrentThread(Node* jt, Node* thread) { // Load the raw epoch value from the vthread. Node* epoch_offset = basic_plus_adr(thread, java_lang_Thread::jfr_epoch_offset()); - Node* epoch_raw = access_load_at(thread, epoch_offset, TypeRawPtr::BOTTOM, TypeInt::CHAR, T_CHAR, + Node* epoch_raw = access_load_at(thread, epoch_offset, _gvn.type(epoch_offset)->is_ptr(), TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD); // Mask off the excluded information from the epoch. @@ -6960,6 +6942,48 @@ bool LibraryCallKit::inline_reference_refersTo0(bool is_phantom) { return true; } +//----------------------------inline_reference_clear0---------------------------- +// void java.lang.ref.Reference.clear0(); +// void java.lang.ref.PhantomReference.clear0(); +bool LibraryCallKit::inline_reference_clear0(bool is_phantom) { + // This matches the implementation in JVM_ReferenceClear, see the comments there. + + // Get arguments + Node* reference_obj = null_check_receiver(); + if (stopped()) return true; + + // Common access parameters + DecoratorSet decorators = IN_HEAP | AS_NO_KEEPALIVE; + decorators |= (is_phantom ? ON_PHANTOM_OOP_REF : ON_WEAK_OOP_REF); + Node* referent_field_addr = basic_plus_adr(reference_obj, java_lang_ref_Reference::referent_offset()); + const TypePtr* referent_field_addr_type = _gvn.type(referent_field_addr)->isa_ptr(); + const Type* val_type = TypeOopPtr::make_from_klass(env()->Object_klass()); + + Node* referent = access_load_at(reference_obj, + referent_field_addr, + referent_field_addr_type, + val_type, + T_OBJECT, + decorators); + + IdealKit ideal(this); +#define __ ideal. + __ if_then(referent, BoolTest::ne, null()); + sync_kit(ideal); + access_store_at(reference_obj, + referent_field_addr, + referent_field_addr_type, + null(), + val_type, + T_OBJECT, + decorators); + __ sync_kit(this); + __ end_if(); + final_sync(ideal); +#undef __ + + return true; +} Node* LibraryCallKit::load_field_from_object(Node* fromObj, const char* fieldName, const char* fieldTypeString, DecoratorSet decorators, bool is_static, @@ -7350,11 +7374,11 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { //------------------------------get_key_start_from_aescrypt_object----------------------- Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { -#if defined(PPC64) || defined(S390) +#if defined(PPC64) || defined(S390) || defined(RISCV64) // MixColumns for decryption can be reduced by preprocessing MixColumns with round keys. // Intel's extension is based on this optimization and AESCrypt generates round keys by preprocessing MixColumns. // However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption. - // The ppc64 stubs of encryption and decryption use the same round keys (sessionK[0]). + // The ppc64 and riscv64 stubs of encryption and decryption use the same round keys (sessionK[0]). Node* objSessionK = load_field_from_object(aescrypt_object, "sessionK", "[[I"); assert (objSessionK != nullptr, "wrong version of com.sun.crypto.provider.AESCrypt"); if (objSessionK == nullptr) { diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 10375fc23f650..c5437e3bf73f0 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -297,6 +297,7 @@ class LibraryCallKit : public GraphKit { bool inline_divmod_methods(vmIntrinsics::ID id); bool inline_reference_get(); bool inline_reference_refersTo0(bool is_phantom); + bool inline_reference_clear0(bool is_phantom); bool inline_Class_cast(); bool inline_aescrypt_Block(vmIntrinsics::ID id); bool inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id); @@ -373,8 +374,9 @@ class LibraryCallKit : public GraphKit { bool inline_vector_compress_expand(); bool inline_index_vector(); bool inline_index_partially_in_upper_range(); + bool inline_vector_select_from_two_vectors(); - Node* gen_call_to_svml(int vector_api_op_id, BasicType bt, int num_elem, Node* opd1, Node* opd2); + Node* gen_call_to_vector_math(int vector_api_op_id, BasicType bt, int num_elem, Node* opd1, Node* opd2); enum VectorMaskUseType { VecMaskUseLoad = 1 << 0, diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index 5e585a406f20c..d1de9c981012c 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -338,7 +338,8 @@ void PhaseIdealLoop::clone_assertion_predicates_to_unswitched_loop(IdealLoopTree } // Put all Assertion Predicate projections on a list, starting at 'predicate' and going up in the tree. If 'get_opaque' -// is set, then the Opaque4 nodes of the Assertion Predicates are put on the list instead of the projections. +// is set, then the OpaqueTemplateAssertionPredicate nodes of the Assertion Predicates are put on the list instead of +// the projections. void PhaseIdealLoop::get_assertion_predicates(Node* predicate, Unique_Node_List& list, bool get_opaque) { ParsePredicateNode* parse_predicate = predicate->in(0)->as_ParsePredicate(); ProjNode* uncommon_proj = parse_predicate->proj_out(1 - predicate->as_Proj()->_con); @@ -353,10 +354,10 @@ void PhaseIdealLoop::get_assertion_predicates(Node* predicate, Unique_Node_List& } Node* bol = iff->in(1); assert(!bol->is_OpaqueInitializedAssertionPredicate(), "should not find an Initialized Assertion Predicate"); - if (bol->is_Opaque4()) { + if (bol->is_OpaqueTemplateAssertionPredicate()) { assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes"); if (get_opaque) { - // Collect the predicate Opaque4 node. + // Collect the OpaqueTemplateAssertionPredicateNode. list.push(bol); } else { // Collect the predicate projection. @@ -374,11 +375,11 @@ IfProjNode* PhaseIdealLoop::clone_assertion_predicate_for_unswitched_loops(IfNod IfProjNode* predicate, Deoptimization::DeoptReason reason, ParsePredicateSuccessProj* parse_predicate_proj) { - TemplateAssertionExpression template_assertion_expression(template_assertion_predicate->in(1)->as_Opaque4()); - Opaque4Node* cloned_opaque4_node = template_assertion_expression.clone(parse_predicate_proj->in(0)->in(0), this); + TemplateAssertionExpression template_assertion_expression(template_assertion_predicate->in(1)->as_OpaqueTemplateAssertionPredicate()); + OpaqueTemplateAssertionPredicateNode* cloned_opaque_node = template_assertion_expression.clone(parse_predicate_proj->in(0)->in(0), this); IfProjNode* if_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, template_assertion_predicate->Opcode(), false); - _igvn.replace_input_of(if_proj->in(0), 1, cloned_opaque4_node); + _igvn.replace_input_of(if_proj->in(0), 1, cloned_opaque_node); _igvn.replace_input_of(parse_predicate_proj->in(0), 0, if_proj); set_idom(parse_predicate_proj->in(0), if_proj, dom_depth(if_proj)); return if_proj; @@ -1153,7 +1154,8 @@ void PhaseIdealLoop::loop_predication_follow_branches(Node *n, IdealLoopTree *lo bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNode* if_success_proj, ParsePredicateSuccessProj* parse_predicate_proj, CountedLoopNode* cl, - ConNode* zero, Invariance& invar, Deoptimization::DeoptReason reason) { + ConNode* zero, Invariance& invar, + Deoptimization::DeoptReason deopt_reason) { // Following are changed to nonnull when a predicate can be hoisted IfNode* iff = if_success_proj->in(0)->as_If(); Node* test = iff->in(1); @@ -1165,7 +1167,7 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod if (invar.is_invariant(bol)) { C->print_method(PHASE_BEFORE_LOOP_PREDICATION_IC, 4, iff); // Invariant test - IfProjNode* hoisted_check_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, + IfProjNode* hoisted_check_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, deopt_reason, iff->Opcode()); Node* ctrl = hoisted_check_predicate_proj->in(0)->as_If()->in(0); BoolNode* hoisted_check_predicate_bool = invar.clone(bol, ctrl)->as_Bool(); @@ -1206,9 +1208,9 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod const Node* cmp = bol->in(1)->as_Cmp(); Node* idx = cmp->in(1); assert(!invar.is_invariant(idx), "index is variant"); - Node* rng = cmp->in(2); - assert(rng->Opcode() == Op_LoadRange || iff->is_RangeCheck() || _igvn.type(rng)->is_int()->_lo >= 0, "must be"); - assert(invar.is_invariant(rng), "range must be invariant"); + Node* range = cmp->in(2); + assert(range->Opcode() == Op_LoadRange || iff->is_RangeCheck() || _igvn.type(range)->is_int()->_lo >= 0, "must be"); + assert(invar.is_invariant(range), "range must be invariant"); int scale = 1; Node* offset = zero; bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset); @@ -1237,7 +1239,7 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod // late schedule will place invariant things in the loop. ParsePredicateNode* parse_predicate = parse_predicate_proj->in(0)->as_ParsePredicate(); Node* ctrl = parse_predicate->in(0); - rng = invar.clone(rng, ctrl); + range = invar.clone(range, ctrl); if (offset && offset != zero) { assert(invar.is_invariant(offset), "offset must be loop invariant"); offset = invar.clone(offset, ctrl); @@ -1245,10 +1247,10 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod // If predicate expressions may overflow in the integer range, longs are used. bool overflow = false; // Test the lower bound - BoolNode* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, false, overflow); + BoolNode* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, range, false, overflow); const int if_opcode = iff->Opcode(); - IfProjNode* lower_bound_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : if_opcode); + IfProjNode* lower_bound_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, deopt_reason, overflow ? Op_If : if_opcode); IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If(); _igvn.hash_delete(lower_bound_iff); lower_bound_iff->set_req(1, lower_bound_bol); @@ -1257,9 +1259,9 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod } // Test the upper bound - BoolNode* upper_bound_bol = rc_predicate(lower_bound_proj, scale, offset, init, limit, stride, rng, true, overflow); + BoolNode* upper_bound_bol = rc_predicate(lower_bound_proj, scale, offset, init, limit, stride, range, true, overflow); - IfProjNode* upper_bound_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : if_opcode); + IfProjNode* upper_bound_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, deopt_reason, overflow ? Op_If : if_opcode); assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate"); IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If(); _igvn.hash_delete(upper_bound_iff); @@ -1272,8 +1274,8 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod // upper bound test. We always need to create skeleton predicates in order to properly remove dead loops when later // splitting the predicated loop into (unreachable) sub-loops (i.e. done by unrolling, peeling, pre/main/post etc.). IfTrueNode* template_assertion_predicate_proj = - add_template_assertion_predicate(iff, loop, hoisted_check_proj, parse_predicate_proj, upper_bound_proj, scale, - offset, init, limit, stride, rng, overflow, reason); + create_template_assertion_predicate(if_opcode, cl, parse_predicate_proj, upper_bound_proj, scale, offset, range, + deopt_reason); // Eliminate the old range check in the loop body. // When a range check is eliminated, data dependent nodes (Load and range check CastII nodes) are now dependent on 2 @@ -1309,53 +1311,15 @@ void PhaseIdealLoop::eliminate_hoisted_range_check(IfTrueNode* hoisted_check_pro // Each newly created Hoisted Check Predicate is accompanied by two Template Assertion Predicates. Later, we initialize // them by making a copy of them when splitting a loop into sub loops. The Assertion Predicates ensure that dead sub // loops are removed properly. -IfTrueNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj, - ParsePredicateSuccessProj* parse_predicate_proj, - IfProjNode* upper_bound_proj, const int scale, Node* offset, - Node* init, Node* limit, const jint stride, - Node* rng, bool& overflow, Deoptimization::DeoptReason reason) { - // First predicate for the initial value on first loop iteration - Node* opaque_init = new OpaqueLoopInitNode(C, init); - register_new_node(opaque_init, upper_bound_proj); - bool negate = (if_proj->_con != parse_predicate_proj->_con); - BoolNode* bol = rc_predicate(upper_bound_proj, scale, offset, opaque_init, limit, stride, rng, - (stride > 0) != (scale > 0), overflow); - Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); // This will go away once loop opts are over - C->add_template_assertion_predicate_opaq(opaque_bol); - register_new_node(opaque_bol, upper_bound_proj); - IfTrueNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode(), - false NOT_PRODUCT(COMMA AssertionPredicateType::InitValue)); - _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); - assert(opaque_init->outcnt() > 0, "should be used"); - - // Second predicate for init + (current stride - initial stride) - // This is identical to the previous predicate initially but as - // unrolling proceeds current stride is updated. - Node* init_stride = loop->_head->as_CountedLoop()->stride(); - Node* opaque_stride = new OpaqueLoopStrideNode(C, init_stride); - register_new_node(opaque_stride, new_proj); - Node* max_value = new SubINode(opaque_stride, init_stride); - register_new_node(max_value, new_proj); - max_value = new AddINode(opaque_init, max_value); - register_new_node(max_value, new_proj); - // init + (current stride - initial stride) is within the loop so narrow its type by leveraging the type of the iv Phi - const Type* type_iv = loop->_head->as_CountedLoop()->phi()->bottom_type(); - assert(!type_iv->is_int()->is_con(), "constant indicates one loop iteration for which we bailed out earlier"); - max_value = new CastIINode(new_proj, max_value, type_iv); - register_new_node(max_value, new_proj); - - bol = rc_predicate(new_proj, scale, offset, max_value, limit, stride, rng, (stride > 0) != (scale > 0), - overflow); - opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); - C->add_template_assertion_predicate_opaq(opaque_bol); - register_new_node(opaque_bol, new_proj); - new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode(), - false NOT_PRODUCT(COMMA AssertionPredicateType::LastValue)); - _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); - assert(max_value->outcnt() > 0, "should be used"); - assert(assertion_predicate_has_loop_opaque_node(new_proj->in(0)->as_If()), "unexpected"); - - return new_proj; +IfTrueNode* PhaseIdealLoop::create_template_assertion_predicate(const int if_opcode, CountedLoopNode* loop_head, + ParsePredicateSuccessProj* parse_predicate_proj, + IfProjNode* new_control, const int scale, Node* offset, + Node* range, Deoptimization::DeoptReason deopt_reason) { + + TemplateAssertionPredicateCreator template_assertion_predicate_creator(loop_head, scale, offset, range, this); + return template_assertion_predicate_creator.create_with_uncommon_trap(new_control, parse_predicate_proj, deopt_reason, + if_opcode); + } // Insert Hoisted Check Predicates for null checks and range checks and additional Template Assertion Predicates for diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 59662ad53fe07..f5a7ffcf92ada 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -762,7 +762,7 @@ void PhaseIdealLoop::do_peeling(IdealLoopTree *loop, Node_List &old_new) { // Step 1: Clone the loop body. The clone becomes the peeled iteration. // The pre-loop illegally has 2 control users (old & new loops). - const uint idx_before_clone = Compile::current()->unique(); + const uint first_node_index_in_cloned_loop_body = Compile::current()->unique(); LoopNode* outer_loop_head = head->skip_strip_mined(); clone_loop(loop, old_new, dom_depth(outer_loop_head), ControlAroundStripMined); @@ -815,19 +815,8 @@ void PhaseIdealLoop::do_peeling(IdealLoopTree *loop, Node_List &old_new) { // Step 5: Assertion Predicates initialization if (counted_loop && UseLoopPredicate) { - CountedLoopNode *cl_head = head->as_CountedLoop(); - Node* init = cl_head->init_trip(); - Node* stride = cl_head->stride(); - IdealLoopTree* outer_loop = get_loop(outer_loop_head); - const Predicates predicates(new_head->in(LoopNode::EntryControl)); - initialize_assertion_predicates_for_peeled_loop(predicates.loop_predicate_block(), - outer_loop_head, dd_outer_loop_head, - init, stride, outer_loop, - idx_before_clone, old_new); - initialize_assertion_predicates_for_peeled_loop(predicates.profiled_loop_predicate_block(), - outer_loop_head, dd_outer_loop_head, - init, stride, outer_loop, - idx_before_clone, old_new); + initialize_assertion_predicates_for_peeled_loop(new_head->as_CountedLoop(), head->as_CountedLoop(), + first_node_index_in_cloned_loop_body, old_new); } // Now force out all loop-invariant dominating tests. The optimizer @@ -1189,8 +1178,10 @@ bool IdealLoopTree::policy_range_check(PhaseIdealLoop* phase, bool provisional, continue; } if (!bol->is_Bool()) { - assert(bol->is_Opaque4() || bol->is_OpaqueInitializedAssertionPredicate(), - "Opaque node of non-null-check or of Initialized Assertion Predicate"); + assert(bol->is_OpaqueNotNull() || + bol->is_OpaqueTemplateAssertionPredicate() || + bol->is_OpaqueInitializedAssertionPredicate(), + "Opaque node of a non-null-check or an Assertion Predicate"); continue; } if (bol->as_Bool()->_test._test == BoolTest::ne) { @@ -1359,7 +1350,7 @@ void PhaseIdealLoop::copy_assertion_predicates_to_main_loop_helper(const Predica break; Node* bol = iff->in(1); assert(!bol->is_OpaqueInitializedAssertionPredicate(), "should not find an Initialized Assertion Predicate"); - if (bol->is_Opaque4()) { + if (bol->is_OpaqueTemplateAssertionPredicate()) { // Clone the Assertion Predicate twice and initialize one with the initial // value of the loop induction variable. Leave the other predicate // to be initialized when increasing the stride during loop unrolling. @@ -1399,11 +1390,11 @@ void PhaseIdealLoop::copy_assertion_predicates_to_main_loop_helper(const Predica } } +#ifdef ASSERT bool PhaseIdealLoop::assertion_predicate_has_loop_opaque_node(IfNode* iff) { uint init; uint stride; count_opaque_loop_nodes(iff->in(1)->in(1), init, stride); -#ifdef ASSERT ResourceMark rm; Unique_Node_List wq; wq.clear(); @@ -1429,7 +1420,6 @@ bool PhaseIdealLoop::assertion_predicate_has_loop_opaque_node(IfNode* iff) { } } assert(init == verif_init && stride == verif_stride, "missed opaque node"); -#endif assert(stride == 0 || init != 0, "init should be there every time stride is"); return init != 0; } @@ -1458,14 +1448,17 @@ void PhaseIdealLoop::count_opaque_loop_nodes(Node* n, uint& init, uint& stride) } } } +#endif // ASSERT // Create an Initialized Assertion Predicate from the template_assertion_predicate IfTrueNode* PhaseIdealLoop::create_initialized_assertion_predicate(IfNode* template_assertion_predicate, Node* new_init, - Node* new_stride, Node* control) { + Node* new_stride, Node* new_control) { assert(assertion_predicate_has_loop_opaque_node(template_assertion_predicate), "must find OpaqueLoop* nodes for Template Assertion Predicate"); - InitializedAssertionPredicate initialized_assertion_predicate(template_assertion_predicate, new_init, new_stride, this); - IfTrueNode* success_proj = initialized_assertion_predicate.create(control); + InitializedAssertionPredicateCreator initialized_assertion_predicate(this); + IfTrueNode* success_proj = initialized_assertion_predicate.create_from_template(template_assertion_predicate, + new_control, new_init, new_stride); + assert(!assertion_predicate_has_loop_opaque_node(success_proj->in(0)->as_If()), "Initialized Assertion Predicates do not have OpaqueLoop* nodes in the bool expression anymore"); return success_proj; @@ -1473,33 +1466,22 @@ IfTrueNode* PhaseIdealLoop::create_initialized_assertion_predicate(IfNode* templ // Clone the Template Assertion Predicate and set a new OpaqueLoopInitNode to create a new Template Assertion Predicate. // This is done when creating a new Template Assertion Predicate for the main loop which requires a new init node. -// We keep the Opaque4 node since it's still a template. Since the templates are eventually removed after loop opts, -// these are never executed. We therefore insert a Halt node instead of an uncommon trap. +// We keep the OpaqueTemplateAssertionPredicate node since it's still a template. Since the templates are eventually +// removed after loop opts, these are never executed. We therefore insert a Halt node instead of an uncommon trap. Node* PhaseIdealLoop::clone_template_assertion_predicate(IfNode* iff, Node* new_init, Node* predicate, Node* uncommon_proj, - Node* control, IdealLoopTree* outer_loop, Node* input_proj) { + Node* control, IdealLoopTree* outer_loop, Node* new_control) { assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes for Template Assertion Predicate"); - TemplateAssertionExpression template_assertion_expression(iff->in(1)->as_Opaque4()); + TemplateAssertionExpression template_assertion_expression(iff->in(1)->as_OpaqueTemplateAssertionPredicate()); assert(new_init->is_OpaqueLoopInit(), "only for creating new Template Assertion Predicates"); - Opaque4Node* new_opaque_node = template_assertion_expression.clone_and_replace_init(new_init, control, this); - Node* proj = predicate->clone(); - Node* other_proj = uncommon_proj->clone(); - Node* new_iff = iff->clone(); - new_iff->set_req(1, new_opaque_node); - proj->set_req(0, new_iff); - other_proj->set_req(0, new_iff); - Node* frame = new ParmNode(C->start(), TypeFunc::FramePtr); - register_new_node(frame, C->start()); - Node* halt = new HaltNode(other_proj, frame, "Template Assertion Predicates are always removed before code generation"); - _igvn.add_input_to(C->root(), halt); - new_iff->set_req(0, input_proj); - - register_control(new_iff, outer_loop == _ltree_root ? _ltree_root : outer_loop->_parent, input_proj); - register_control(proj, outer_loop == _ltree_root ? _ltree_root : outer_loop->_parent, new_iff); - register_control(other_proj, _ltree_root, new_iff); - register_control(halt, _ltree_root, other_proj); - assert(assertion_predicate_has_loop_opaque_node(proj->in(0)->as_If()), + OpaqueTemplateAssertionPredicateNode* new_opaque_node = + template_assertion_expression.clone_and_replace_init(new_init, control, this); + AssertionPredicateIfCreator assertion_predicate_if_creator(this); + IfTrueNode* success_proj = + assertion_predicate_if_creator.create_for_template(new_control, iff->Opcode(), new_opaque_node + NOT_PRODUCT(COMMA iff->assertion_predicate_type())); + assert(assertion_predicate_has_loop_opaque_node(success_proj->in(0)->as_If()), "Template Assertion Predicates must have OpaqueLoop* nodes in the bool expression"); - return proj; + return success_proj; } void PhaseIdealLoop::copy_assertion_predicates_to_main_loop(CountedLoopNode* pre_head, Node* init, Node* stride, @@ -1932,18 +1914,13 @@ void PhaseIdealLoop::update_main_loop_assertion_predicates(Node* ctrl, CountedLo break; } Node* bol = iff->in(1); - if (bol->is_Opaque4()) { - if (assertion_predicate_has_loop_opaque_node(iff)) { - // This is a Template Assertion Predicate for the initial or last access. - // Create an Initialized Assertion Predicates for it accordingly: - // - For the initial access a[init] (same as before) - // - For the last access a[init+new_stride-orig_stride] (with the new unroll stride) - prev_proj = create_initialized_assertion_predicate(iff, init, max_value, prev_proj); - } else { - // Ignore Opaque4 from a non-null-check for an intrinsic or unsafe access. This could happen when we maximally - // unroll a non-main loop with such an If with an Opaque4 node directly above the loop entry. - assert(!loop_head->is_main_loop(), "Opaque4 node from a non-null check - should not be at main loop"); - } + if (bol->is_OpaqueTemplateAssertionPredicate()) { + assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes"); + // This is a Template Assertion Predicate for the initial or last access. + // Create an Initialized Assertion Predicates for it accordingly: + // - For the initial access a[init] (same as before) + // - For the last access a[init+new_stride-orig_stride] (with the new unroll stride) + prev_proj = create_initialized_assertion_predicate(iff, init, max_value, prev_proj); } else if (bol->is_OpaqueInitializedAssertionPredicate()) { // This is one of the two Initialized Assertion Predicates: // - For the initial access a[init] @@ -1951,6 +1928,7 @@ void PhaseIdealLoop::update_main_loop_assertion_predicates(Node* ctrl, CountedLo // We could keep the one for the initial access but we do not know which one we currently have here. Just kill both. _igvn.replace_input_of(iff, 1, _igvn.intcon(1)); } + assert(!bol->is_OpaqueNotNull() || !loop_head->is_main_loop(), "OpaqueNotNull should not be at main loop"); entry = entry->in(0)->in(0); } if (prev_proj != ctrl) { @@ -1977,7 +1955,7 @@ void PhaseIdealLoop::copy_assertion_predicates_to_post_loop(LoopNode* main_loop_ if (!proj->unique_ctrl_out()->is_Halt()) { break; } - if (iff->in(1)->is_Opaque4()) { + if (iff->in(1)->is_OpaqueTemplateAssertionPredicate()) { // Initialize from Template Assertion Predicate. prev_proj = create_initialized_assertion_predicate(iff, init, stride, prev_proj); } @@ -1989,55 +1967,32 @@ void PhaseIdealLoop::copy_assertion_predicates_to_post_loop(LoopNode* main_loop_ } } -void PhaseIdealLoop::initialize_assertion_predicates_for_peeled_loop(const PredicateBlock* predicate_block, - LoopNode* outer_loop_head, - const int dd_outer_loop_head, Node* init, - Node* stride, IdealLoopTree* outer_loop, - const uint idx_before_clone, - const Node_List &old_new) { - if (!predicate_block->has_parse_predicate()) { - return; - } - Node* input_proj = outer_loop_head->in(LoopNode::EntryControl); - const Node* parse_predicate_uncommon_trap = predicate_block->parse_predicate()->uncommon_trap(); - Node* next_regular_predicate_proj = predicate_block->skip_parse_predicate(); - while (next_regular_predicate_proj->is_IfProj()) { - IfNode* iff = next_regular_predicate_proj->in(0)->as_If(); - ProjNode* uncommon_proj = iff->proj_out(1 - next_regular_predicate_proj->as_Proj()->_con); - if (uncommon_proj->unique_ctrl_out() != parse_predicate_uncommon_trap) { - // Does not belong to this Predicate Block anymore. - break; - } - Node* bol = iff->in(1); - assert(!bol->is_OpaqueInitializedAssertionPredicate(), "should not find an Initialized Assertion Predicate"); - if (bol->is_Opaque4()) { - // Initialize from Template Assertion Predicate. - input_proj = create_initialized_assertion_predicate(iff, init, stride, input_proj); - - // Rewire any control inputs from the old Assertion Predicates above the peeled iteration down to the initialized - // Assertion Predicates above the peeled loop. - for (DUIterator i = next_regular_predicate_proj->outs(); next_regular_predicate_proj->has_out(i); i++) { - Node* dependent = next_regular_predicate_proj->out(i); - Node* new_node = old_new[dependent->_idx]; - - if (!dependent->is_CFG() && - dependent->_idx < idx_before_clone && // old node - new_node != nullptr && // cloned - new_node->_idx >= idx_before_clone) { // for peeling - // The old nodes from the peeled loop still point to the predicate above the peeled loop. - // We need to rewire the dependencies to the newly Initialized Assertion Predicates. - _igvn.replace_input_of(dependent, 0, input_proj); - --i; // correct for just deleted predicate->out(i) - } - } - } - next_regular_predicate_proj = iff->in(0); - } - - _igvn.replace_input_of(outer_loop_head, LoopNode::EntryControl, input_proj); - set_idom(outer_loop_head, input_proj, dd_outer_loop_head); +void PhaseIdealLoop::initialize_assertion_predicates_for_peeled_loop(CountedLoopNode* peeled_loop_head, + CountedLoopNode* remaining_loop_head, + const uint first_node_index_in_cloned_loop_body, + const Node_List& old_new) { + const NodeInOriginalLoopBody node_in_original_loop_body(first_node_index_in_cloned_loop_body, old_new); + create_assertion_predicates_at_loop(peeled_loop_head, remaining_loop_head, node_in_original_loop_body); } +void PhaseIdealLoop::create_assertion_predicates_at_loop(CountedLoopNode* source_loop_head, + CountedLoopNode* target_loop_head, + const NodeInLoopBody& _node_in_loop_body) { + Node* init = target_loop_head->init_trip(); + Node* stride = target_loop_head->stride(); + LoopNode* target_outer_loop_head = target_loop_head->skip_strip_mined(); + Node* target_loop_entry = target_outer_loop_head->in(LoopNode::EntryControl); + CreateAssertionPredicatesVisitor create_assertion_predicates_visitor(init, stride, target_loop_entry, this, + _node_in_loop_body); + Node* source_loop_entry = source_loop_head->skip_strip_mined()->in(LoopNode::EntryControl); + PredicateIterator predicate_iterator(source_loop_entry); + predicate_iterator.for_each(create_assertion_predicates_visitor); + if (create_assertion_predicates_visitor.has_created_predicates()) { + IfTrueNode* last_created_predicate_success_proj = create_assertion_predicates_visitor.last_created_success_proj(); + _igvn.replace_input_of(target_outer_loop_head, LoopNode::EntryControl, last_created_predicate_success_proj); + set_idom(target_outer_loop_head, last_created_predicate_success_proj, dom_depth(target_outer_loop_head)); + } +} //------------------------------do_unroll-------------------------------------- // Unroll the loop body one step - make each trip do 2 iterations. void PhaseIdealLoop::do_unroll(IdealLoopTree *loop, Node_List &old_new, bool adjust_min_trip) { @@ -2731,40 +2686,6 @@ bool PhaseIdealLoop::is_scaled_iv_plus_extra_offset(Node* exp1, Node* offset3, N return false; } -// Same as PhaseIdealLoop::duplicate_predicates() but for range checks -// eliminated by iteration splitting. -Node* PhaseIdealLoop::add_range_check_elimination_assertion_predicate( - IdealLoopTree* loop, Node* ctrl, const int scale_con, Node* offset, Node* limit, jint stride_con, Node* value, - const bool is_template NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)) { - bool overflow = false; - BoolNode* bol = rc_predicate(ctrl, scale_con, offset, value, nullptr, stride_con, - limit, (stride_con > 0) != (scale_con > 0), overflow); - Node* opaque_assertion_predicate; - if (is_template) { - opaque_assertion_predicate = new Opaque4Node(C, bol, _igvn.intcon(1)); - } else { - opaque_assertion_predicate = new OpaqueInitializedAssertionPredicateNode(bol, C); - } - register_new_node(opaque_assertion_predicate, ctrl); - IfNode* new_iff = nullptr; - if (overflow) { - new_iff = new IfNode(ctrl, opaque_assertion_predicate, PROB_MAX, COUNT_UNKNOWN); - } else { - new_iff = new RangeCheckNode(ctrl, opaque_assertion_predicate, PROB_MAX, COUNT_UNKNOWN); - } - register_control(new_iff, loop->_parent, ctrl); - Node* iffalse = new IfFalseNode(new_iff); - register_control(iffalse, _ltree_root, new_iff); - ProjNode* iftrue = new IfTrueNode(new_iff); - register_control(iftrue, loop->_parent, new_iff); - Node *frame = new ParmNode(C->start(), TypeFunc::FramePtr); - register_new_node(frame, C->start()); - Node* halt = new HaltNode(iffalse, frame, "range check predicate failed which is impossible"); - register_control(halt, _ltree_root, iffalse); - _igvn.add_input_to(C->root(), halt); - return iftrue; -} - //------------------------------do_range_check--------------------------------- // Eliminate range-checks and other trip-counter vs loop-invariant tests. void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { @@ -2938,7 +2859,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { limit_ctrl = ensure_node_and_inputs_are_above_pre_end(pre_end, limit); // offset and limit could have control below new_limit_ctrl if they are not loop invariant in the pre loop. - new_limit_ctrl = dominated_node(new_limit_ctrl, offset_ctrl, limit_ctrl); + Node* next_limit_ctrl = dominated_node(new_limit_ctrl, offset_ctrl, limit_ctrl); #ifdef ASSERT if (TraceRangeLimitCheck) { @@ -2959,59 +2880,53 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { jlong lscale_con = scale_con; Node* int_offset = offset; offset = new ConvI2LNode(offset); - register_new_node(offset, new_limit_ctrl); + register_new_node(offset, next_limit_ctrl); Node* int_limit = limit; limit = new ConvI2LNode(limit); - register_new_node(limit, new_limit_ctrl); + register_new_node(limit, next_limit_ctrl); // Adjust pre and main loop limits to guard the correct iteration set if (cmp->Opcode() == Op_CmpU) { // Unsigned compare is really 2 tests if (b_test._test == BoolTest::lt) { // Range checks always use lt // The underflow and overflow limits: 0 <= scale*I+offset < limit - add_constraint(stride_con, lscale_con, offset, zero, limit, new_limit_ctrl, &pre_limit, &main_limit); + add_constraint(stride_con, lscale_con, offset, zero, limit, next_limit_ctrl, &pre_limit, &main_limit); Node* init = cl->init_trip(); Node* opaque_init = new OpaqueLoopInitNode(C, init); register_new_node(opaque_init, loop_entry); + InitializedAssertionPredicateCreator initialized_assertion_predicate_creator(this); if (abs_stride_is_one) { // If the main loop becomes empty and the array access for this range check is sunk out of the loop, the index // for the array access will be set to the index value of the final iteration which could be out of loop. - // Add an Assertion Predicate for that corner case. The final iv is computed from LoopLimit which is the - // LoopNode::limit() only if abs(stride) == 1 otherwise the computation depends on LoopNode::init_trip() as - // well. When LoopLimit only depends on LoopNode::limit(), there are cases where the zero trip guard for the - // main loop doesn't constant fold after range check elimination but, the array access for the final + // Add an Initialized Assertion Predicate for that corner case. The final iv is computed from LoopLimit which + // is the LoopNode::limit() only if abs(stride) == 1 otherwise the computation depends on LoopNode::init_trip() + // as well. When LoopLimit only depends on LoopNode::limit(), there are cases where the zero trip guard for + // the main loop doesn't constant fold after range check elimination but, the array access for the final // iteration of the main loop is out of bound and the index for that access is out of range for the range // check CastII. - loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset, - int_limit, stride_con, final_iv_placeholder, false); + // Note that we do not need to emit a Template Assertion Predicate to update this predicate. When further + // splitting this loop, the final IV will still be the same. When unrolling the loop, we will remove a + // previously added Initialized Assertion Predicate here. But then abs(stride) is greater than 1, and we + // cannot remove an empty loop with a constant limit when init is not a constant as well. We will use + // a LoopLimitCheck node that can only be folded if the zero grip guard is also foldable. + loop_entry = initialized_assertion_predicate_creator.create(final_iv_placeholder, loop_entry, stride_con, + scale_con, int_offset, int_limit NOT_PRODUCT( + COMMA AssertionPredicateType::FinalIv)); assert(!assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); } - // Initialized Assertion Predicate for the value of the initial main-loop. - loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset, - int_limit, stride_con, init, false); - assert(!assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); - // Add two Template Assertion Predicates to create new Initialized Assertion Predicates from when either // unrolling or splitting this main-loop further. - loop_entry = add_range_check_elimination_assertion_predicate( - loop, loop_entry, scale_con, int_offset, int_limit, stride_con, opaque_init, true - NOT_PRODUCT(COMMA AssertionPredicateType::InitValue)); + TemplateAssertionPredicateCreator template_assertion_predicate_creator(cl, scale_con , int_offset, int_limit, + this); + loop_entry = template_assertion_predicate_creator.create_with_halt(loop_entry); assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); - Node* opaque_stride = new OpaqueLoopStrideNode(C, cl->stride()); - register_new_node(opaque_stride, loop_entry); - Node* max_value = new SubINode(opaque_stride, cl->stride()); - register_new_node(max_value, loop_entry); - max_value = new AddINode(opaque_init, max_value); - register_new_node(max_value, loop_entry); - // init + (current stride - initial stride) is within the loop so narrow its type by leveraging the type of the iv Phi - max_value = new CastIINode(loop_entry, max_value, loop->_head->as_CountedLoop()->phi()->bottom_type()); - register_new_node(max_value, loop_entry); - loop_entry = add_range_check_elimination_assertion_predicate( - loop, loop_entry, scale_con, int_offset, int_limit, stride_con, max_value, true - NOT_PRODUCT(COMMA AssertionPredicateType::LastValue)); - assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); + // Initialized Assertion Predicate for the value of the initial main-loop. + loop_entry = initialized_assertion_predicate_creator.create(init, loop_entry, stride_con, scale_con, + int_offset, int_limit NOT_PRODUCT(COMMA + AssertionPredicateType::InitValue)); + assert(!assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); } else { if (PrintOpto) { @@ -3027,22 +2942,22 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // Convert (I*scale+offset) >= Limit to (I*(-scale)+(-offset)) <= -Limit lscale_con = -lscale_con; offset = new SubLNode(zero, offset); - register_new_node(offset, new_limit_ctrl); + register_new_node(offset, next_limit_ctrl); limit = new SubLNode(zero, limit); - register_new_node(limit, new_limit_ctrl); + register_new_node(limit, next_limit_ctrl); // Fall into LE case case BoolTest::le: if (b_test._test != BoolTest::gt) { // Convert X <= Y to X < Y+1 limit = new AddLNode(limit, one); - register_new_node(limit, new_limit_ctrl); + register_new_node(limit, next_limit_ctrl); } // Fall into LT case case BoolTest::lt: // The underflow and overflow limits: MIN_INT <= scale*I+offset < limit // Note: (MIN_INT+1 == -MAX_INT) is used instead of MIN_INT here // to avoid problem with scale == -1: MIN_INT/(-1) == MIN_INT. - add_constraint(stride_con, lscale_con, offset, mini, limit, new_limit_ctrl, &pre_limit, &main_limit); + add_constraint(stride_con, lscale_con, offset, mini, limit, next_limit_ctrl, &pre_limit, &main_limit); break; default: if (PrintOpto) { @@ -3051,6 +2966,9 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { continue; // Unhandled case } } + // Only update variable tracking control for new nodes if it's indeed a range check that can be eliminated (and + // limits are updated) + new_limit_ctrl = next_limit_ctrl; // Kill the eliminated test C->set_major_progress(); @@ -3071,9 +2989,6 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { --imax; } } - - C->print_method(PHASE_AFTER_RANGE_CHECK_ELIMINATION, 4, cl); - } // End of is IF } if (loop_entry != cl->skip_strip_mined()->in(LoopNode::EntryControl)) { @@ -3137,6 +3052,8 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { set_ctrl(opqzm, new_limit_ctrl); set_ctrl(iffm->in(1)->in(1), new_limit_ctrl); set_ctrl(iffm->in(1), new_limit_ctrl); + + C->print_method(PHASE_AFTER_RANGE_CHECK_ELIMINATION, 4, cl); } // Adjust control for node and its inputs (and inputs of its inputs) to be above the pre end @@ -3816,7 +3733,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st break; } int opc = n->Opcode(); - if (opc == Op_StoreP || opc == Op_StoreN || opc == Op_StoreNKlass || opc == Op_StoreCM) { + if (opc == Op_StoreP || opc == Op_StoreN || opc == Op_StoreNKlass) { msg = "oop fills not handled"; break; } diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index b2a1a9d5e2102..e2db179676df8 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -692,14 +692,24 @@ SafePointNode* PhaseIdealLoop::find_safepoint(Node* back_control, Node* x, Ideal // We can only use that safepoint if there's no side effect between the backedge and the safepoint. - // mm is used for book keeping + // mm is the memory state at the safepoint (when it's a MergeMem) + // no_side_effect_since_safepoint() goes over the memory state at the backedge. It resets the mm input for each + // component of the memory state it encounters so it points to the base memory. Once no_side_effect_since_safepoint() + // is done, if no side effect after the safepoint was found, mm should transform to the base memory: the states at + // the backedge and safepoint are the same so all components of the memory state at the safepoint should have been + // reset. MergeMemNode* mm = nullptr; #ifdef ASSERT if (mem->is_MergeMem()) { mm = mem->clone()->as_MergeMem(); _igvn._worklist.push(mm); for (MergeMemStream mms(mem->as_MergeMem()); mms.next_non_empty(); ) { - if (mms.alias_idx() != Compile::AliasIdxBot && loop != get_loop(ctrl_or_self(mms.memory()))) { + // Loop invariant memory state won't be reset by no_side_effect_since_safepoint(). Do it here. + // Escape Analysis can add state to mm that it doesn't add to the backedge memory Phis, breaking verification + // code that relies on mm. Clear that extra state here. + if (mms.alias_idx() != Compile::AliasIdxBot && + (loop != get_loop(ctrl_or_self(mms.memory())) || + (mms.adr_type()->isa_oop_ptr() && mms.adr_type()->is_known_instance()))) { mm->set_memory_at(mms.alias_idx(), mem->as_MergeMem()->base_memory()); } } @@ -2591,7 +2601,7 @@ Node *LoopLimitNode::Ideal(PhaseGVN *phase, bool can_reshape) { const TypeInt* init_t = phase->type(in(Init) )->is_int(); const TypeInt* limit_t = phase->type(in(Limit))->is_int(); - int stride_p; + jlong stride_p; jlong lim, ini; julong max; if (stride_con > 0) { @@ -2600,10 +2610,10 @@ Node *LoopLimitNode::Ideal(PhaseGVN *phase, bool can_reshape) { ini = init_t->_lo; max = (julong)max_jint; } else { - stride_p = -stride_con; + stride_p = -(jlong)stride_con; lim = init_t->_hi; ini = limit_t->_lo; - max = (julong)min_jint; + max = (julong)(juint)min_jint; // double cast to get 0x0000000080000000, not 0xffffffff80000000 } julong range = lim - ini + stride_p; if (range <= max) { @@ -2816,6 +2826,10 @@ SafePointNode* CountedLoopNode::outer_safepoint() const { Node* CountedLoopNode::skip_assertion_predicates_with_halt() { Node* ctrl = in(LoopNode::EntryControl); + if (ctrl == nullptr) { + // Dying loop. + return nullptr; + } if (is_main_loop()) { ctrl = skip_strip_mined()->in(LoopNode::EntryControl); } @@ -3937,6 +3951,41 @@ bool PhaseIdealLoop::is_deleteable_safept(Node* sfpt) { //---------------------------replace_parallel_iv------------------------------- // Replace parallel induction variable (parallel to trip counter) +// This optimization looks for patterns similar to: +// +// int a = init2; +// for (int iv = init; iv < limit; iv += stride_con) { +// a += stride_con2; +// } +// +// and transforms it to: +// +// int iv2 = init2 +// int iv = init +// loop: +// if (iv >= limit) goto exit +// iv += stride_con +// iv2 = init2 + (iv - init) * (stride_con2 / stride_con) +// goto loop +// exit: +// ... +// +// Such transformation introduces more optimization opportunities. In this +// particular example, the loop can be eliminated entirely given that +// `stride_con2 / stride_con` is exact (i.e., no remainder). Checks are in +// place to only perform this optimization if such a division is exact. This +// example will be transformed into its semantic equivalence: +// +// int iv2 = (iv * stride_con2 / stride_con) + (init2 - (init * stride_con2 / stride_con)) +// +// which corresponds to the structure of transformed subgraph. +// +// However, if there is a mismatch between types of the loop and the parallel +// induction variable (e.g., a long-typed IV in an int-typed loop), type +// conversions are required: +// +// long iv2 = ((long) iv * stride_con2 / stride_con) + (init2 - ((long) init * stride_con2 / stride_con)) +// void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { assert(loop->_head->is_CountedLoop(), ""); CountedLoopNode *cl = loop->_head->as_CountedLoop(); @@ -3949,7 +3998,7 @@ void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { } Node *init = cl->init_trip(); Node *phi = cl->phi(); - int stride_con = cl->stride_con(); + jlong stride_con = cl->stride_con(); // Visit all children, looking for Phis for (DUIterator i = cl->outs(); cl->has_out(i); i++) { @@ -3966,7 +4015,7 @@ void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { incr2->req() != 3 || incr2->in(1)->uncast() != phi2 || incr2 == incr || - incr2->Opcode() != Op_AddI || + (incr2->Opcode() != Op_AddI && incr2->Opcode() != Op_AddL) || !incr2->in(2)->is_Con()) { continue; } @@ -3982,11 +4031,15 @@ void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { // the trip-counter, so we need to convert all these to trip-counter // expressions. Node* init2 = phi2->in(LoopNode::EntryControl); - int stride_con2 = incr2->in(2)->get_int(); + + // Determine the basic type of the stride constant (and the iv being incremented). + BasicType stride_con2_bt = incr2->Opcode() == Op_AddI ? T_INT : T_LONG; + jlong stride_con2 = incr2->in(2)->get_integer_as_long(stride_con2_bt); // The ratio of the two strides cannot be represented as an int - // if stride_con2 is min_int and stride_con is -1. - if (stride_con2 == min_jint && stride_con == -1) { + // if stride_con2 is min_jint (or min_jlong, respectively) and + // stride_con is -1. + if (stride_con2 == min_signed_integer(stride_con2_bt) && stride_con == -1) { continue; } @@ -3997,44 +4050,67 @@ void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { // Instead we require 'stride_con2' to be a multiple of 'stride_con', // where +/-1 is the common case, but other integer multiples are // also easy to handle. - int ratio_con = stride_con2/stride_con; + jlong ratio_con = stride_con2 / stride_con; + + if ((ratio_con * stride_con) != stride_con2) { // Check for exact (no remainder) + continue; + } - if ((ratio_con * stride_con) == stride_con2) { // Check for exact #ifndef PRODUCT - if (TraceLoopOpts) { - tty->print("Parallel IV: %d ", phi2->_idx); - loop->dump_head(); - } + if (TraceLoopOpts) { + tty->print("Parallel IV: %d ", phi2->_idx); + loop->dump_head(); + } #endif - // Convert to using the trip counter. The parallel induction - // variable differs from the trip counter by a loop-invariant - // amount, the difference between their respective initial values. - // It is scaled by the 'ratio_con'. - Node* ratio = _igvn.intcon(ratio_con); - set_ctrl(ratio, C->root()); - Node* ratio_init = new MulINode(init, ratio); - _igvn.register_new_node_with_optimizer(ratio_init, init); - set_early_ctrl(ratio_init, false); - Node* diff = new SubINode(init2, ratio_init); - _igvn.register_new_node_with_optimizer(diff, init2); - set_early_ctrl(diff, false); - Node* ratio_idx = new MulINode(phi, ratio); - _igvn.register_new_node_with_optimizer(ratio_idx, phi); - set_ctrl(ratio_idx, cl); - Node* add = new AddINode(ratio_idx, diff); - _igvn.register_new_node_with_optimizer(add); - set_ctrl(add, cl); - _igvn.replace_node( phi2, add ); - // Sometimes an induction variable is unused - if (add->outcnt() == 0) { - _igvn.remove_dead_node(add); - } - --i; // deleted this phi; rescan starting with next position - continue; + + // Convert to using the trip counter. The parallel induction + // variable differs from the trip counter by a loop-invariant + // amount, the difference between their respective initial values. + // It is scaled by the 'ratio_con'. + Node* ratio = _igvn.integercon(ratio_con, stride_con2_bt); + set_ctrl(ratio, C->root()); + + Node* init_converted = insert_convert_node_if_needed(stride_con2_bt, init); + Node* phi_converted = insert_convert_node_if_needed(stride_con2_bt, phi); + + Node* ratio_init = MulNode::make(init_converted, ratio, stride_con2_bt); + _igvn.register_new_node_with_optimizer(ratio_init, init_converted); + set_early_ctrl(ratio_init, false); + + Node* diff = SubNode::make(init2, ratio_init, stride_con2_bt); + _igvn.register_new_node_with_optimizer(diff, init2); + set_early_ctrl(diff, false); + + Node* ratio_idx = MulNode::make(phi_converted, ratio, stride_con2_bt); + _igvn.register_new_node_with_optimizer(ratio_idx, phi_converted); + set_ctrl(ratio_idx, cl); + + Node* add = AddNode::make(ratio_idx, diff, stride_con2_bt); + _igvn.register_new_node_with_optimizer(add); + set_ctrl(add, cl); + + _igvn.replace_node( phi2, add ); + // Sometimes an induction variable is unused + if (add->outcnt() == 0) { + _igvn.remove_dead_node(add); } + --i; // deleted this phi; rescan starting with next position } } +Node* PhaseIdealLoop::insert_convert_node_if_needed(BasicType target, Node* input) { + BasicType source = _igvn.type(input)->basic_type(); + if (source == target) { + return input; + } + + Node* converted = ConvertNode::create_convert(source, target, input); + _igvn.register_new_node_with_optimizer(converted, input); + set_early_ctrl(converted, false); + + return converted; +} + void IdealLoopTree::remove_safepoints(PhaseIdealLoop* phase, bool keep_one) { Node* keep = nullptr; if (keep_one) { @@ -4339,13 +4415,21 @@ void PhaseIdealLoop::mark_loop_associated_parse_predicates_useful() { } } +// This visitor marks all visited Parse Predicates useful. +class ParsePredicateUsefulMarker : public PredicateVisitor { + public: + using PredicateVisitor::visit; + + void visit(const ParsePredicate& parse_predicate) override { + parse_predicate.head()->mark_useful(); + } +}; + void PhaseIdealLoop::mark_useful_parse_predicates_for_loop(IdealLoopTree* loop) { Node* entry = loop->_head->as_Loop()->skip_strip_mined()->in(LoopNode::EntryControl); - const Predicates predicates(entry); - ParsePredicateIterator iterator(predicates); - while (iterator.has_next()) { - iterator.next()->mark_useful(); - } + const PredicateIterator predicate_iterator(entry); + ParsePredicateUsefulMarker useful_marker; + predicate_iterator.for_each(useful_marker); } void PhaseIdealLoop::add_useless_parse_predicates_to_igvn_worklist() { @@ -4359,7 +4443,8 @@ void PhaseIdealLoop::add_useless_parse_predicates_to_igvn_worklist() { // Eliminate all Template Assertion Predicates that do not belong to their originally associated loop anymore by -// replacing the Opaque4 node of the If node with true. These nodes will be removed during the next round of IGVN. +// replacing the OpaqueTemplateAssertionPredicate node of the If node with true. These nodes will be removed during the +// next round of IGVN. void PhaseIdealLoop::eliminate_useless_template_assertion_predicates() { Unique_Node_List useful_predicates; if (C->has_loops()) { @@ -4400,9 +4485,12 @@ void PhaseIdealLoop::collect_useful_template_assertion_predicates_for_loop(Ideal void PhaseIdealLoop::eliminate_useless_template_assertion_predicates(Unique_Node_List& useful_predicates) { for (int i = C->template_assertion_predicate_count(); i > 0; i--) { - Opaque4Node* opaque4_node = C->template_assertion_predicate_opaq_node(i - 1)->as_Opaque4(); - if (!useful_predicates.member(opaque4_node)) { // not in the useful list - _igvn.replace_node(opaque4_node, opaque4_node->in(2)); + OpaqueTemplateAssertionPredicateNode* opaque_node = + C->template_assertion_predicate_opaq_node(i - 1)->as_OpaqueTemplateAssertionPredicate(); + if (!useful_predicates.member(opaque_node)) { // not in the useful list + ConINode* one = _igvn.intcon(1); + set_ctrl(one, C->root()); + _igvn.replace_node(opaque_node, one); } } } @@ -4935,7 +5023,9 @@ void PhaseIdealLoop::verify() const { bool success = true; PhaseIdealLoop phase_verify(_igvn, this); - if (C->failing()) return; + if (C->failing_internal()) { + return; + } // Verify ctrl and idom of every node. success &= verify_idom_and_nodes(C->root(), &phase_verify); @@ -6287,6 +6377,43 @@ void PhaseIdealLoop::build_loop_late_post(Node *n) { build_loop_late_post_work(n, true); } +// Class to visit all predicates in a predicate chain to find out which are dominated by a given node. Keeps track of +// the entry to the earliest predicate that is still dominated by the given dominator. This class is used when trying to +// legally skip all predicates when figuring out the latest placement such that a node does not interfere with Loop +// Predication or creating a Loop Limit Check Predicate later. +class DominatedPredicates : public UnifiedPredicateVisitor { + Node* const _dominator; + Node* _earliest_dominated_predicate_entry; + bool _should_continue; + PhaseIdealLoop* const _phase; + + public: + DominatedPredicates(Node* dominator, Node* start_node, PhaseIdealLoop* phase) + : _dominator(dominator), + _earliest_dominated_predicate_entry(start_node), + _should_continue(true), + _phase(phase) {} + NONCOPYABLE(DominatedPredicates); + + bool should_continue() const override { + return _should_continue; + } + + // Returns the entry to the earliest predicate that is still dominated by the given dominator (all could be dominated). + Node* earliest_dominated_predicate_entry() const { + return _earliest_dominated_predicate_entry; + } + + void visit_predicate(const Predicate& predicate) override { + Node* entry = predicate.entry(); + if (_phase->is_strict_dominator(entry, _dominator)) { + _should_continue = false; + } else { + _earliest_dominated_predicate_entry = entry; + } + } +}; + void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) { if (n->req() == 2 && (n->Opcode() == Op_ConvI2L || n->Opcode() == Op_CastII) && !C->major_progress() && !_verify_only) { @@ -6398,14 +6525,10 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) { // Move the node above predicates as far up as possible so a // following pass of Loop Predication doesn't hoist a predicate // that depends on it above that node. - PredicateEntryIterator predicate_iterator(least); - while (predicate_iterator.has_next()) { - Node* next_predicate_entry = predicate_iterator.next_entry(); - if (is_strict_dominator(next_predicate_entry, early)) { - break; - } - least = next_predicate_entry; - } + const PredicateIterator predicate_iterator(least); + DominatedPredicates dominated_predicates(early, least, this); + predicate_iterator.for_each(dominated_predicates); + least = dominated_predicates.earliest_dominated_predicate_entry(); } // Try not to place code on a loop entry projection // which can inhibit range check elimination. diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 2d169a6459b38..fc0f1b4d53c5e 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -951,19 +951,23 @@ class PhaseIdealLoop : public PhaseTransform { uint idx_after_post_before_pre, Node* zero_trip_guard_proj_main, Node* zero_trip_guard_proj_post, const Node_List& old_new); Node* clone_template_assertion_predicate(IfNode* iff, Node* new_init, Node* predicate, Node* uncommon_proj, Node* control, - IdealLoopTree* outer_loop, Node* input_proj); + IdealLoopTree* outer_loop, Node* new_control); + public: IfTrueNode* create_initialized_assertion_predicate(IfNode* template_assertion_predicate, Node* new_init, Node* new_stride, Node* control); - static void count_opaque_loop_nodes(Node* n, uint& init, uint& stride); - static bool assertion_predicate_has_loop_opaque_node(IfNode* iff); + private: + DEBUG_ONLY(static void count_opaque_loop_nodes(Node* n, uint& init, uint& stride);) + DEBUG_ONLY(static bool assertion_predicate_has_loop_opaque_node(IfNode* iff);) static void get_assertion_predicates(Node* predicate, Unique_Node_List& list, bool get_opaque = false); void update_main_loop_assertion_predicates(Node* ctrl, CountedLoopNode* loop_head, Node* init, int stride_con); void copy_assertion_predicates_to_post_loop(LoopNode* main_loop_head, CountedLoopNode* post_loop_head, Node* stride); - void initialize_assertion_predicates_for_peeled_loop(const PredicateBlock* predicate_block, LoopNode* outer_loop_head, - int dd_outer_loop_head, Node* init, Node* stride, - IdealLoopTree* outer_loop, uint idx_before_clone, + void initialize_assertion_predicates_for_peeled_loop(CountedLoopNode* peeled_loop_head, + CountedLoopNode* remaining_loop_head, + uint first_node_index_in_cloned_loop_body, const Node_List& old_new); + void create_assertion_predicates_at_loop(CountedLoopNode* source_loop_head, CountedLoopNode* target_loop_head, + const NodeInLoopBody& _node_in_loop_body); void insert_loop_limit_check_predicate(ParsePredicateSuccessProj* loop_limit_check_parse_proj, Node* cmp_limit, Node* bol); void log_loop_tree(); @@ -1128,10 +1132,14 @@ class PhaseIdealLoop : public PhaseTransform { _verify_only(verify_me == nullptr), _mode(LoopOptsVerify), _nodes_required(UINT_MAX) { + DEBUG_ONLY(C->set_phase_verify_ideal_loop();) build_and_optimize(); + DEBUG_ONLY(C->reset_phase_verify_ideal_loop();) } #endif + Node* insert_convert_node_if_needed(BasicType target, Node* input); + public: Node* idom_no_update(Node* d) const { return idom_no_update(d->_idx); @@ -1382,20 +1390,17 @@ class PhaseIdealLoop : public PhaseTransform { private: bool loop_predication_impl_helper(IdealLoopTree* loop, IfProjNode* if_success_proj, ParsePredicateSuccessProj* parse_predicate_proj, CountedLoopNode* cl, ConNode* zero, - Invariance& invar, Deoptimization::DeoptReason reason); + Invariance& invar, Deoptimization::DeoptReason deopt_reason); bool can_create_loop_predicates(const PredicateBlock* profiled_loop_predicate_block) const; bool loop_predication_should_follow_branches(IdealLoopTree* loop, float& loop_trip_cnt); void loop_predication_follow_branches(Node *c, IdealLoopTree *loop, float loop_trip_cnt, PathFrequency& pf, Node_Stack& stack, VectorSet& seen, Node_List& if_proj_list); - IfTrueNode* add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj, - ParsePredicateSuccessProj* parse_predicate_proj, - IfProjNode* upper_bound_proj, int scale, Node* offset, Node* init, Node* limit, - jint stride, Node* rng, bool& overflow, Deoptimization::DeoptReason reason); + IfTrueNode* create_template_assertion_predicate(int if_opcode, CountedLoopNode* loop_head, + ParsePredicateSuccessProj* parse_predicate_proj, + IfProjNode* new_control, int scale, Node* offset, + Node* range, Deoptimization::DeoptReason deopt_reason); void eliminate_hoisted_range_check(IfTrueNode* hoisted_check_proj, IfTrueNode* template_assertion_predicate_proj); - Node* add_range_check_elimination_assertion_predicate( - IdealLoopTree* loop, Node* predicate_proj, int scale_con, Node* offset, Node* limit, int stride_con, Node* value, - bool is_template NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type = AssertionPredicateType::None)); // Helper function to collect predicate for eliminating the useless ones void eliminate_useless_predicates(); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 7f42d2d4beb42..9c4385000fbc2 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -787,10 +787,9 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { }//for Node* bol = iff->in(1); assert(!bol->is_OpaqueInitializedAssertionPredicate(), "Initialized Assertion Predicates cannot form a diamond with Halt"); - if (bol->is_Opaque4()) { - // Ignore Template Assertion Predicates with Opaque4 nodes. - assert(assertion_predicate_has_loop_opaque_node(iff), - "must be Template Assertion Predicate, non-null-check with Opaque4 cannot form a diamond with Halt"); + if (bol->is_OpaqueTemplateAssertionPredicate()) { + // Ignore Template Assertion Predicates with OpaqueTemplateAssertionPredicate nodes. + assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes"); return nullptr; } assert(bol->Opcode() == Op_Bool, "Unexpected node"); @@ -1702,8 +1701,9 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { !n->is_Proj() && !n->is_MergeMem() && !n->is_CMove() && - !n->is_Opaque4() && + !n->is_OpaqueNotNull() && !n->is_OpaqueInitializedAssertionPredicate() && + !n->is_OpaqueTemplateAssertionPredicate() && !n->is_Type()) { Node *n_ctrl = get_ctrl(n); IdealLoopTree *n_loop = get_loop(n_ctrl); @@ -1945,10 +1945,11 @@ bool PhaseIdealLoop::ctrl_of_use_out_of_loop(const Node* n, Node* n_ctrl, IdealL // Sinking a node from a pre loop to its main loop pins the node between the pre and main loops. If that node is input // to a check that's eliminated by range check elimination, it becomes input to an expression that feeds into the exit // test of the pre loop above the point in the graph where it's pinned. - if (n_loop->_head->is_CountedLoop() && n_loop->_head->as_CountedLoop()->is_pre_loop() && - u_loop->_head->is_CountedLoop() && u_loop->_head->as_CountedLoop()->is_main_loop() && - n_loop->_next == get_loop(u_loop->_head->as_CountedLoop()->skip_strip_mined())) { - return false; + if (n_loop->_head->is_CountedLoop() && n_loop->_head->as_CountedLoop()->is_pre_loop()) { + CountedLoopNode* pre_loop = n_loop->_head->as_CountedLoop(); + if (is_dominator(pre_loop->loopexit(), ctrl)) { + return false; + } } return true; } @@ -2020,14 +2021,14 @@ Node* PhaseIdealLoop::clone_iff(PhiNode* phi) { if (b->is_Phi()) { _igvn.replace_input_of(phi, i, clone_iff(b->as_Phi())); } else { - assert(b->is_Bool() || b->is_Opaque4() || b->is_OpaqueInitializedAssertionPredicate(), - "bool, non-null check with Opaque4 node or Initialized Assertion Predicate with its Opaque node"); + assert(b->is_Bool() || b->is_OpaqueNotNull() || b->is_OpaqueInitializedAssertionPredicate(), + "bool, non-null check with OpaqueNotNull or Initialized Assertion Predicate with its Opaque node"); } } Node* n = phi->in(1); Node* sample_opaque = nullptr; Node *sample_bool = nullptr; - if (n->is_Opaque4() || n->is_OpaqueInitializedAssertionPredicate()) { + if (n->is_OpaqueNotNull() || n->is_OpaqueInitializedAssertionPredicate()) { sample_opaque = n; sample_bool = n->in(1); assert(sample_bool->is_Bool(), "wrong type"); @@ -2201,7 +2202,9 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new, // For example, it is unexpected that there is a Phi between an // AllocateArray node and its ValidLengthTest input that could cause // split if to break. - if (use->is_If() || use->is_CMove() || use->is_Opaque4() || use->is_OpaqueInitializedAssertionPredicate() || + assert(!use->is_OpaqueTemplateAssertionPredicate(), + "should not clone a Template Assertion Predicate which should be removed once it's useless"); + if (use->is_If() || use->is_CMove() || use->is_OpaqueNotNull() || use->is_OpaqueInitializedAssertionPredicate() || (use->Opcode() == Op_AllocateArray && use->in(AllocateNode::ValidLengthTest) == old)) { // Since this code is highly unlikely, we lazily build the worklist // of such Nodes to go split. @@ -4548,7 +4551,6 @@ void PhaseIdealLoop::move_unordered_reduction_out_of_loop(IdealLoopTree* loop) { const TypeVect* vec_t = last_ur->vect_type(); uint vector_length = vec_t->length(); BasicType bt = vec_t->element_basic_type(); - const Type* bt_t = Type::get_const_basic_type(bt); // Convert opcode from vector-reduction -> scalar -> normal-vector-op const int sopc = VectorNode::scalar_opcode(last_ur->Opcode(), bt); @@ -4628,7 +4630,7 @@ void PhaseIdealLoop::move_unordered_reduction_out_of_loop(IdealLoopTree* loop) { Node* identity_scalar = ReductionNode::make_identity_con_scalar(_igvn, sopc, bt); set_ctrl(identity_scalar, C->root()); - VectorNode* identity_vector = VectorNode::scalar2vector(identity_scalar, vector_length, bt_t); + VectorNode* identity_vector = VectorNode::scalar2vector(identity_scalar, vector_length, bt); register_new_node(identity_vector, C->root()); assert(vec_t == identity_vector->vect_type(), "matching vector type"); VectorNode::trace_new_vector(identity_vector, "Unordered Reduction"); diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index de804457a262d..31a453c9093ff 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2428,7 +2428,7 @@ void PhaseMacroExpand::eliminate_macro_nodes() { break; default: assert(n->Opcode() == Op_LoopLimit || - n->is_Opaque4() || + n->is_OpaqueNotNull() || n->is_OpaqueInitializedAssertionPredicate() || n->Opcode() == Op_MaxL || n->Opcode() == Op_MinL || @@ -2480,17 +2480,14 @@ bool PhaseMacroExpand::expand_macro_nodes() { } else if (n->is_Opaque1()) { _igvn.replace_node(n, n->in(1)); success = true; - } else if (n->is_Opaque4()) { - // With Opaque4 nodes, the expectation is that the test of input 1 - // is always equal to the constant value of input 2. So we can - // remove the Opaque4 and replace it by input 2. In debug builds, - // leave the non constant test in instead to sanity check that it - // never fails (if it does, that subgraph was constructed so, at - // runtime, a Halt node is executed). + } else if (n->is_OpaqueNotNull()) { + // Tests with OpaqueNotNull nodes are implicitly known to be true. Replace the node with true. In debug builds, + // we leave the test in the graph to have an additional sanity check at runtime. If the test fails (i.e. a bug), + // we will execute a Halt node. #ifdef ASSERT _igvn.replace_node(n, n->in(1)); #else - _igvn.replace_node(n, n->in(2)); + _igvn.replace_node(n, _igvn.intcon(1)); #endif success = true; } else if (n->is_OpaqueInitializedAssertionPredicate()) { diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index bf773d43d3d39..920178a0d0407 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -194,6 +194,9 @@ void Matcher::match( ) { } // One-time initialization of some register masks. init_spill_mask( C->root()->in(1) ); + if (C->failing()) { + return; + } _return_addr_mask = return_addr(); #ifdef _LP64 // Pointers take 2 slots in 64-bit land @@ -287,10 +290,16 @@ void Matcher::match( ) { // preserve area, locks & pad2. OptoReg::Name reg1 = warp_incoming_stk_arg(vm_parm_regs[i].first()); + if (C->failing()) { + return; + } if( OptoReg::is_valid(reg1)) _calling_convention_mask[i].Insert(reg1); OptoReg::Name reg2 = warp_incoming_stk_arg(vm_parm_regs[i].second()); + if (C->failing()) { + return; + } if( OptoReg::is_valid(reg2)) _calling_convention_mask[i].Insert(reg2); @@ -386,7 +395,7 @@ void Matcher::match( ) { // Don't set control, it will confuse GCM since there are no uses. // The control will be set when this node is used first time // in find_base_for_derived(). - assert(_mach_null != nullptr, ""); + assert(_mach_null != nullptr || C->failure_is_artificial(), ""); // bailouts are handled below. C->set_root(xroot->is_Root() ? xroot->as_Root() : nullptr); @@ -404,7 +413,7 @@ void Matcher::match( ) { assert(C->failure_reason() != nullptr, "graph lost: reason unknown"); ss.print("graph lost: reason unknown"); } - C->record_method_not_compilable(ss.as_string()); + C->record_method_not_compilable(ss.as_string() DEBUG_ONLY(COMMA true)); } if (C->failing()) { // delete old; @@ -1439,10 +1448,16 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { } // Grab first register, adjust stack slots and insert in mask. OptoReg::Name reg1 = warp_outgoing_stk_arg(first, begin_out_arg_area, out_arg_limit_per_call ); + if (C->failing()) { + return nullptr; + } if (OptoReg::is_valid(reg1)) rm->Insert( reg1 ); // Grab second register (if any), adjust stack slots and insert in mask. OptoReg::Name reg2 = warp_outgoing_stk_arg(second, begin_out_arg_area, out_arg_limit_per_call ); + if (C->failing()) { + return nullptr; + } if (OptoReg::is_valid(reg2)) rm->Insert( reg2 ); } // End of for all arguments @@ -1594,6 +1609,14 @@ static bool match_into_reg( const Node *n, Node *m, Node *control, int i, bool s // the same register. See find_shared_node. return false; } else { // Not a constant + if (!shared && Matcher::is_encode_and_store_pattern(n, m)) { + // Make it possible to match "encode and store" patterns with non-shared + // encode operations that are pinned to a control node (e.g. by CastPP + // node removal in final graph reshaping). The matched instruction cannot + // float above the encode's control node because it is pinned to the + // store's control node. + return false; + } // Stop recursion if they have different Controls. Node* m_control = m->in(0); // Control of load's memory can post-dominates load's control. @@ -2413,6 +2436,7 @@ void Matcher::find_shared_post_visit(Node* n, uint opcode) { n->del_req(4); break; } + case Op_SelectFromTwoVector: case Op_LoopLimit: { Node* pair1 = new BinaryNode(n->in(1), n->in(2)); n->set_req(1, pair1); @@ -2671,6 +2695,10 @@ bool Matcher::gen_narrow_oop_implicit_null_checks() { // Compute RegMask for an ideal register. const RegMask* Matcher::regmask_for_ideal_register(uint ideal_reg, Node* ret) { + assert(!C->failing_internal() || C->failure_is_artificial(), "already failing."); + if (C->failing()) { + return nullptr; + } const Type* t = Type::mreg2type[ideal_reg]; if (t == nullptr) { assert(ideal_reg >= Op_VecA && ideal_reg <= Op_VecZ, "not a vector: %d", ideal_reg); @@ -2701,7 +2729,10 @@ const RegMask* Matcher::regmask_for_ideal_register(uint ideal_reg, Node* ret) { default: ShouldNotReachHere(); } MachNode* mspill = match_tree(spill); - assert(mspill != nullptr, "matching failed: %d", ideal_reg); + assert(mspill != nullptr || C->failure_is_artificial(), "matching failed: %d", ideal_reg); + if (C->failing()) { + return nullptr; + } // Handle generic vector operand case if (Matcher::supports_generic_vector_operands && t->isa_vect()) { specialize_mach_node(mspill); @@ -2833,9 +2864,21 @@ bool Matcher::is_non_long_integral_vector(const Node* n) { return is_subword_type(bt) || bt == T_INT; } +bool Matcher::is_encode_and_store_pattern(const Node* n, const Node* m) { + if (n == nullptr || + m == nullptr || + n->Opcode() != Op_StoreN || + !m->is_EncodeP() || + n->as_Store()->barrier_data() == 0) { + return false; + } + assert(m == n->in(MemNode::ValueIn), "m should be input to n"); + return true; +} + #ifdef ASSERT bool Matcher::verify_after_postselect_cleanup() { - assert(!C->failing(), "sanity"); + assert(!C->failing_internal() || C->failure_is_artificial(), "sanity"); if (supports_generic_vector_operands) { Unique_Node_List useful; C->identify_useful_nodes(useful); diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp index 84e48086f92d3..de3b23aa6d2a1 100644 --- a/src/hotspot/share/opto/matcher.hpp +++ b/src/hotspot/share/opto/matcher.hpp @@ -342,7 +342,6 @@ class Matcher : public PhaseTransform { static bool vector_needs_partial_operations(Node* node, const TypeVect* vt); static const RegMask* predicate_reg_mask(void); - static const TypeVectMask* predicate_reg_type(const Type* elemTy, int length); // Vector width in bytes static int vector_width_in_bytes(BasicType bt); @@ -385,6 +384,8 @@ class Matcher : public PhaseTransform { return ((bt & BoolTest::unsigned_compare) == BoolTest::unsigned_compare); } + static bool is_encode_and_store_pattern(const Node* n, const Node* m); + // These calls are all generated by the ADLC // Java-Java calling convention diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index eee14e5ba03f1..27c0d16fac1b6 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -3462,9 +3462,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* address = in(MemNode::Address); Node* value = in(MemNode::ValueIn); // Back-to-back stores to same address? Fold em up. Generally - // unsafe if I have intervening uses... Also disallowed for StoreCM - // since they must follow each StoreP operation. Redundant StoreCMs - // are eliminated just before matching in final_graph_reshape. + // unsafe if I have intervening uses. { Node* st = mem; // If Store 'st' has more than one use, we cannot fold 'st' away. @@ -3474,7 +3472,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { // require exactly ONE user until such time as we clone 'mem' for // each of 'mem's uses (thus making the exactly-1-user-rule hold // true). - while (st->is_Store() && st->outcnt() == 1 && st->Opcode() != Op_StoreCM) { + while (st->is_Store() && st->outcnt() == 1) { // Looking at a dead closed cycle of memory? assert(st != st->in(MemNode::Memory), "dead loop in StoreNode::Ideal"); assert(Opcode() == st->Opcode() || @@ -3781,48 +3779,6 @@ Node *StoreCNode::Ideal(PhaseGVN *phase, bool can_reshape){ return StoreNode::Ideal(phase, can_reshape); } -//============================================================================= -//------------------------------Identity--------------------------------------- -Node* StoreCMNode::Identity(PhaseGVN* phase) { - // No need to card mark when storing a null ptr - Node* my_store = in(MemNode::OopStore); - if (my_store->is_Store()) { - const Type *t1 = phase->type( my_store->in(MemNode::ValueIn) ); - if( t1 == TypePtr::NULL_PTR ) { - return in(MemNode::Memory); - } - } - return this; -} - -//============================================================================= -//------------------------------Ideal--------------------------------------- -Node *StoreCMNode::Ideal(PhaseGVN *phase, bool can_reshape){ - Node* progress = StoreNode::Ideal(phase, can_reshape); - if (progress != nullptr) return progress; - - Node* my_store = in(MemNode::OopStore); - if (my_store->is_MergeMem()) { - Node* mem = my_store->as_MergeMem()->memory_at(oop_alias_idx()); - set_req_X(MemNode::OopStore, mem, phase); - return this; - } - - return nullptr; -} - -//------------------------------Value----------------------------------------- -const Type* StoreCMNode::Value(PhaseGVN* phase) const { - // Either input is TOP ==> the result is TOP (checked in StoreNode::Value). - // If extra input is TOP ==> the result is TOP - const Type* t = phase->type(in(MemNode::OopStore)); - if (t == Type::TOP) { - return Type::TOP; - } - return StoreNode::Value(phase); -} - - //============================================================================= //----------------------------------SCMemProjNode------------------------------ const Type* SCMemProjNode::Value(PhaseGVN* phase) const @@ -4644,6 +4600,11 @@ intptr_t InitializeNode::can_capture_store(StoreNode* st, PhaseGVN* phase, bool Node* mem = st->in(MemNode::Memory); if (!(mem->is_Proj() && mem->in(0) == this)) return FAIL; // must not be preceded by other stores + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + if ((st->Opcode() == Op_StoreP || st->Opcode() == Op_StoreN) && + !bs->can_initialize_object(st)) { + return FAIL; + } Node* adr = st->in(MemNode::Address); intptr_t offset; AllocateNode* alloc = AllocateNode::Ideal_allocation(adr, phase, offset); diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 85d206749f6be..1ca3a4b16ce1e 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -55,8 +55,7 @@ class MemNode : public Node { enum { Control, // When is it safe to do this load? Memory, // Chunk of memory is being loaded from Address, // Actually address, derived from base - ValueIn, // Value to store - OopStore // Preceding oop store, only in StoreCM + ValueIn // Value to store }; typedef enum { unordered = 0, acquire, // Load has to acquire or be succeeded by MemBarAcquire. @@ -124,11 +123,7 @@ class MemNode : public Node { // Raw access function, to allow copying of adr_type efficiently in // product builds and retain the debug info for debug builds. const TypePtr *raw_adr_type() const { -#ifdef ASSERT - return _adr_type; -#else - return 0; -#endif + return DEBUG_ONLY(_adr_type) NOT_DEBUG(nullptr); } // Return the barrier data of n, if available, or 0 otherwise. @@ -781,36 +776,6 @@ class StoreNKlassNode : public StoreNNode { virtual BasicType memory_type() const { return T_NARROWKLASS; } }; -//------------------------------StoreCMNode----------------------------------- -// Store card-mark byte to memory for CM -// The last StoreCM before a SafePoint must be preserved and occur after its "oop" store -// Preceding equivalent StoreCMs may be eliminated. -class StoreCMNode : public StoreNode { - private: - virtual uint hash() const { return StoreNode::hash() + _oop_alias_idx; } - virtual bool cmp( const Node &n ) const { - return _oop_alias_idx == ((StoreCMNode&)n)._oop_alias_idx - && StoreNode::cmp(n); - } - virtual uint size_of() const { return sizeof(*this); } - int _oop_alias_idx; // The alias_idx of OopStore - -public: - StoreCMNode( Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, Node *oop_store, int oop_alias_idx ) : - StoreNode(c, mem, adr, at, val, oop_store, MemNode::release), - _oop_alias_idx(oop_alias_idx) { - assert(_oop_alias_idx >= Compile::AliasIdxRaw || - (_oop_alias_idx == Compile::AliasIdxBot && !Compile::current()->do_aliasing()), - "bad oop alias idx"); - } - virtual int Opcode() const; - virtual Node* Identity(PhaseGVN* phase); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual const Type* Value(PhaseGVN* phase) const; - virtual BasicType memory_type() const { return T_VOID; } // unspecific - int oop_alias_idx() const { return _oop_alias_idx; } -}; - //------------------------------SCMemProjNode--------------------------------------- // This class defines a projection of the memory state of a store conditional node. // These nodes return a value, but also update memory. diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 2e586de33a3d8..3f82c47216303 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -611,7 +611,7 @@ void Node::destruct(PhaseValues* phase) { if (is_expensive()) { compile->remove_expensive_node(this); } - if (is_Opaque4()) { + if (is_OpaqueTemplateAssertionPredicate()) { compile->remove_template_assertion_predicate_opaq(this); } if (is_ParsePredicate()) { @@ -2770,9 +2770,7 @@ const RegMask &Node::in_RegMask(uint) const { void Node_Array::grow(uint i) { _nesting.check(_a); // Check if a potential reallocation in the arena is safe - if (i < _max) { - return; // No need to grow - } + assert(i >= _max, "Should have been checked before, use maybe_grow?"); assert(_max > 0, "invariant"); uint old = _max; _max = next_power_of_2(i); diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 07a623e2f936d..db8b00c0bda81 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -138,8 +138,9 @@ class NeverBranchNode; class Opaque1Node; class OpaqueLoopInitNode; class OpaqueLoopStrideNode; -class Opaque4Node; +class OpaqueNotNullNode; class OpaqueInitializedAssertionPredicateNode; +class OpaqueTemplateAssertionPredicateNode; class OuterStripMinedLoopNode; class OuterStripMinedLoopEndNode; class Node; @@ -168,6 +169,7 @@ class RootNode; class SafePointNode; class SafePointScalarObjectNode; class SafePointScalarMergeNode; +class SaturatingVectorNode; class StartNode; class State; class StoreNode; @@ -740,6 +742,7 @@ class Node { DEFINE_CLASS_ID(CompressM, Vector, 6) DEFINE_CLASS_ID(Reduction, Vector, 7) DEFINE_CLASS_ID(NegV, Vector, 8) + DEFINE_CLASS_ID(SaturatingVector, Vector, 9) DEFINE_CLASS_ID(Con, Type, 8) DEFINE_CLASS_ID(ConI, Con, 0) DEFINE_CLASS_ID(SafePointScalarMerge, Type, 9) @@ -796,11 +799,12 @@ class Node { DEFINE_CLASS_ID(Opaque1, Node, 16) DEFINE_CLASS_ID(OpaqueLoopInit, Opaque1, 0) DEFINE_CLASS_ID(OpaqueLoopStride, Opaque1, 1) - DEFINE_CLASS_ID(Opaque4, Node, 17) + DEFINE_CLASS_ID(OpaqueNotNull, Node, 17) DEFINE_CLASS_ID(OpaqueInitializedAssertionPredicate, Node, 18) - DEFINE_CLASS_ID(Move, Node, 19) - DEFINE_CLASS_ID(LShift, Node, 20) - DEFINE_CLASS_ID(Neg, Node, 21) + DEFINE_CLASS_ID(OpaqueTemplateAssertionPredicate, Node, 19) + DEFINE_CLASS_ID(Move, Node, 20) + DEFINE_CLASS_ID(LShift, Node, 21) + DEFINE_CLASS_ID(Neg, Node, 22) _max_classes = ClassMask_Neg }; @@ -970,8 +974,9 @@ class Node { DEFINE_CLASS_QUERY(NegV) DEFINE_CLASS_QUERY(NeverBranch) DEFINE_CLASS_QUERY(Opaque1) - DEFINE_CLASS_QUERY(Opaque4) + DEFINE_CLASS_QUERY(OpaqueNotNull) DEFINE_CLASS_QUERY(OpaqueInitializedAssertionPredicate) + DEFINE_CLASS_QUERY(OpaqueTemplateAssertionPredicate) DEFINE_CLASS_QUERY(OpaqueLoopInit) DEFINE_CLASS_QUERY(OpaqueLoopStride) DEFINE_CLASS_QUERY(OuterStripMinedLoop) @@ -1007,6 +1012,7 @@ class Node { DEFINE_CLASS_QUERY(StoreVectorScatter) DEFINE_CLASS_QUERY(StoreVectorMasked) DEFINE_CLASS_QUERY(StoreVectorScatterMasked) + DEFINE_CLASS_QUERY(SaturatingVector) DEFINE_CLASS_QUERY(ShiftV) DEFINE_CLASS_QUERY(Unlock) @@ -1607,7 +1613,14 @@ class Node_Array : public AnyObj { Node** _nodes; ReallocMark _nesting; // Safety checks for arena reallocation - void grow( uint i ); // Grow array node to fit + // Grow array to required capacity + void maybe_grow(uint i) { + if (i >= _max) { + grow(i); + } + } + void grow(uint i); + public: Node_Array(Arena* a, uint max = OptoNodeListSize) : _a(a), _max(max) { _nodes = NEW_ARENA_ARRAY(a, Node*, max); @@ -1625,7 +1638,7 @@ class Node_Array : public AnyObj { Node* at(uint i) const { assert(i<_max,"oob"); return _nodes[i]; } Node** adr() { return _nodes; } // Extend the mapping: index i maps to Node *n. - void map( uint i, Node *n ) { grow(i); _nodes[i] = n; } + void map( uint i, Node *n ) { maybe_grow(i); _nodes[i] = n; } void insert( uint i, Node *n ); void remove( uint i ); // Remove, preserving order // Clear all entries in _nodes to null but keep storage diff --git a/src/hotspot/share/opto/opaquenode.cpp b/src/hotspot/share/opto/opaquenode.cpp index 14fd0d5f1a7a9..8a8eea51db6d0 100644 --- a/src/hotspot/share/opto/opaquenode.cpp +++ b/src/hotspot/share/opto/opaquenode.cpp @@ -82,7 +82,24 @@ IfNode* OpaqueZeroTripGuardNode::if_node() const { return iff->as_If(); } -const Type* Opaque4Node::Value(PhaseGVN* phase) const { +const Type* OpaqueNotNullNode::Value(PhaseGVN* phase) const { + return phase->type(in(1)); +} + +Node* OpaqueTemplateAssertionPredicateNode::Identity(PhaseGVN* phase) { + if (phase->C->post_loop_opts_phase()) { + // Template Assertion Predicates only serve as templates to create Initialized Assertion Predicates when splitting + // a loop during loop opts. They are not used anymore once loop opts are over and can then be removed. They feed + // into the bool input of an If node and can thus be replaced by true to let the Template Assertion Predicate be + // folded away (the success path is always the true path by design). + return phase->intcon(1); + } else { + phase->C->record_for_post_loop_opts_igvn(this); + } + return this; +} + +const Type* OpaqueTemplateAssertionPredicateNode::Value(PhaseGVN* phase) const { return phase->type(in(1)); } diff --git a/src/hotspot/share/opto/opaquenode.hpp b/src/hotspot/share/opto/opaquenode.hpp index 9c775408cc0cd..c1686d846f90b 100644 --- a/src/hotspot/share/opto/opaquenode.hpp +++ b/src/hotspot/share/opto/opaquenode.hpp @@ -91,18 +91,18 @@ class OpaqueZeroTripGuardNode : public Opaque1Node { IfNode* if_node() const; }; -// Input 1 is a check that we know implicitly is always true or false -// but the compiler has no way to prove. If during optimizations, that -// check becomes true or false, the Opaque4 node is replaced by that -// constant true or false. Input 2 is the constant value we know the -// test takes. After loop optimizations, we replace input 1 by input 2 -// so the control that depends on that test can be removed and there's -// no overhead at runtime. Used for instance by +// This node is used in the context of intrinsics. We sometimes implicitly know that an object is non-null even though +// the compiler cannot prove it. We therefore add a corresponding cast to propagate this implicit knowledge. However, +// this cast could become top during optimizations (input to cast becomes null) and the data path is folded. To ensure +// that the control path is also properly folded, we insert an If node with a OpaqueNotNullNode as condition. During +// macro expansion, we replace the OpaqueNotNullNodes with true in product builds such that the actually unneeded checks +// are folded and do not end up in the emitted code. In debug builds, we keep the actual checks as additional +// verification code (i.e. removing OpaqueNotNullNodes and use the BoolNode inputs instead). For more details, also see // GraphKit::must_be_not_null(). -class Opaque4Node : public Node { - public: - Opaque4Node(Compile* C, Node* tst, Node* final_tst) : Node(nullptr, tst, final_tst) { - init_class_id(Class_Opaque4); +class OpaqueNotNullNode : public Node { + public: + OpaqueNotNullNode(Compile* C, Node* tst) : Node(nullptr, tst) { + init_class_id(Class_OpaqueNotNull); init_flags(Flag_is_macro); C->add_macro_node(this); } @@ -112,9 +112,26 @@ class Opaque4Node : public Node { virtual const Type* bottom_type() const { return TypeInt::BOOL; } }; +// This node is used for Template Assertion Predicate BoolNodes. A Template Assertion Predicate is always removed +// after loop opts and thus is never converted to actual code. In the post loop opts IGVN phase, the +// OpaqueTemplateAssertionPredicateNode is replaced by true in order to fold the Template Assertion Predicate away. +class OpaqueTemplateAssertionPredicateNode : public Node { + public: + OpaqueTemplateAssertionPredicateNode(BoolNode* bol) : Node(nullptr, bol) { + init_class_id(Class_OpaqueTemplateAssertionPredicate); + } + + virtual int Opcode() const; + virtual Node* Identity(PhaseGVN* phase); + virtual const Type* Value(PhaseGVN* phase) const; + virtual const Type* bottom_type() const { return TypeInt::BOOL; } +}; + // This node is used for Initialized Assertion Predicate BoolNodes. Initialized Assertion Predicates must always evaluate -// to true. Therefore, we get rid of them in product builds during macro expansion as they are useless. In debug builds -// we keep them as additional verification code (i.e. removing this node and use the BoolNode input instead). +// to true. During macro expansion, we replace the OpaqueInitializedAssertionPredicateNodes with true in product builds +// such that the actually unneeded checks are folded and do not end up in the emitted code. In debug builds, we keep the +// actual checks as additional verification code (i.e. removing OpaqueInitializedAssertionPredicateNodes and use the +// BoolNode inputs instead). class OpaqueInitializedAssertionPredicateNode : public Node { public: OpaqueInitializedAssertionPredicateNode(BoolNode* bol, Compile* C) : Node(nullptr, bol) { diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index b3f251bb361ba..ea1175bce1447 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -792,7 +792,14 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, for (uint i = 1; i < smerge->req(); i++) { Node* obj_node = smerge->in(i); - (void)FillLocArray(mv->possible_objects()->length(), sfpt, obj_node, mv->possible_objects(), objs); + int idx = mv->possible_objects()->length(); + (void)FillLocArray(idx, sfpt, obj_node, mv->possible_objects(), objs); + + // By default ObjectValues that are in 'possible_objects' are not root objects. + // They will be marked as root later if they are directly referenced in a JVMS. + assert(mv->possible_objects()->length() > idx, "Didn't add entry to possible_objects?!"); + assert(mv->possible_objects()->at(idx)->is_object(), "Entries in possible_objects should be ObjectValue."); + mv->possible_objects()->at(idx)->as_ObjectValue()->set_root(false); } } array->append(mv); @@ -1127,7 +1134,14 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { for (uint i = 1; i < smerge->req(); i++) { Node* obj_node = smerge->in(i); - FillLocArray(mv->possible_objects()->length(), sfn, obj_node, mv->possible_objects(), objs); + int idx = mv->possible_objects()->length(); + (void)FillLocArray(idx, sfn, obj_node, mv->possible_objects(), objs); + + // By default ObjectValues that are in 'possible_objects' are not root objects. + // They will be marked as root later if they are directly referenced in a JVMS. + assert(mv->possible_objects()->length() > idx, "Didn't add entry to possible_objects?!"); + assert(mv->possible_objects()->at(idx)->is_object(), "Entries in possible_objects should be ObjectValue."); + mv->possible_objects()->at(idx)->as_ObjectValue()->set_root(false); } } scval = mv; @@ -1158,11 +1172,17 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { for (int j = 0; j< merge->possible_objects()->length(); j++) { ObjectValue* ov = merge->possible_objects()->at(j)->as_ObjectValue(); - bool is_root = locarray->contains(ov) || - exparray->contains(ov) || - contains_as_owner(monarray, ov) || - contains_as_scalarized_obj(jvms, sfn, objs, ov); - ov->set_root(is_root); + if (ov->is_root()) { + // Already flagged as 'root' by something else. We shouldn't change it + // to non-root in a younger JVMS because it may need to be alive in + // a younger JVMS. + } else { + bool is_root = locarray->contains(ov) || + exparray->contains(ov) || + contains_as_owner(monarray, ov) || + contains_as_scalarized_obj(jvms, sfn, objs, ov); + ov->set_root(is_root); + } } } } @@ -1665,30 +1685,7 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { } } } - } -#ifdef ASSERT - // Check that oop-store precedes the card-mark - else if (mach->ideal_Opcode() == Op_StoreCM) { - uint storeCM_idx = j; - int count = 0; - for (uint prec = mach->req(); prec < mach->len(); prec++) { - Node *oop_store = mach->in(prec); // Precedence edge - if (oop_store == nullptr) continue; - count++; - uint i4; - for (i4 = 0; i4 < last_inst; ++i4) { - if (block->get_node(i4) == oop_store) { - break; - } - } - // Note: This test can provide a false failure if other precedence - // edges have been added to the storeCMNode. - assert(i4 == last_inst || i4 < storeCM_idx, "CM card-mark executes before oop-store"); - } - assert(count > 0, "storeCM expects at least one precedence edge"); - } -#endif - else if (!n->is_Proj()) { + } else if (!n->is_Proj()) { // Remember the beginning of the previous instruction, in case // it's followed by a flag-kill and a null-check. Happens on // Intel all the time, with add-to-memory kind of opcodes. @@ -1715,7 +1712,7 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { node_offsets[n->_idx] = masm->offset(); } #endif - assert(!C->failing(), "Should not reach here if failing."); + assert(!C->failing_internal() || C->failure_is_artificial(), "Should not reach here if failing."); // "Normal" instruction case DEBUG_ONLY(uint instr_offset = masm->offset()); @@ -2022,6 +2019,8 @@ void PhaseOutput::FillExceptionTables(uint cnt, uint *call_returns, uint *inct_s // Handle implicit null exception table updates if (n->is_MachNullCheck()) { + assert(n->in(1)->as_Mach()->barrier_data() == 0, + "Implicit null checks on memory accesses with barriers are not yet supported"); uint block_num = block->non_connector_successor(0)->_pre_order; _inc_table.append(inct_starts[inct_cnt++], blk_labels[block_num].loc_pos()); continue; @@ -3391,7 +3390,7 @@ uint PhaseOutput::scratch_emit_size(const Node* n) { n->emit(&masm, C->regalloc()); // Emitting into the scratch buffer should not fail - assert (!C->failing(), "Must not have pending failure. Reason is: %s", C->failure_reason()); + assert(!C->failing_internal() || C->failure_is_artificial(), "Must not have pending failure. Reason is: %s", C->failure_reason()); if (is_branch) // Restore label. n->as_MachBranch()->label_set(saveL, save_bnum); diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index 484c49367cc4d..039283bc863d1 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -426,7 +426,7 @@ class Parse : public GraphKit { void set_parse_bci(int bci); // Must this parse be aborted? - bool failing() { return C->failing(); } + bool failing() const { return C->failing_internal(); } // might have cascading effects, not stressing bailouts for now. Block* rpo_at(int rpo) { assert(0 <= rpo && rpo < _block_count, "oob"); diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 6b7cb4eaa99e3..d428024e53edc 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -1958,26 +1958,13 @@ void Parse::do_one_bytecode() { case Bytecodes::_ldc: case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: { + // ciTypeFlow should trap if the ldc is in error state or if the constant is not loaded + assert(!iter().is_in_error(), "ldc is in error state"); ciConstant constant = iter().get_constant(); - if (constant.is_loaded()) { - const Type* con_type = Type::make_from_constant(constant); - if (con_type != nullptr) { - push_node(con_type->basic_type(), makecon(con_type)); - } - } else { - // If the constant is unresolved or in error state, run this BC in the interpreter. - if (iter().is_in_error()) { - uncommon_trap(Deoptimization::make_trap_request(Deoptimization::Reason_unhandled, - Deoptimization::Action_none), - nullptr, "constant in error state", true /* must_throw */); - - } else { - int index = iter().get_constant_pool_index(); - uncommon_trap(Deoptimization::make_trap_request(Deoptimization::Reason_unloaded, - Deoptimization::Action_reinterpret, - index), - nullptr, "unresolved constant", false /* must_throw */); - } + assert(constant.is_loaded(), "constant is not loaded"); + const Type* con_type = Type::make_from_constant(constant); + if (con_type != nullptr) { + push_node(con_type->basic_type(), makecon(con_type)); } break; } diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 3887e8a5f6cdf..54a17376f18e4 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -23,7 +23,9 @@ */ #include "precompiled.hpp" +#include "opto/addnode.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/loopnode.hpp" #include "opto/node.hpp" #include "opto/predicates.hpp" @@ -32,6 +34,7 @@ // Walk over all Initialized Assertion Predicates and return the entry into the first Initialized Assertion Predicate // (i.e. not belonging to an Initialized Assertion Predicate anymore) Node* AssertionPredicatesWithHalt::find_entry(Node* start_proj) { + assert(start_proj != nullptr, "should not be null"); Node* entry = start_proj; while (AssertionPredicateWithHalt::is_predicate(entry)) { entry = entry->in(0)->in(0); @@ -39,19 +42,25 @@ Node* AssertionPredicatesWithHalt::find_entry(Node* start_proj) { return entry; } +// An Assertion Predicate has always a true projection on the success path. +bool may_be_assertion_predicate_if(const Node* node) { + assert(node != nullptr, "should not be null"); + return node->is_IfTrue() && RegularPredicate::may_be_predicate_if(node->as_IfProj()); +} + bool AssertionPredicateWithHalt::is_predicate(const Node* maybe_success_proj) { - if (maybe_success_proj == nullptr || !maybe_success_proj->is_IfProj() || !maybe_success_proj->in(0)->is_If()) { + if (!may_be_assertion_predicate_if(maybe_success_proj)) { return false; } return has_assertion_predicate_opaque(maybe_success_proj) && has_halt(maybe_success_proj); } -// Check if the If node of `predicate_proj` has an Opaque4 (Template Assertion Predicate) or an -// OpaqueInitializedAssertionPredicate (Initialized Assertion Predicate) node as input. +// Check if the If node of `predicate_proj` has an OpaqueTemplateAssertionPredicate (Template Assertion Predicate) or +// an OpaqueInitializedAssertionPredicate (Initialized Assertion Predicate) node as input. bool AssertionPredicateWithHalt::has_assertion_predicate_opaque(const Node* predicate_proj) { IfNode* iff = predicate_proj->in(0)->as_If(); Node* bol = iff->in(1); - return bol->is_Opaque4() || bol->is_OpaqueInitializedAssertionPredicate(); + return bol->is_OpaqueTemplateAssertionPredicate() || bol->is_OpaqueInitializedAssertionPredicate(); } // Check if the other projection (UCT projection) of `success_proj` has a Halt node as output. @@ -73,14 +82,6 @@ ParsePredicateNode* ParsePredicate::init_parse_predicate(Node* parse_predicate_p return nullptr; } -bool ParsePredicate::is_predicate(Node* maybe_success_proj) { - if (!maybe_success_proj->is_IfProj()) { - return false; - } - IfNode* if_node = maybe_success_proj->in(0)->as_If(); - return if_node->is_ParsePredicate(); -} - Deoptimization::DeoptReason RegularPredicateWithUCT::uncommon_trap_reason(IfProjNode* if_proj) { CallStaticJavaNode* uct_call = if_proj->is_uncommon_trap_if_pattern(); if (uct_call == nullptr) { @@ -90,28 +91,33 @@ Deoptimization::DeoptReason RegularPredicateWithUCT::uncommon_trap_reason(IfProj } bool RegularPredicateWithUCT::is_predicate(Node* maybe_success_proj) { - if (may_be_predicate_if(maybe_success_proj)) { - IfProjNode* success_proj = maybe_success_proj->as_IfProj(); - const Deoptimization::DeoptReason deopt_reason = uncommon_trap_reason(success_proj); - return (deopt_reason == Deoptimization::Reason_loop_limit_check || - deopt_reason == Deoptimization::Reason_predicate || - deopt_reason == Deoptimization::Reason_profile_predicate); + if (RegularPredicate::may_be_predicate_if(maybe_success_proj)) { + return has_valid_uncommon_trap(maybe_success_proj); } else { return false; } } -bool RegularPredicateWithUCT::is_predicate(Node* node, Deoptimization::DeoptReason deopt_reason) { - if (may_be_predicate_if(node)) { +bool RegularPredicateWithUCT::has_valid_uncommon_trap(const Node* success_proj) { + assert(RegularPredicate::may_be_predicate_if(success_proj), "must have been checked before"); + const Deoptimization::DeoptReason deopt_reason = uncommon_trap_reason(success_proj->as_IfProj()); + return (deopt_reason == Deoptimization::Reason_loop_limit_check || + deopt_reason == Deoptimization::Reason_predicate || + deopt_reason == Deoptimization::Reason_profile_predicate); +} + +bool RegularPredicateWithUCT::is_predicate(const Node* node, Deoptimization::DeoptReason deopt_reason) { + if (RegularPredicate::may_be_predicate_if(node)) { return deopt_reason == uncommon_trap_reason(node->as_IfProj()); } else { return false; } } -// A Runtime Predicate must have an If or a RangeCheck node, while the If should not be a zero trip guard check. -bool RegularPredicateWithUCT::may_be_predicate_if(Node* node) { - if (node->is_IfProj()) { +// A Regular Predicate must have an If or a RangeCheck node, while the If should not be a zero trip guard check. +// Note that this method can be called during IGVN, so we also need to check that the If is not top. +bool RegularPredicate::may_be_predicate_if(const Node* node) { + if (node->is_IfProj() && node->in(0)->is_If()) { const IfNode* if_node = node->in(0)->as_If(); const int opcode_if = if_node->Opcode(); if ((opcode_if == Op_If && !if_node->is_zero_trip_guard()) @@ -122,39 +128,55 @@ bool RegularPredicateWithUCT::may_be_predicate_if(Node* node) { return false; } -bool RuntimePredicate::is_success_proj(Node* node, Deoptimization::DeoptReason deopt_reason) { +// Runtime Predicates always have an UCT since they could normally fail at runtime. In this case we execute the trap +// on the failing path. +bool RuntimePredicate::is_predicate(Node* node) { + return RegularPredicateWithUCT::is_predicate(node); +} + +bool RuntimePredicate::is_predicate(Node* node, Deoptimization::DeoptReason deopt_reason) { return RegularPredicateWithUCT::is_predicate(node, deopt_reason); } -ParsePredicateIterator::ParsePredicateIterator(const Predicates& predicates) : _current_index(0) { - const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block(); - if (loop_limit_check_predicate_block->has_parse_predicate()) { - _parse_predicates.push(loop_limit_check_predicate_block->parse_predicate()); - } - if (UseProfiledLoopPredicate) { - const PredicateBlock* profiled_loop_predicate_block = predicates.profiled_loop_predicate_block(); - if (profiled_loop_predicate_block->has_parse_predicate()) { - _parse_predicates.push(profiled_loop_predicate_block->parse_predicate()); +// Rewire any non-CFG nodes dependent on this Template Assertion Predicate (i.e. with a control input to this +// Template Assertion Predicate) to the 'target_predicate' based on the 'data_in_loop_body' check. +void TemplateAssertionPredicate::rewire_loop_data_dependencies(IfTrueNode* target_predicate, + const NodeInLoopBody& data_in_loop_body, + PhaseIdealLoop* phase) const { + for (DUIterator i = _success_proj->outs(); _success_proj->has_out(i); i++) { + Node* output = _success_proj->out(i); + if (!output->is_CFG() && data_in_loop_body.check(output)) { + phase->igvn().replace_input_of(output, 0, target_predicate); + --i; // account for the just deleted output } } - if (UseLoopPredicate) { - const PredicateBlock* loop_predicate_block = predicates.loop_predicate_block(); - if (loop_predicate_block->has_parse_predicate()) { - _parse_predicates.push(loop_predicate_block->parse_predicate()); - } +} + + +// Template Assertion Predicates always have the dedicated OpaqueTemplateAssertionPredicate to identify them. +bool TemplateAssertionPredicate::is_predicate(Node* node) { + if (!may_be_assertion_predicate_if(node)) { + return false; } + IfNode* if_node = node->in(0)->as_If(); + return if_node->in(1)->is_OpaqueTemplateAssertionPredicate(); } -ParsePredicateNode* ParsePredicateIterator::next() { - assert(has_next(), "always check has_next() first"); - return _parse_predicates.at(_current_index++); +// Initialized Assertion Predicates always have the dedicated OpaqueInitiailizedAssertionPredicate node to identify +// them. +bool InitializedAssertionPredicate::is_predicate(Node* node) { + if (!may_be_assertion_predicate_if(node)) { + return false; + } + IfNode* if_node = node->in(0)->as_If(); + return if_node->in(1)->is_OpaqueInitializedAssertionPredicate(); } #ifdef ASSERT // Check that the block has at most one Parse Predicate and that we only find Regular Predicate nodes (i.e. IfProj, // If, or RangeCheck nodes). -void PredicateBlock::verify_block() { - Node* next = _parse_predicate.entry(); // Skip unique Parse Predicate of this block if present +void RegularPredicateBlock::verify_block(Node* tail) { + Node* next = tail; while (next != _entry) { assert(!next->is_ParsePredicate(), "can only have one Parse Predicate in a block"); const int opcode = next->Opcode(); @@ -166,17 +188,6 @@ void PredicateBlock::verify_block() { } #endif // ASSERT -// Walk over all Regular Predicates of this block (if any) and return the first node not belonging to the block -// anymore (i.e. entry to the first Regular Predicate in this block if any or `regular_predicate_proj` otherwise). -Node* PredicateBlock::skip_regular_predicates(Node* regular_predicate_proj, Deoptimization::DeoptReason deopt_reason) { - Node* entry = regular_predicate_proj; - while (RuntimePredicate::is_success_proj(entry, deopt_reason)) { - assert(entry->in(0)->as_If(), "must be If node"); - entry = entry->in(0)->in(0); - } - return entry; -} - // This strategy clones the OpaqueLoopInit and OpaqueLoopStride nodes. class CloneStrategy : public TransformStrategyForOpaqueLoopNodes { PhaseIdealLoop* const _phase; @@ -240,29 +251,29 @@ class ReplaceInitAndStrideStrategy : public TransformStrategyForOpaqueLoopNodes } }; -// Creates an identical clone of this Template Assertion Expression (i.e.cloning all nodes from the Opaque4Node to and -// including the OpaqueLoop* nodes). The cloned nodes are rewired to reflect the same graph structure as found for this -// Template Assertion Expression. The cloned nodes get 'new_ctrl' as ctrl. There is no other update done for the cloned -// nodes. Return the newly cloned Opaque4Node. -Opaque4Node* TemplateAssertionExpression::clone(Node* new_ctrl, PhaseIdealLoop* phase) { +// Creates an identical clone of this Template Assertion Expression (i.e.cloning all nodes from the +// OpaqueTemplateAssertionPredicate to and including the OpaqueLoop* nodes). The cloned nodes are rewired to reflect the +// same graph structure as found for this Template Assertion Expression. The cloned nodes get 'new_ctrl' as ctrl. There +// is no other update done for the cloned nodes. Return the newly cloned OpaqueTemplateAssertionPredicate. +OpaqueTemplateAssertionPredicateNode* TemplateAssertionExpression::clone(Node* new_ctrl, PhaseIdealLoop* phase) { CloneStrategy clone_init_and_stride_strategy(phase, new_ctrl); return clone(clone_init_and_stride_strategy, new_ctrl, phase); } // Same as clone() but instead of cloning the OpaqueLoopInitNode, we replace it with the provided 'new_init' node. -Opaque4Node* TemplateAssertionExpression::clone_and_replace_init(Node* new_init, Node* new_ctrl, - PhaseIdealLoop* phase) { +OpaqueTemplateAssertionPredicateNode* +TemplateAssertionExpression::clone_and_replace_init(Node* new_init, Node* new_ctrl, PhaseIdealLoop* phase) { ReplaceInitAndCloneStrideStrategy replace_init_and_clone_stride_strategy(new_init, new_ctrl, phase); return clone(replace_init_and_clone_stride_strategy, new_ctrl, phase); } // Same as clone() but instead of cloning the OpaqueLoopInit and OpaqueLoopStride node, we replace them with the provided // 'new_init' and 'new_stride' nodes, respectively. -Opaque4Node* TemplateAssertionExpression::clone_and_replace_init_and_stride(Node* new_init, Node* new_stride, - Node* new_ctrl, - PhaseIdealLoop* phase) { +OpaqueTemplateAssertionPredicateNode* +TemplateAssertionExpression::clone_and_replace_init_and_stride(Node* new_control, Node* new_init, Node* new_stride, + PhaseIdealLoop* phase) { ReplaceInitAndStrideStrategy replace_init_and_stride_strategy(new_init, new_stride); - return clone(replace_init_and_stride_strategy, new_ctrl, phase); + return clone(replace_init_and_stride_strategy, new_control, phase); } // Class to collect data nodes from a source to target nodes by following the inputs of the source node recursively. @@ -343,20 +354,21 @@ class DataNodesOnPathsToTargets : public StackObj { }; // Clones this Template Assertion Expression and applies the given strategy to transform the OpaqueLoop* nodes. -Opaque4Node* TemplateAssertionExpression::clone(const TransformStrategyForOpaqueLoopNodes& transform_strategy, - Node* new_ctrl, PhaseIdealLoop* phase) { +OpaqueTemplateAssertionPredicateNode* +TemplateAssertionExpression::clone(const TransformStrategyForOpaqueLoopNodes& transform_strategy, Node* new_ctrl, + PhaseIdealLoop* phase) { ResourceMark rm; auto is_opaque_loop_node = [](const Node* node) { return node->is_Opaque1(); }; DataNodesOnPathsToTargets data_nodes_on_path_to_targets(TemplateAssertionExpressionNode::is_maybe_in_expression, is_opaque_loop_node); - const Unique_Node_List& collected_nodes = data_nodes_on_path_to_targets.collect(_opaque4_node); + const Unique_Node_List& collected_nodes = data_nodes_on_path_to_targets.collect(_opaque_node); DataNodeGraph data_node_graph(collected_nodes, phase); const OrigToNewHashtable& orig_to_new = data_node_graph.clone_with_opaque_loop_transform_strategy(transform_strategy, new_ctrl); - assert(orig_to_new.contains(_opaque4_node), "must exist"); - Node* opaque4_clone = *orig_to_new.get(_opaque4_node); - return opaque4_clone->as_Opaque4(); + assert(orig_to_new.contains(_opaque_node), "must exist"); + Node* opaque_node_clone = *orig_to_new.get(_opaque_node); + return opaque_node_clone->as_OpaqueTemplateAssertionPredicate(); } // Check if this node belongs a Template Assertion Expression (including OpaqueLoop* nodes). @@ -378,100 +390,362 @@ bool TemplateAssertionExpressionNode::is_in_expression(Node* node) { } bool TemplateAssertionExpressionNode::is_template_assertion_predicate(Node* node) { - return node->is_If() && node->in(1)->is_Opaque4(); + return node->is_If() && node->in(1)->is_OpaqueTemplateAssertionPredicate(); } -InitializedAssertionPredicate::InitializedAssertionPredicate(IfNode* template_assertion_predicate, Node* new_init, - Node* new_stride, PhaseIdealLoop* phase) - : _template_assertion_predicate(template_assertion_predicate), - _new_init(new_init), - _new_stride(new_stride), - _phase(phase) {} +// This class creates the Assertion Predicate expression to be used for a Template or Initialized Assertion Predicate. +class AssertionPredicateExpressionCreator : public StackObj { + PhaseIdealLoop* const _phase; + const jint _stride; + const int _scale; + Node* const _offset; + Node* const _range; + const bool _upper; -// Create an Initialized Assertion Predicate at the provided control from the _template_assertion_predicate. -// We clone the Template Assertion Expression and replace: -// - Opaque4 with OpaqueInitializedAssertionPredicate -// - OpaqueLoop*Nodes with _new_init and _new_stride, respectively. + public: + AssertionPredicateExpressionCreator(const int stride, const int scale, Node* offset, Node* range, + PhaseIdealLoop* phase) + : _phase(phase), + _stride(stride), + _scale(scale), + _offset(offset), + _range(range), + _upper((_stride > 0) != (_scale > 0)) {} // Make sure rc_predicate() chooses the "scale*init + offset" case. + + // Create the expression for a Template Assertion Predicate with an OpaqueTemplateAssertionPredicate node. + OpaqueTemplateAssertionPredicateNode* create_for_template(Node* new_control, Node* operand, bool& does_overflow) const { + BoolNode* bool_for_expression = _phase->rc_predicate(new_control, _scale, _offset, operand, nullptr, + _stride, _range, _upper, does_overflow); + return create_opaque_node(new_control, bool_for_expression); + } + + private: + OpaqueTemplateAssertionPredicateNode* create_opaque_node(Node* new_control, BoolNode* bool_for_expression) const { + OpaqueTemplateAssertionPredicateNode* new_expression = new OpaqueTemplateAssertionPredicateNode(bool_for_expression); + _phase->C->add_template_assertion_predicate_opaq(new_expression); + _phase->register_new_node(new_expression, new_control); + return new_expression; + } + + public: + // Create the expression for an Initialized Assertion Predicate with an OpaqueInitializedAssertionPredicate node. + OpaqueInitializedAssertionPredicateNode* create_for_initialized(Node* new_control, Node* operand, + bool& does_overflow) const { + BoolNode* bool_for_expression = _phase->rc_predicate(new_control, _scale, _offset, operand, nullptr, + _stride, _range, _upper, does_overflow); + return create_opaque_initialized_assertion_predicate_node(new_control, bool_for_expression); + } + + private: + OpaqueInitializedAssertionPredicateNode* create_opaque_initialized_assertion_predicate_node( + Node* new_control, BoolNode* bool_for_expression) const { + OpaqueInitializedAssertionPredicateNode* new_expression = + new OpaqueInitializedAssertionPredicateNode(bool_for_expression, _phase->C); + _phase->register_new_node(new_expression, new_control); + return new_expression; + } +}; + +// Creates an If with a success and a fail path with the given assertion_expression. The only difference to +// create_for_initialized() is that we use a template specific Halt message on the fail path. +IfTrueNode* AssertionPredicateIfCreator::create_for_template(Node* new_control, const int if_opcode, + Node* assertion_expression NOT_PRODUCT(COMMA + const AssertionPredicateType assertion_predicate_type)) { + const char* halt_message = "Template Assertion Predicates are always removed before code generation"; + return create(new_control, if_opcode, assertion_expression, halt_message NOT_PRODUCT(COMMA assertion_predicate_type)); +} + +// Creates an If with a success and a fail path with the given assertion_expression. The only difference to +// create_for_template() is that we use a initialized specific Halt message on the fail path. +IfTrueNode* AssertionPredicateIfCreator::create_for_initialized(Node* new_control, const int if_opcode, + Node* assertion_expression NOT_PRODUCT(COMMA + const AssertionPredicateType assertion_predicate_type)) { + const char* halt_message = "Initialized Assertion Predicate cannot fail"; + return create(new_control, if_opcode, assertion_expression, halt_message NOT_PRODUCT(COMMA assertion_predicate_type)); +} + +// Creates the If node for an Assertion Predicate with a success path and a fail path having a Halt node: // -// / init stride -// | | | -// | OpaqueLoopInitNode OpaqueLoopStrideNode / _new_init _new_stride -// Template | \ / | \ / -// Assertion | ... Assertion | ... -// Expression | | Expression | | -// | Bool | new Bool -// | | | | -// \ Opaque4 ======> control \ OpaqueInitializedAssertionPredicate -// | \ / -// If new If -// / \ / \ -// success fail path new success new Halt -// proj (Halt or UCT) proj +// new_control assertion_expression +// \ / +// If +// / \ +// success fail path +// proj with Halt // -IfTrueNode* InitializedAssertionPredicate::create(Node* control) { - IdealLoopTree* loop = _phase->get_loop(control); - OpaqueInitializedAssertionPredicateNode* assertion_expression = create_assertion_expression(control); - IfNode* if_node = create_if_node(control, assertion_expression, loop); - create_fail_path(if_node, loop); +IfTrueNode* AssertionPredicateIfCreator::create(Node* new_control, const int if_opcode, Node* assertion_expression, + const char* halt_message NOT_PRODUCT(COMMA + const AssertionPredicateType assertion_predicate_type)) { + assert(assertion_expression->is_OpaqueTemplateAssertionPredicate() || + assertion_expression->is_OpaqueInitializedAssertionPredicate(), "not a valid assertion expression"); + IdealLoopTree* loop = _phase->get_loop(new_control); + IfNode* if_node = create_if_node(new_control, if_opcode, assertion_expression, loop + NOT_PRODUCT(COMMA assertion_predicate_type)); + create_fail_path(if_node, loop, halt_message); return create_success_path(if_node, loop); } -// Create a new Assertion Expression to be used as bool input for the Initialized Assertion Predicate IfNode. -OpaqueInitializedAssertionPredicateNode* InitializedAssertionPredicate::create_assertion_expression(Node* control) { - Opaque4Node* template_opaque = _template_assertion_predicate->in(1)->as_Opaque4(); - TemplateAssertionExpression template_assertion_expression(template_opaque); - Opaque4Node* tmp_opaque = template_assertion_expression.clone_and_replace_init_and_stride(_new_init, _new_stride, - control, _phase); - OpaqueInitializedAssertionPredicateNode* assertion_expression = - new OpaqueInitializedAssertionPredicateNode(tmp_opaque->in(1)->as_Bool(), _phase->C); - _phase->register_new_node(assertion_expression, control); - return assertion_expression; -} - -IfNode* InitializedAssertionPredicate::create_if_node(Node* control, - OpaqueInitializedAssertionPredicateNode* assertion_expression, - IdealLoopTree* loop) { - const int if_opcode = _template_assertion_predicate->Opcode(); - NOT_PRODUCT(const AssertionPredicateType assertion_predicate_type = _template_assertion_predicate->assertion_predicate_type();) - IfNode* if_node = if_opcode == Op_If ? - new IfNode(control, assertion_expression, PROB_MAX, COUNT_UNKNOWN NOT_PRODUCT(COMMA assertion_predicate_type)) : - new RangeCheckNode(control, assertion_expression, PROB_MAX, COUNT_UNKNOWN NOT_PRODUCT(COMMA assertion_predicate_type)); - _phase->register_control(if_node, loop, control); +IfNode* AssertionPredicateIfCreator::create_if_node(Node* new_control, const int if_opcode, Node* assertion_expression, + IdealLoopTree* loop NOT_PRODUCT(COMMA + const AssertionPredicateType assertion_predicate_type)) { + IfNode* if_node; + if (if_opcode == Op_If) { + if_node = new IfNode(new_control, assertion_expression, PROB_MAX, COUNT_UNKNOWN + NOT_PRODUCT(COMMA assertion_predicate_type)); + } else { + assert(if_opcode == Op_RangeCheck, "must be range check"); + if_node = new RangeCheckNode(new_control, assertion_expression, PROB_MAX, COUNT_UNKNOWN + NOT_PRODUCT(COMMA assertion_predicate_type)); + } + _phase->register_control(if_node, loop, new_control); return if_node; } -IfTrueNode* InitializedAssertionPredicate::create_success_path(IfNode* if_node, IdealLoopTree* loop) { +IfTrueNode* AssertionPredicateIfCreator::create_success_path(IfNode* if_node, IdealLoopTree* loop) { IfTrueNode* success_proj = new IfTrueNode(if_node); _phase->register_control(success_proj, loop, if_node); return success_proj; } -void InitializedAssertionPredicate::create_fail_path(IfNode* if_node, IdealLoopTree* loop) { +void AssertionPredicateIfCreator::create_fail_path(IfNode* if_node, IdealLoopTree* loop, const char* halt_message) { IfFalseNode* fail_proj = new IfFalseNode(if_node); _phase->register_control(fail_proj, loop, if_node); - create_halt_node(fail_proj, loop); + create_halt_node(fail_proj, loop, halt_message); } -void InitializedAssertionPredicate::create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop) { +void AssertionPredicateIfCreator::create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop, + const char* halt_message) { StartNode* start_node = _phase->C->start(); Node* frame = new ParmNode(start_node, TypeFunc::FramePtr); _phase->register_new_node(frame, start_node); - Node* halt = new HaltNode(fail_proj, frame, "Initialized Assertion Predicate cannot fail"); + Node* halt = new HaltNode(fail_proj, frame, halt_message); _phase->igvn().add_input_to(_phase->C->root(), halt); _phase->register_control(halt, loop, fail_proj); } -// Is current node pointed to by iterator a predicate? -bool PredicateEntryIterator::has_next() const { - return ParsePredicate::is_predicate(_current) || - RegularPredicateWithUCT::is_predicate(_current) || - AssertionPredicateWithHalt::is_predicate(_current); +// Creates an init and last value Template Assertion Predicate connected together from a Parse Predicate with an UCT on +// the failing path. Returns the success projection of the last value Template Assertion Predicate. +IfTrueNode* TemplateAssertionPredicateCreator::create_with_uncommon_trap( + Node* new_control, ParsePredicateSuccessProj* parse_predicate_success_proj, + const Deoptimization::DeoptReason deopt_reason, const int if_opcode) { + OpaqueLoopInitNode* opaque_init = create_opaque_init(new_control); + bool does_overflow; + OpaqueTemplateAssertionPredicateNode* template_assertion_predicate_expression = + create_for_init_value(new_control, opaque_init, does_overflow); + IfTrueNode* template_predicate_success_proj = + create_if_node_with_uncommon_trap(template_assertion_predicate_expression, parse_predicate_success_proj, + deopt_reason, if_opcode, does_overflow + NOT_PRODUCT(COMMA AssertionPredicateType::InitValue)); + template_assertion_predicate_expression = create_for_last_value(template_predicate_success_proj, opaque_init, + does_overflow); + return create_if_node_with_uncommon_trap(template_assertion_predicate_expression, parse_predicate_success_proj, + deopt_reason, if_opcode, does_overflow + NOT_PRODUCT(COMMA AssertionPredicateType::LastValue)); } -// Skip the current predicate pointed to by iterator by returning the input into the predicate. This could possibly be -// a non-predicate node. -Node* PredicateEntryIterator::next_entry() { - assert(has_next(), "current must be predicate"); - _current = _current->in(0)->in(0); - return _current; +OpaqueLoopInitNode* TemplateAssertionPredicateCreator::create_opaque_init(Node* new_control) { + OpaqueLoopInitNode* opaque_init = new OpaqueLoopInitNode(_phase->C, _loop_head->init_trip()); + _phase->register_new_node(opaque_init, new_control); + return opaque_init; +} + +OpaqueTemplateAssertionPredicateNode* +TemplateAssertionPredicateCreator::create_for_init_value(Node* new_control, OpaqueLoopInitNode* opaque_init, + bool& does_overflow) const { + AssertionPredicateExpressionCreator expression_creator(_loop_head->stride_con(), _scale, _offset, _range, _phase); + return expression_creator.create_for_template(new_control, opaque_init, does_overflow); +} + +IfTrueNode* TemplateAssertionPredicateCreator::create_if_node_with_uncommon_trap( + OpaqueTemplateAssertionPredicateNode* template_assertion_predicate_expression, + ParsePredicateSuccessProj* parse_predicate_success_proj, const Deoptimization::DeoptReason deopt_reason, + const int if_opcode, const bool does_overflow + NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)) { + IfTrueNode* success_proj = _phase->create_new_if_for_predicate(parse_predicate_success_proj, nullptr, deopt_reason, + does_overflow ? Op_If : if_opcode, false + NOT_PRODUCT(COMMA assertion_predicate_type)); + _phase->igvn().replace_input_of(success_proj->in(0), 1, template_assertion_predicate_expression); + return success_proj; +} + +OpaqueTemplateAssertionPredicateNode* +TemplateAssertionPredicateCreator::create_for_last_value(Node* new_control, OpaqueLoopInitNode* opaque_init, + bool& does_overflow) const { + Node* last_value = create_last_value(new_control, opaque_init); + AssertionPredicateExpressionCreator expression_creator(_loop_head->stride_con(), _scale, _offset, _range, _phase); + return expression_creator.create_for_template(new_control, last_value, does_overflow); +} + +Node* TemplateAssertionPredicateCreator::create_last_value(Node* new_control, OpaqueLoopInitNode* opaque_init) const { + Node* init_stride = _loop_head->stride(); + Node* opaque_stride = new OpaqueLoopStrideNode(_phase->C, init_stride); + _phase->register_new_node(opaque_stride, new_control); + Node* last_value = new SubINode(opaque_stride, init_stride); + _phase->register_new_node(last_value, new_control); + last_value = new AddINode(opaque_init, last_value); + _phase->register_new_node(last_value, new_control); + // init + (current stride - initial stride) is within the loop so narrow its type by leveraging the type of the iv phi + last_value = new CastIINode(new_control, last_value, _loop_head->phi()->bottom_type()); + _phase->register_new_node(last_value, new_control); + return last_value; +} + +IfTrueNode* TemplateAssertionPredicateCreator::create_if_node_with_halt( + Node* new_control, OpaqueTemplateAssertionPredicateNode* template_assertion_predicate_expression, bool does_overflow + NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)) { + AssertionPredicateIfCreator assertion_predicate_if_creator(_phase); + return assertion_predicate_if_creator.create_for_template(new_control, does_overflow ? Op_If : Op_RangeCheck, + template_assertion_predicate_expression + NOT_PRODUCT(COMMA assertion_predicate_type)); +} + +// Creates an init and last value Template Assertion Predicate connected together with a Halt node on the failing path. +// Returns the success projection of the last value Template Assertion Predicate latter. +IfTrueNode* TemplateAssertionPredicateCreator::create_with_halt(Node* new_control) { + OpaqueLoopInitNode* opaque_init = create_opaque_init(new_control); + bool does_overflow; + OpaqueTemplateAssertionPredicateNode* template_assertion_predicate_expression = + create_for_init_value(new_control, opaque_init, does_overflow); + IfTrueNode* template_predicate_success_proj = + create_if_node_with_halt(new_control, template_assertion_predicate_expression, does_overflow + NOT_PRODUCT(COMMA AssertionPredicateType::InitValue)); + template_assertion_predicate_expression = create_for_last_value(template_predicate_success_proj, opaque_init, + does_overflow); + return create_if_node_with_halt(template_predicate_success_proj, template_assertion_predicate_expression, + does_overflow NOT_PRODUCT(COMMA AssertionPredicateType::LastValue)); +} + +InitializedAssertionPredicateCreator::InitializedAssertionPredicateCreator(PhaseIdealLoop* phase) + : _phase(phase) {} + +// Create an Initialized Assertion Predicate from the provided template_assertion_predicate at 'new_control'. +// We clone the Template Assertion Expression and replace: +// - OpaqueTemplateAssertionPredicateNode with OpaqueInitializedAssertionPredicate +// - OpaqueLoop*Nodes with new_init and _ew_stride, respectively. +// +// / init stride +// | | | +// | OpaqueLoopInitNode OpaqueLoopStrideNode / new_init new_stride +// Template | \ / | \ / +// Assertion | ... Assertion | ... +// Expression | | Expression | | +// | Bool | new Bool +// | | | | +// \ OpaqueTemplateAssertionPredicate ===> new_control \ OpaqueInitializedAssertionPredicate +// | \ / +// If new If +// / \ / \ +// success fail path new success new Halt +// proj (Halt or UCT) proj +// +IfTrueNode* InitializedAssertionPredicateCreator::create_from_template(IfNode* template_assertion_predicate, + Node* new_control, Node* new_init, + Node* new_stride) { + OpaqueInitializedAssertionPredicateNode* assertion_expression = + create_assertion_expression_from_template(template_assertion_predicate, new_control, new_init, new_stride); + return create_control_nodes(new_control, template_assertion_predicate->Opcode(), assertion_expression + NOT_PRODUCT(COMMA template_assertion_predicate->assertion_predicate_type())); +} + +// Create a new Initialized Assertion Predicate directly without a template. +IfTrueNode* InitializedAssertionPredicateCreator::create(Node* operand, Node* new_control, const jint stride, + const int scale, Node* offset, Node* range NOT_PRODUCT(COMMA + AssertionPredicateType assertion_predicate_type)) { + AssertionPredicateExpressionCreator expression_creator(stride, scale, offset, range, _phase); + bool does_overflow; + OpaqueInitializedAssertionPredicateNode* assertion_expression = + expression_creator.create_for_initialized(new_control, operand, does_overflow); + return create_control_nodes(new_control, does_overflow ? Op_If : Op_RangeCheck, assertion_expression + NOT_PRODUCT(COMMA assertion_predicate_type)); +} + +// Creates the CFG nodes for the Initialized Assertion Predicate. +IfTrueNode* InitializedAssertionPredicateCreator::create_control_nodes( + Node* new_control, const int if_opcode, OpaqueInitializedAssertionPredicateNode* assertion_expression + NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)) { + AssertionPredicateIfCreator assertion_predicate_if_creator(_phase); + return assertion_predicate_if_creator.create_for_initialized(new_control, if_opcode, assertion_expression + NOT_PRODUCT(COMMA assertion_predicate_type)); +} + +// Create a new Assertion Expression based from the given template to be used as bool input for the Initialized +// Assertion Predicate IfNode. +OpaqueInitializedAssertionPredicateNode* +InitializedAssertionPredicateCreator::create_assertion_expression_from_template(IfNode* template_assertion_predicate, + Node* new_control, Node* new_init, + Node* new_stride) { + OpaqueTemplateAssertionPredicateNode* template_opaque = + template_assertion_predicate->in(1)->as_OpaqueTemplateAssertionPredicate(); + TemplateAssertionExpression template_assertion_expression(template_opaque); + OpaqueTemplateAssertionPredicateNode* tmp_opaque = + template_assertion_expression.clone_and_replace_init_and_stride(new_control, new_init, new_stride, _phase); + OpaqueInitializedAssertionPredicateNode* assertion_expression = + new OpaqueInitializedAssertionPredicateNode(tmp_opaque->in(1)->as_Bool(), _phase->C); + _phase->register_new_node(assertion_expression, new_control); + return assertion_expression; +} + +#ifndef PRODUCT +void PredicateBlock::dump() const { + dump(""); +} + +void PredicateBlock::dump(const char* prefix) const { + if (is_non_empty()) { + PredicatePrinter printer(prefix); + PredicateBlockIterator iterator(_tail, _deopt_reason); + iterator.for_each(printer); + } else { + tty->print_cr("%s- ", prefix); + } +} + +// Dumps all predicates from the loop to the earliest predicate in a pretty format. +void Predicates::dump() const { + if (has_any()) { + Node* loop_head = _tail->unique_ctrl_out(); + tty->print_cr("%d %s:", loop_head->_idx, loop_head->Name()); + tty->print_cr("- Loop Limit Check Predicate Block:"); + _loop_limit_check_predicate_block.dump(" "); + tty->print_cr("- Profiled Loop Predicate Block:"); + _profiled_loop_predicate_block.dump(" "); + tty->print_cr("- Loop Predicate Block:"); + _loop_predicate_block.dump(" "); + tty->cr(); + } else { + tty->print_cr(""); + } +} + +void Predicates::dump_at(Node* node) { + Predicates predicates(node); + predicates.dump(); +} + +// Debug method to dump all predicates that are found above 'loop_node'. +void Predicates::dump_for_loop(LoopNode* loop_node) { + dump_at(loop_node->skip_strip_mined()->in(LoopNode::EntryControl)); +} +#endif // NOT PRODUCT + +// Keep track of whether we are in the correct Predicate Block where Template Assertion Predicates can be found. +// The PredicateIterator will always start at the loop entry and first visits the Loop Limit Check Predicate Block. +void CreateAssertionPredicatesVisitor::visit(const ParsePredicate& parse_predicate) { + Deoptimization::DeoptReason deopt_reason = parse_predicate.head()->deopt_reason(); + if (deopt_reason == Deoptimization::Reason_predicate || + deopt_reason == Deoptimization::Reason_profile_predicate) { + _has_hoisted_check_parse_predicates = true; + } +} + +void CreateAssertionPredicatesVisitor::visit(const TemplateAssertionPredicate& template_assertion_predicate) { + if (!_has_hoisted_check_parse_predicates) { + // Only process if we are in the correct Predicate Block. + return; + } + IfNode* template_head = template_assertion_predicate.head(); + IfTrueNode* initialized_predicate = _phase->create_initialized_assertion_predicate(template_head, _init, _stride, + _new_control); + template_assertion_predicate.rewire_loop_data_dependencies(initialized_predicate, _node_in_loop_body, _phase); + _new_control = initialized_predicate; } diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index 96f5c438b802f..5eb0cfc9b3578 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -30,6 +30,11 @@ #include "opto/opaquenode.hpp" class IdealLoopTree; +class InitializedAssertionPredicate; +class ParsePredicate; +class PredicateVisitor; +class RuntimePredicate; +class TemplateAssertionPredicate; /* * There are different kinds of predicates throughout the code. We differentiate between the following predicates: @@ -77,8 +82,8 @@ class IdealLoopTree; * actually dead. Assertion Predicates come to the rescue to fold such seemingly dead sub loops * away to avoid a broken graph. Assertion Predicates are left in the graph as a sanity checks in * debug builds (they must never fail at runtime) while they are being removed in product builds. - * We use special Opaque4 nodes to block some optimizations and replace the Assertion Predicates - * later in product builds. + * We use special OpaqueTemplateAssertionPredicateNode nodes to block some optimizations and replace + * the Assertion Predicates later in product builds. * * There are two kinds of Assertion Predicates: * - Template Assertion Predicate: A template for an Assertion Predicate that uses OpaqueLoop* @@ -152,7 +157,8 @@ class IdealLoopTree; * together. * - Loop Limit Check Groups the Loop Limit Check Predicate (if created) and the Loop Limit * Predicate Block: Check Parse Predicate (if not removed, yet) together. - * + * - Regular Predicate Block: A block that only contains the Regular Predicates of a Predicate Block without the + * Parse Predicate. * * Initially, before applying any loop-splitting optimizations, we find the following structure after Loop Predication * (predicates inside square brackets [] do not need to exist if there are no checks to hoist): @@ -201,10 +207,53 @@ class IdealLoopTree; enum class AssertionPredicateType { None, // Not an Assertion Predicate InitValue, - LastValue + LastValue, + // Used for the Initialized Assertion Predicate emitted during Range Check Elimination for the final IV value. + FinalIv }; #endif // NOT PRODUCT +// Interface to represent a C2 predicate. A predicate is always represented by two CFG nodes: +// - An If node (head) +// - An IfProj node representing the success projection of the If node (tail). +class Predicate : public StackObj { + public: + // Return the unique entry CFG node into the predicate. + virtual Node* entry() const = 0; + + // Return the head node of the predicate which is either: + // - A ParsePredicateNode if the predicate is a Parse Predicate + // - An IfNode or RangeCheckNode, otherwise. + virtual IfNode* head() const = 0; + + // Return the tail node of the predicate. Runtime Predicates can either have a true of false projection as success + // projection while Parse Predicates and Assertion Predicates always have a true projection as success projection. + virtual IfProjNode* tail() const = 0; +}; + +// Generic predicate visitor that does nothing. Subclass this visitor to add customized actions for each predicate. +// The visit methods of this visitor are called from the predicate iterator classes which walk the predicate chain. +// Use the UnifiedPredicateVisitor if the type of the predicate does not matter. +class PredicateVisitor : StackObj { + public: + virtual void visit(const ParsePredicate& parse_predicate) {} + virtual void visit(const RuntimePredicate& runtime_predicate) {} + virtual void visit(const TemplateAssertionPredicate& template_assertion_predicate) {} + virtual void visit(const InitializedAssertionPredicate& initialized_assertion_predicate) {} + + // This method can be overridden to stop the predicate iterators from visiting more predicates further up in the + // predicate chain. + virtual bool should_continue() const { + return true; + } +}; + +// Interface to check whether a node is in a loop body or not. +class NodeInLoopBody : public StackObj { + public: + virtual bool check(Node* node) const = 0; +}; + // Class to represent Assertion Predicates with a HaltNode instead of an UCT (i.e. either an Initialized Assertion // Predicate or a Template Assertion Predicate created after the initial one at Loop Predication). class AssertionPredicatesWithHalt : public StackObj { @@ -228,9 +277,15 @@ class AssertionPredicatesWithHalt : public StackObj { // Note that all other Regular Predicates have an UCT node. class AssertionPredicateWithHalt : public StackObj { static bool has_assertion_predicate_opaque(const Node* predicate_proj); - static bool has_halt(const Node* success_proj); public: static bool is_predicate(const Node* maybe_success_proj); + static bool has_halt(const Node* success_proj); +}; + +// Utility class representing a Regular Predicate which is either a Runtime Predicate or an Assertion Predicate. +class RegularPredicate : public StackObj { + public: + static bool may_be_predicate_if(const Node* node); }; // Class to represent a single Regular Predicate with an UCT. This could either be: @@ -239,15 +294,15 @@ class AssertionPredicateWithHalt : public StackObj { // Note that all other Regular Predicates have a Halt node. class RegularPredicateWithUCT : public StackObj { static Deoptimization::DeoptReason uncommon_trap_reason(IfProjNode* if_proj); - static bool may_be_predicate_if(Node* node); public: static bool is_predicate(Node* maybe_success_proj); - static bool is_predicate(Node* node, Deoptimization::DeoptReason deopt_reason); + static bool is_predicate(const Node* node, Deoptimization::DeoptReason deopt_reason); + static bool has_valid_uncommon_trap(const Node* success_proj); }; // Class to represent a Parse Predicate. -class ParsePredicate : public StackObj { +class ParsePredicate : public Predicate { ParsePredicateSuccessProj* _success_proj; ParsePredicateNode* _parse_predicate_node; Node* _entry; @@ -267,7 +322,7 @@ class ParsePredicate : public StackObj { // Returns the control input node into this Parse Predicate if it is valid. Otherwise, it returns the passed node // into the constructor of this class. - Node* entry() const { + Node* entry() const override { return _entry; } @@ -277,23 +332,104 @@ class ParsePredicate : public StackObj { return _parse_predicate_node != nullptr; } - ParsePredicateNode* node() const { + ParsePredicateNode* head() const override { assert(is_valid(), "must be valid"); return _parse_predicate_node; } - ParsePredicateSuccessProj* success_proj() const { + ParsePredicateSuccessProj* tail() const override { assert(is_valid(), "must be valid"); return _success_proj; } +}; + +// Class to represent a Runtime Predicate which always has an associated UCT on the failing path. +class RuntimePredicate : public Predicate { + IfProjNode* _success_proj; + IfNode* _if_node; + + public: + explicit RuntimePredicate(IfProjNode* success_proj) + : _success_proj(success_proj), + _if_node(success_proj->in(0)->as_If()) { + assert(is_predicate(success_proj), "must be valid"); + } + NONCOPYABLE(RuntimePredicate); + private: static bool is_predicate(Node* maybe_success_proj); + + public: + Node* entry() const override { + return _if_node->in(0); + } + + IfNode* head() const override { + return _if_node; + } + + IfProjNode* tail() const override { + return _success_proj; + } + + static bool is_predicate(Node* node, Deoptimization::DeoptReason deopt_reason); +}; + +// Class to represent a Template Assertion Predicate. +class TemplateAssertionPredicate : public Predicate { + IfTrueNode* _success_proj; + IfNode* _if_node; + + public: + explicit TemplateAssertionPredicate(IfTrueNode* success_proj) + : _success_proj(success_proj), + _if_node(success_proj->in(0)->as_If()) { + assert(is_predicate(success_proj), "must be valid"); + } + + Node* entry() const override { + return _if_node->in(0); + } + + IfNode* head() const override { + return _if_node; + } + + IfTrueNode* tail() const override { + return _success_proj; + } + + void rewire_loop_data_dependencies(IfTrueNode* target_predicate, const NodeInLoopBody& data_in_loop_body, + PhaseIdealLoop* phase) const; + static bool is_predicate(Node* node); }; -// Utility class for queries on Runtime Predicates. -class RuntimePredicate : public StackObj { +// Class to represent an Initialized Assertion Predicate which always has a halt node on the failing path. +// This predicate should never fail at runtime by design. +class InitializedAssertionPredicate : public Predicate { + IfTrueNode* _success_proj; + IfNode* _if_node; + public: - static bool is_success_proj(Node* node, Deoptimization::DeoptReason deopt_reason); + explicit InitializedAssertionPredicate(IfTrueNode* success_proj) + : _success_proj(success_proj), + _if_node(success_proj->in(0)->as_If()) { + assert(is_predicate(success_proj), "must be valid"); + } + + Node* entry() const override { + return _if_node->in(0); + } + + IfNode* head() const override { + return _if_node; + } + + IfTrueNode* tail() const override { + return _success_proj; + } + + static bool is_predicate(Node* node); }; // Interface to transform OpaqueLoopInit and OpaqueLoopStride nodes of a Template Assertion Expression. @@ -303,21 +439,23 @@ class TransformStrategyForOpaqueLoopNodes : public StackObj { virtual Node* transform_opaque_stride(OpaqueLoopStrideNode* opaque_stride) const = 0; }; -// A Template Assertion Predicate represents the Opaque4Node for the initial value or the last value of a -// Template Assertion Predicate and all the nodes up to and including the OpaqueLoop* nodes. +// A Template Assertion Predicate represents the OpaqueTemplateAssertionPredicateNode for the initial value or the last +// value of a Template Assertion Predicate and all the nodes up to and including the OpaqueLoop* nodes. class TemplateAssertionExpression : public StackObj { - Opaque4Node* _opaque4_node; + OpaqueTemplateAssertionPredicateNode* _opaque_node; public: - explicit TemplateAssertionExpression(Opaque4Node* opaque4_node) : _opaque4_node(opaque4_node) {} + explicit TemplateAssertionExpression(OpaqueTemplateAssertionPredicateNode* opaque_node) : _opaque_node(opaque_node) {} private: - Opaque4Node* clone(const TransformStrategyForOpaqueLoopNodes& transform_strategy, Node* new_ctrl, PhaseIdealLoop* phase); + OpaqueTemplateAssertionPredicateNode* clone(const TransformStrategyForOpaqueLoopNodes& transform_strategy, + Node* new_ctrl, PhaseIdealLoop* phase); public: - Opaque4Node* clone(Node* new_ctrl, PhaseIdealLoop* phase); - Opaque4Node* clone_and_replace_init(Node* new_init, Node* new_ctrl,PhaseIdealLoop* phase); - Opaque4Node* clone_and_replace_init_and_stride(Node* new_init, Node* new_stride, Node* new_ctrl, PhaseIdealLoop* phase); + OpaqueTemplateAssertionPredicateNode* clone(Node* new_ctrl, PhaseIdealLoop* phase); + OpaqueTemplateAssertionPredicateNode* clone_and_replace_init(Node* new_init, Node* new_ctrl, PhaseIdealLoop* phase); + OpaqueTemplateAssertionPredicateNode* clone_and_replace_init_and_stride(Node* new_control, Node* new_init, + Node* new_stride, PhaseIdealLoop* phase); }; // Class to represent a node being part of a Template Assertion Expression. Note that this is not an IR node. @@ -394,45 +532,296 @@ class TemplateAssertionExpressionNode : public StackObj { } }; -// This class creates a new Initialized Assertion Predicate. -class InitializedAssertionPredicate : public StackObj { - IfNode* const _template_assertion_predicate; - Node* const _new_init; - Node* const _new_stride; +// This class is used to create the actual If node with a success path and a fail path with a Halt node. +class AssertionPredicateIfCreator : public StackObj { PhaseIdealLoop* const _phase; public: - InitializedAssertionPredicate(IfNode* template_assertion_predicate, Node* new_init, Node* new_stride, - PhaseIdealLoop* phase); - NONCOPYABLE(InitializedAssertionPredicate); - - IfTrueNode* create(Node* control); + explicit AssertionPredicateIfCreator(PhaseIdealLoop* const phase) : _phase(phase) {} + NONCOPYABLE(AssertionPredicateIfCreator); + IfTrueNode* create_for_initialized(Node* new_control, int if_opcode, Node* assertion_expression + NOT_PRODUCT(COMMA const AssertionPredicateType assertion_predicate_type)); + IfTrueNode* create_for_template(Node* new_control, int if_opcode, Node* assertion_expression + NOT_PRODUCT(COMMA const AssertionPredicateType assertion_predicate_type)); private: - OpaqueInitializedAssertionPredicateNode* create_assertion_expression(Node* control); - IfNode* create_if_node(Node* control, OpaqueInitializedAssertionPredicateNode* assertion_expression, IdealLoopTree* loop); - void create_fail_path(IfNode* if_node, IdealLoopTree* loop); - void create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop); + IfTrueNode* create(Node* new_control, int if_opcode, Node* assertion_expression, const char* halt_message + NOT_PRODUCT(COMMA const AssertionPredicateType assertion_predicate_type)); + IfNode* create_if_node(Node* new_control, int if_opcode, Node* assertion_expression, IdealLoopTree* loop + NOT_PRODUCT(COMMA const AssertionPredicateType assertion_predicate_type)); IfTrueNode* create_success_path(IfNode* if_node, IdealLoopTree* loop); + void create_fail_path(IfNode* if_node, IdealLoopTree* loop, const char* halt_message); + void create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop, const char* halt_message); +}; + +// This class is used to create a Template Assertion Predicate either with an UCT or a Halt Node from scratch. +class TemplateAssertionPredicateCreator : public StackObj { + CountedLoopNode* const _loop_head; + const int _scale; + Node* const _offset; + Node* const _range; + PhaseIdealLoop* const _phase; + + OpaqueLoopInitNode* create_opaque_init(Node* new_control); + OpaqueTemplateAssertionPredicateNode* create_for_init_value(Node* new_control, OpaqueLoopInitNode* opaque_init, + bool& does_overflow) const; + OpaqueTemplateAssertionPredicateNode* create_for_last_value(Node* new_control, OpaqueLoopInitNode* opaque_init, + bool& does_overflow) const; + Node* create_last_value(Node* new_control, OpaqueLoopInitNode* opaque_init) const; + IfTrueNode* create_if_node_with_uncommon_trap(OpaqueTemplateAssertionPredicateNode* template_assertion_predicate_expression, + ParsePredicateSuccessProj* parse_predicate_success_proj, + Deoptimization::DeoptReason deopt_reason, int if_opcode, + bool does_overflow + NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)); + IfTrueNode* create_if_node_with_halt(Node* new_control, + OpaqueTemplateAssertionPredicateNode* template_assertion_predicate_expression, + bool does_overflow + NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)); + + public: + TemplateAssertionPredicateCreator(CountedLoopNode* loop_head, int scale, Node* offset, Node* range, + PhaseIdealLoop* phase) + : _loop_head(loop_head), + _scale(scale), + _offset(offset), + _range(range), + _phase(phase) {} + NONCOPYABLE(TemplateAssertionPredicateCreator); + + IfTrueNode* create_with_uncommon_trap(Node* new_control, ParsePredicateSuccessProj* parse_predicate_success_proj, + Deoptimization::DeoptReason deopt_reason, int if_opcode); + IfTrueNode* create_with_halt(Node* new_control); +}; + +// This class creates a new Initialized Assertion Predicate either from a template or from scratch. +class InitializedAssertionPredicateCreator : public StackObj { + PhaseIdealLoop* const _phase; + + public: + explicit InitializedAssertionPredicateCreator(PhaseIdealLoop* phase); + NONCOPYABLE(InitializedAssertionPredicateCreator); + + IfTrueNode* create_from_template(IfNode* template_assertion_predicate, Node* new_control, Node* new_init, + Node* new_stride); + IfTrueNode* create(Node* operand, Node* new_control, jint stride, int scale, Node* offset, Node* range + NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)); + + private: + OpaqueInitializedAssertionPredicateNode* create_assertion_expression_from_template(IfNode* template_assertion_predicate, + Node* new_control, Node* new_init, + Node* new_stride); + IfTrueNode* create_control_nodes(Node* new_control, int if_opcode, + OpaqueInitializedAssertionPredicateNode* assertion_expression + NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)); +}; + +// This class iterates through all predicates of a Regular Predicate Block and applies the given visitor to each. +class RegularPredicateBlockIterator : public StackObj { + Node* const _start_node; + const Deoptimization::DeoptReason _deopt_reason; + + public: + RegularPredicateBlockIterator(Node* start_node, Deoptimization::DeoptReason deopt_reason) + : _start_node(start_node), + _deopt_reason(deopt_reason) {} + NONCOPYABLE(RegularPredicateBlockIterator); + + // Skip all predicates by just following the inputs. We do not call any user provided visitor. + Node* skip_all() const { + PredicateVisitor do_nothing; // No real visits, just do nothing. + return for_each(do_nothing); + } + + // Walk over all predicates of this block (if any) and apply the given 'predicate_visitor' to each predicate. + // Returns the entry to the earliest predicate. + Node* for_each(PredicateVisitor& predicate_visitor) const { + Node* current = _start_node; + while (predicate_visitor.should_continue()) { + if (TemplateAssertionPredicate::is_predicate(current)) { + TemplateAssertionPredicate template_assertion_predicate(current->as_IfTrue()); + predicate_visitor.visit(template_assertion_predicate); + current = template_assertion_predicate.entry(); + } else if (RuntimePredicate::is_predicate(current, _deopt_reason)) { + RuntimePredicate runtime_predicate(current->as_IfProj()); + predicate_visitor.visit(runtime_predicate); + current = runtime_predicate.entry(); + } else if (InitializedAssertionPredicate::is_predicate(current)) { + InitializedAssertionPredicate initialized_assertion_predicate(current->as_IfTrue()); + predicate_visitor.visit(initialized_assertion_predicate); + current = initialized_assertion_predicate.entry(); + } else { + // Either a Parse Predicate or not a Regular Predicate. In both cases, the node does not belong to this block. + break; + } + } + return current; + } +}; + +// This class iterates through all predicates of a Predicate Block and applies the given visitor to each. +class PredicateBlockIterator : public StackObj { + Node* const _start_node; + const ParsePredicate _parse_predicate; // Could be missing. + const RegularPredicateBlockIterator _regular_predicate_block_iterator; + + public: + PredicateBlockIterator(Node* start_node, Deoptimization::DeoptReason deopt_reason) + : _start_node(start_node), + _parse_predicate(start_node, deopt_reason), + _regular_predicate_block_iterator(_parse_predicate.entry(), deopt_reason) {} + + // Walk over all predicates of this block (if any) and apply the given 'predicate_visitor' to each predicate. + // Returns the entry to the earliest predicate. + Node* for_each(PredicateVisitor& predicate_visitor) const { + if (!predicate_visitor.should_continue()) { + return _start_node; + } + if (_parse_predicate.is_valid()) { + predicate_visitor.visit(_parse_predicate); + } + return _regular_predicate_block_iterator.for_each(predicate_visitor); + } +}; + +// Class to walk over all predicates starting at a node, which usually is the loop entry node, and following the inputs. +// At each predicate, a PredicateVisitor is applied which the user can implement freely. +class PredicateIterator : public StackObj { + Node* _start_node; + + public: + explicit PredicateIterator(Node* start_node) + : _start_node(start_node) {} + NONCOPYABLE(PredicateIterator); + + // Apply the 'predicate_visitor' for each predicate found in the predicate chain started at the provided node. + // Returns the entry to the earliest predicate. + Node* for_each(PredicateVisitor& predicate_visitor) const { + Node* current = _start_node; + PredicateBlockIterator loop_limit_check_predicate_iterator(current, Deoptimization::Reason_loop_limit_check); + current = loop_limit_check_predicate_iterator.for_each(predicate_visitor); + if (UseLoopPredicate) { + if (UseProfiledLoopPredicate) { + PredicateBlockIterator profiled_loop_predicate_iterator(current, Deoptimization::Reason_profile_predicate); + current = profiled_loop_predicate_iterator.for_each(predicate_visitor); + } + PredicateBlockIterator loop_predicate_iterator(current, Deoptimization::Reason_predicate); + current = loop_predicate_iterator.for_each(predicate_visitor); + } + return current; + } +}; + +// Unified PredicateVisitor which only provides a single visit method for a generic Predicate. This visitor can be used +// when it does not matter what kind of predicate is visited. Note that we override all normal visit methods from +// PredicateVisitor by calling the unified method. These visit methods are marked final such that they cannot be +// overridden by implementors of this class. +class UnifiedPredicateVisitor : public PredicateVisitor { + public: + virtual void visit(const TemplateAssertionPredicate& template_assertion_predicate) override final { + visit_predicate(template_assertion_predicate); + } + + virtual void visit(const ParsePredicate& parse_predicate) override final { + visit_predicate(parse_predicate); + } + + virtual void visit(const RuntimePredicate& runtime_predicate) override final { + visit_predicate(runtime_predicate); + } + + virtual void visit(const InitializedAssertionPredicate& initialized_assertion_predicate) override final { + visit_predicate(initialized_assertion_predicate); + } + + virtual void visit_predicate(const Predicate& predicate) = 0; +}; + +// A block of Regular Predicates inside a Predicate Block without its Parse Predicate. +class RegularPredicateBlock : public StackObj { + const Deoptimization::DeoptReason _deopt_reason; + Node* const _entry; + + public: + RegularPredicateBlock(Node* tail, Deoptimization::DeoptReason deopt_reason) + : _deopt_reason(deopt_reason), + _entry(skip_all(tail)) { + DEBUG_ONLY(verify_block(tail);) + } + NONCOPYABLE(RegularPredicateBlock); + + private: + // Walk over all Regular Predicates of this block (if any) and return the first node not belonging to the block + // anymore (i.e. entry to the first Regular Predicate in this block if any or `tail` otherwise). + Node* skip_all(Node* tail) const { + RegularPredicateBlockIterator iterator(tail, _deopt_reason); + return iterator.skip_all(); + } + + DEBUG_ONLY(void verify_block(Node* tail);) + + public: + Node* entry() const { + return _entry; + } }; +#ifndef PRODUCT +// Visitor class to print all the visited predicates. Used by the Predicates class which does the printing starting +// at the loop node and then following the inputs to the earliest predicate. +class PredicatePrinter : public PredicateVisitor { + const char* _prefix; // Prefix added to each dumped string. + + public: + explicit PredicatePrinter(const char* prefix) : _prefix(prefix) {} + NONCOPYABLE(PredicatePrinter); + + void visit(const ParsePredicate& parse_predicate) override { + print_predicate_node("Parse Predicate", parse_predicate); + } + + void visit(const RuntimePredicate& runtime_predicate) override { + print_predicate_node("Runtime Predicate", runtime_predicate); + } + + void visit(const TemplateAssertionPredicate& template_assertion_predicate) override { + print_predicate_node("Template Assertion Predicate", template_assertion_predicate); + } + + void visit(const InitializedAssertionPredicate& initialized_assertion_predicate) override { + print_predicate_node("Initialized Assertion Predicate", initialized_assertion_predicate); + } + + private: + void print_predicate_node(const char* predicate_name, const Predicate& predicate) const { + tty->print_cr("%s- %s: %d %s", _prefix, predicate_name, predicate.head()->_idx, predicate.head()->Name()); + } +}; +#endif // NOT PRODUCT // This class represents a Predicate Block (i.e. either a Loop Predicate Block, a Profiled Loop Predicate Block, // or a Loop Limit Check Predicate Block). It contains zero or more Regular Predicates followed by a Parse Predicate // which, however, does not need to exist (we could already have decided to remove Parse Predicates for this loop). class PredicateBlock : public StackObj { - ParsePredicate _parse_predicate; // Could be missing. - Node* _entry; - - static Node* skip_regular_predicates(Node* regular_predicate_proj, Deoptimization::DeoptReason deopt_reason); - DEBUG_ONLY(void verify_block();) + const ParsePredicate _parse_predicate; // Could be missing. + const RegularPredicateBlock _regular_predicate_block; + Node* const _entry; +#ifndef PRODUCT + // Used for dumping. + Node* const _tail; + const Deoptimization::DeoptReason _deopt_reason; +#endif // NOT PRODUCT public: - PredicateBlock(Node* predicate_proj, Deoptimization::DeoptReason deopt_reason) - : _parse_predicate(predicate_proj, deopt_reason), - _entry(skip_regular_predicates(_parse_predicate.entry(), deopt_reason)) { - DEBUG_ONLY(verify_block();) - } + PredicateBlock(Node* tail, Deoptimization::DeoptReason deopt_reason) + : _parse_predicate(tail, deopt_reason), + _regular_predicate_block(_parse_predicate.entry(), deopt_reason), + _entry(_regular_predicate_block.entry()) +#ifndef PRODUCT + , _tail(tail) + , _deopt_reason(deopt_reason) +#endif // NOT PRODUCT + {} + NONCOPYABLE(PredicateBlock); // Returns the control input node into this Regular Predicate block. This is either: // - The control input to the first If node in the block representing a Runtime Predicate if there is at least one @@ -453,11 +842,11 @@ class PredicateBlock : public StackObj { } ParsePredicateNode* parse_predicate() const { - return _parse_predicate.node(); + return _parse_predicate.head(); } ParsePredicateSuccessProj* parse_predicate_success_proj() const { - return _parse_predicate.success_proj(); + return _parse_predicate.tail(); } bool has_runtime_predicates() const { @@ -471,25 +860,31 @@ class PredicateBlock : public StackObj { Node* skip_parse_predicate() const { return _parse_predicate.entry(); } + +#ifndef PRODUCT + void dump() const; + void dump(const char* prefix) const; +#endif // NOT PRODUCT }; // This class takes a loop entry node and finds all the available predicates for the loop. class Predicates : public StackObj { - Node* _loop_entry; - PredicateBlock _loop_limit_check_predicate_block; - PredicateBlock _profiled_loop_predicate_block; - PredicateBlock _loop_predicate_block; - Node* _entry; + Node* const _tail; + const PredicateBlock _loop_limit_check_predicate_block; + const PredicateBlock _profiled_loop_predicate_block; + const PredicateBlock _loop_predicate_block; + Node* const _entry; public: - Predicates(Node* loop_entry) - : _loop_entry(loop_entry), + explicit Predicates(Node* loop_entry) + : _tail(loop_entry), _loop_limit_check_predicate_block(loop_entry, Deoptimization::Reason_loop_limit_check), _profiled_loop_predicate_block(_loop_limit_check_predicate_block.entry(), Deoptimization::Reason_profile_predicate), _loop_predicate_block(_profiled_loop_predicate_block.entry(), Deoptimization::Reason_predicate), _entry(_loop_predicate_block.entry()) {} + NONCOPYABLE(Predicates); // Returns the control input the first predicate if there are any predicates. If there are no predicates, the same // node initially passed to the constructor is returned. @@ -510,35 +905,83 @@ class Predicates : public StackObj { } bool has_any() const { - return _entry != _loop_entry; + return _entry != _tail; } + +#ifndef PRODUCT + /* + * Debug printing functions. + */ + void dump() const; + static void dump_at(Node* node); + static void dump_for_loop(LoopNode* loop_node); +#endif // NOT PRODUCT }; -// This class iterates over the Parse Predicates of a loop. -class ParsePredicateIterator : public StackObj { - GrowableArray _parse_predicates; - int _current_index; +// This class checks whether a node is in the original loop body and not the cloned one. +class NodeInOriginalLoopBody : public NodeInLoopBody { + const uint _first_node_index_in_cloned_loop_body; + const Node_List& _old_new; public: - ParsePredicateIterator(const Predicates& predicates); - - bool has_next() const { - return _current_index < _parse_predicates.length(); + NodeInOriginalLoopBody(const uint first_node_index_in_cloned_loop_body, const Node_List& old_new) + : _first_node_index_in_cloned_loop_body(first_node_index_in_cloned_loop_body), + _old_new(old_new) {} + NONCOPYABLE(NodeInOriginalLoopBody); + + // Check if 'node' is not a cloned node (i.e. "< _first_node_index_in_cloned_loop_body") and if we've created a + // clone from 'node' (i.e. _old_new entry is non-null). Then we know that 'node' belongs to the original loop body. + bool check(Node* node) const override { + if (node->_idx < _first_node_index_in_cloned_loop_body) { + Node* cloned_node = _old_new[node->_idx]; + return cloned_node != nullptr && cloned_node->_idx >= _first_node_index_in_cloned_loop_body; + } else { + return false; + } } - - ParsePredicateNode* next(); }; -// Special predicate iterator that can be used to walk through predicate entries, regardless of whether the predicate -// belongs to the same loop or not (i.e. leftovers from already folded nodes). The iterator returns the next entry -// to a predicate. -class PredicateEntryIterator : public StackObj { - Node* _current; +// Visitor to create Initialized Assertion Predicates at a target loop from Template Assertion Predicates from a source +// loop. This visitor can be used in combination with a PredicateIterator. +class CreateAssertionPredicatesVisitor : public PredicateVisitor { + Node* const _init; + Node* const _stride; + Node* const _old_target_loop_entry; + Node* _new_control; + PhaseIdealLoop* const _phase; + bool _has_hoisted_check_parse_predicates; + const NodeInLoopBody& _node_in_loop_body; public: - explicit PredicateEntryIterator(Node* start) : _current(start) {}; + CreateAssertionPredicatesVisitor(Node* init, Node* stride, Node* new_control, PhaseIdealLoop* phase, + const NodeInLoopBody& node_in_loop_body) + : _init(init), + _stride(stride), + _old_target_loop_entry(new_control), + _new_control(new_control), + _phase(phase), + _has_hoisted_check_parse_predicates(false), + _node_in_loop_body(node_in_loop_body) {} + NONCOPYABLE(CreateAssertionPredicatesVisitor); + + using PredicateVisitor::visit; + + void visit(const ParsePredicate& parse_predicate) override; + void visit(const TemplateAssertionPredicate& template_assertion_predicate) override; + + // Did we create any new Initialized Assertion Predicates? + bool has_created_predicates() const { + return _new_control != _old_target_loop_entry; + } - bool has_next() const; - Node* next_entry(); + // Return the last created node by this visitor or the originally provided 'new_control' to the visitor if there was + // no new node created (i.e. no Template Assertion Predicates found). + IfTrueNode* last_created_success_proj() const { + assert(has_created_predicates(), "should only be queried if new nodes have been created"); + assert(_new_control->unique_ctrl_out_or_null() == nullptr, "no control outputs, yet"); + assert(_new_control->is_IfTrue(), "Assertion Predicates only have IfTrue on success proj"); + return _new_control->as_IfTrue(); + } }; + #endif // SHARE_OPTO_PREDICATES_HPP diff --git a/src/hotspot/share/opto/reg_split.cpp b/src/hotspot/share/opto/reg_split.cpp index 9f89c683b34b5..6d948aff011cf 100644 --- a/src/hotspot/share/opto/reg_split.cpp +++ b/src/hotspot/share/opto/reg_split.cpp @@ -306,8 +306,8 @@ static Node* clone_node(Node* def, Block *b, Compile* C) { C->record_failure(C2Compiler::retry_no_subsuming_loads()); } else { // Bailout without retry - assert(false, "RA Split failed: attempt to clone node with anti_dependence"); - C->record_method_not_compilable("RA Split failed: attempt to clone node with anti_dependence"); + assert(C->failure_is_artificial(), "RA Split failed: attempt to clone node with anti_dependence"); + C->record_method_not_compilable("RA Split failed: attempt to clone node with anti_dependence" DEBUG_ONLY(COMMA true)); } return nullptr; } diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index 1eff44ab7834f..fea8c9f6ffba5 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -322,7 +322,8 @@ bool PhaseIdealLoop::clone_cmp_down(Node* n, const Node* blk1, const Node* blk2) assert( bol->is_Bool(), "" ); if (bol->outcnt() == 1) { Node* use = bol->unique_out(); - if (use->is_Opaque4() || use->is_OpaqueInitializedAssertionPredicate()) { + if (use->is_OpaqueNotNull() || use->is_OpaqueTemplateAssertionPredicate() || + use->is_OpaqueInitializedAssertionPredicate()) { if (use->outcnt() == 1) { Node* iff = use->unique_out(); assert(iff->is_If(), "unexpected node type"); @@ -351,8 +352,9 @@ bool PhaseIdealLoop::clone_cmp_down(Node* n, const Node* blk1, const Node* blk2) #endif for (DUIterator j = bol->outs(); bol->has_out(j); j++) { Node* u = bol->out(j); - // Uses are either IfNodes, CMoves, Opaque4, or OpaqueInitializedAssertionPredicates - if (u->is_Opaque4() || u->is_OpaqueInitializedAssertionPredicate()) { + // Uses are either IfNodes, CMoves, OpaqueNotNull, or Opaque*AssertionPredicate + if (u->is_OpaqueNotNull() || u->is_OpaqueTemplateAssertionPredicate() || + u->is_OpaqueInitializedAssertionPredicate()) { assert(u->in(1) == bol, "bad input"); for (DUIterator_Last kmin, k = u->last_outs(kmin); k >= kmin; --k) { Node* iff = u->last_out(k); @@ -421,11 +423,12 @@ void PhaseIdealLoop::clone_template_assertion_expression_down(Node* node) { TemplateAssertionExpressionNode template_assertion_expression_node(node); auto clone_expression = [&](IfNode* template_assertion_predicate) { - Opaque4Node* opaque4_node = template_assertion_predicate->in(1)->as_Opaque4(); - TemplateAssertionExpression template_assertion_expression(opaque4_node); + OpaqueTemplateAssertionPredicateNode* opaque_node = + template_assertion_predicate->in(1)->as_OpaqueTemplateAssertionPredicate(); + TemplateAssertionExpression template_assertion_expression(opaque_node); Node* new_ctrl = template_assertion_predicate->in(0); - Opaque4Node* cloned_opaque4_node = template_assertion_expression.clone(new_ctrl, this); - igvn().replace_input_of(template_assertion_predicate, 1, cloned_opaque4_node); + OpaqueTemplateAssertionPredicateNode* cloned_opaque_node = template_assertion_expression.clone(new_ctrl, this); + igvn().replace_input_of(template_assertion_predicate, 1, cloned_opaque_node); }; template_assertion_expression_node.for_each_template_assertion_predicate(clone_expression); } diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index bb5fed78b0274..20c8dfbff1776 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -657,9 +657,6 @@ void VLoopMemorySlices::get_slice_in_reverse_order(PhiNode* head, MemNode* tail, // or need to run igvn.optimize() again before SLP } else if (out->is_memory_phi() && !_vloop.in_bb(out)) { // Ditto. Not sure what else to check further. - } else if (out->Opcode() == Op_StoreCM && out->in(MemNode::OopStore) == n) { - // StoreCM has an input edge used as a precedence edge. - // Maybe an issue when oop stores are vectorized. } else { assert(out == prev || prev == nullptr, "no branches off of store slice"); } diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index b0a0c97cb1676..6c2d3a3be35c3 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -228,8 +228,8 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i return shift_count; } else { // Replicate the scalar same_input to every vector element. - const Type* element_type = _vloop_analyzer.types().velt_type(p0); - if (index == 2 && VectorNode::is_scalar_rotate(p0) && element_type->isa_long()) { + BasicType element_type = _vloop_analyzer.types().velt_basic_type(p0); + if (index == 2 && VectorNode::is_scalar_rotate(p0) && element_type == T_LONG) { // Scalar rotate has int rotation value, but the scalar rotate expects longs. assert(same_input->bottom_type()->isa_int(), "scalar rotate expects int rotation"); VTransformNode* conv = new (_vtransform.arena()) VTransformConvI2LNode(_vtransform); diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 73f852c0f047d..70cd46c900dc2 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -679,7 +679,7 @@ void Type::Initialize_shared(Compile* current) { // get_zero_type() should not happen for T_CONFLICT _zero_type[T_CONFLICT]= nullptr; - TypeVect::VECTMASK = (TypeVect*)(new TypeVectMask(TypeInt::BOOL, MaxVectorSize))->hashcons(); + TypeVect::VECTMASK = (TypeVect*)(new TypeVectMask(T_BOOLEAN, MaxVectorSize))->hashcons(); mreg2type[Op_RegVectMask] = TypeVect::VECTMASK; if (Matcher::supports_scalable_vector()) { @@ -687,20 +687,20 @@ void Type::Initialize_shared(Compile* current) { } // Vector predefined types, it needs initialized _const_basic_type[]. - if (Matcher::vector_size_supported(T_BYTE,4)) { - TypeVect::VECTS = TypeVect::make(T_BYTE,4); + if (Matcher::vector_size_supported(T_BYTE, 4)) { + TypeVect::VECTS = TypeVect::make(T_BYTE, 4); } - if (Matcher::vector_size_supported(T_FLOAT,2)) { - TypeVect::VECTD = TypeVect::make(T_FLOAT,2); + if (Matcher::vector_size_supported(T_FLOAT, 2)) { + TypeVect::VECTD = TypeVect::make(T_FLOAT, 2); } - if (Matcher::vector_size_supported(T_FLOAT,4)) { - TypeVect::VECTX = TypeVect::make(T_FLOAT,4); + if (Matcher::vector_size_supported(T_FLOAT, 4)) { + TypeVect::VECTX = TypeVect::make(T_FLOAT, 4); } - if (Matcher::vector_size_supported(T_FLOAT,8)) { - TypeVect::VECTY = TypeVect::make(T_FLOAT,8); + if (Matcher::vector_size_supported(T_FLOAT, 8)) { + TypeVect::VECTY = TypeVect::make(T_FLOAT, 8); } - if (Matcher::vector_size_supported(T_FLOAT,16)) { - TypeVect::VECTZ = TypeVect::make(T_FLOAT,16); + if (Matcher::vector_size_supported(T_FLOAT, 16)) { + TypeVect::VECTZ = TypeVect::make(T_FLOAT, 16); } mreg2type[Op_VecA] = TypeVect::VECTA; @@ -2482,58 +2482,59 @@ bool TypeAry::ary_must_be_exact() const { //==============================TypeVect======================================= // Convenience common pre-built types. -const TypeVect *TypeVect::VECTA = nullptr; // vector length agnostic -const TypeVect *TypeVect::VECTS = nullptr; // 32-bit vectors -const TypeVect *TypeVect::VECTD = nullptr; // 64-bit vectors -const TypeVect *TypeVect::VECTX = nullptr; // 128-bit vectors -const TypeVect *TypeVect::VECTY = nullptr; // 256-bit vectors -const TypeVect *TypeVect::VECTZ = nullptr; // 512-bit vectors -const TypeVect *TypeVect::VECTMASK = nullptr; // predicate/mask vector +const TypeVect* TypeVect::VECTA = nullptr; // vector length agnostic +const TypeVect* TypeVect::VECTS = nullptr; // 32-bit vectors +const TypeVect* TypeVect::VECTD = nullptr; // 64-bit vectors +const TypeVect* TypeVect::VECTX = nullptr; // 128-bit vectors +const TypeVect* TypeVect::VECTY = nullptr; // 256-bit vectors +const TypeVect* TypeVect::VECTZ = nullptr; // 512-bit vectors +const TypeVect* TypeVect::VECTMASK = nullptr; // predicate/mask vector //------------------------------make------------------------------------------- -const TypeVect* TypeVect::make(const Type *elem, uint length, bool is_mask) { +const TypeVect* TypeVect::make(BasicType elem_bt, uint length, bool is_mask) { if (is_mask) { - return makemask(elem, length); + return makemask(elem_bt, length); } - BasicType elem_bt = elem->array_element_basic_type(); assert(is_java_primitive(elem_bt), "only primitive types in vector"); assert(Matcher::vector_size_supported(elem_bt, length), "length in range"); int size = length * type2aelembytes(elem_bt); switch (Matcher::vector_ideal_reg(size)) { case Op_VecA: - return (TypeVect*)(new TypeVectA(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectA(elem_bt, length))->hashcons(); case Op_VecS: - return (TypeVect*)(new TypeVectS(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectS(elem_bt, length))->hashcons(); case Op_RegL: case Op_VecD: case Op_RegD: - return (TypeVect*)(new TypeVectD(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectD(elem_bt, length))->hashcons(); case Op_VecX: - return (TypeVect*)(new TypeVectX(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectX(elem_bt, length))->hashcons(); case Op_VecY: - return (TypeVect*)(new TypeVectY(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectY(elem_bt, length))->hashcons(); case Op_VecZ: - return (TypeVect*)(new TypeVectZ(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectZ(elem_bt, length))->hashcons(); } ShouldNotReachHere(); return nullptr; } -const TypeVect *TypeVect::makemask(const Type* elem, uint length) { - BasicType elem_bt = elem->array_element_basic_type(); +const TypeVect* TypeVect::makemask(BasicType elem_bt, uint length) { if (Matcher::has_predicated_vectors() && Matcher::match_rule_supported_vector_masked(Op_VectorLoadMask, length, elem_bt)) { - return TypeVectMask::make(elem, length); + return TypeVectMask::make(elem_bt, length); } else { - return make(elem, length); + return make(elem_bt, length); } } //------------------------------meet------------------------------------------- -// Compute the MEET of two types. It returns a new Type object. -const Type *TypeVect::xmeet( const Type *t ) const { +// Compute the MEET of two types. Since each TypeVect is the only instance of +// its species, meeting often returns itself +const Type* TypeVect::xmeet(const Type* t) const { // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? + if (this == t) { + return this; + } // Current "this->_base" is Vector switch (t->base()) { // switch on original type @@ -2543,13 +2544,7 @@ const Type *TypeVect::xmeet( const Type *t ) const { default: // All else is a mistake typerr(t); - case VectorMask: { - const TypeVectMask* v = t->is_vectmask(); - assert( base() == v->base(), ""); - assert(length() == v->length(), ""); - assert(element_basic_type() == v->element_basic_type(), ""); - return TypeVect::makemask(_elem->xmeet(v->_elem), _length); - } + case VectorMask: case VectorA: case VectorS: case VectorD: @@ -2557,10 +2552,10 @@ const Type *TypeVect::xmeet( const Type *t ) const { case VectorY: case VectorZ: { // Meeting 2 vectors? const TypeVect* v = t->is_vect(); - assert( base() == v->base(), ""); + assert(base() == v->base(), ""); assert(length() == v->length(), ""); assert(element_basic_type() == v->element_basic_type(), ""); - return TypeVect::make(_elem->xmeet(v->_elem), _length); + return this; } case Top: break; @@ -2569,26 +2564,26 @@ const Type *TypeVect::xmeet( const Type *t ) const { } //------------------------------xdual------------------------------------------ -// Dual: compute field-by-field dual -const Type *TypeVect::xdual() const { - return new TypeVect(base(), _elem->dual(), _length); +// Since each TypeVect is the only instance of its species, it is self-dual +const Type* TypeVect::xdual() const { + return this; } //------------------------------eq--------------------------------------------- // Structural equality check for Type representations -bool TypeVect::eq(const Type *t) const { - const TypeVect *v = t->is_vect(); - return (_elem == v->_elem) && (_length == v->_length); +bool TypeVect::eq(const Type* t) const { + const TypeVect* v = t->is_vect(); + return (element_basic_type() == v->element_basic_type()) && (length() == v->length()); } //------------------------------hash------------------------------------------- // Type-specific hashing function. uint TypeVect::hash(void) const { - return (uint)(uintptr_t)_elem + (uint)(uintptr_t)_length; + return (uint)base() + (uint)(uintptr_t)_elem_bt + (uint)(uintptr_t)_length; } //------------------------------singleton-------------------------------------- -// TRUE if Type is a singleton type, FALSE otherwise. Singletons are simple +// TRUE if Type is a singleton type, FALSE otherwise. Singletons are simple // constants (Ldi nodes). Vector is singleton if all elements are the same // constant value (when vector is created with Replicate code). bool TypeVect::singleton(void) const { @@ -2598,52 +2593,36 @@ bool TypeVect::singleton(void) const { } bool TypeVect::empty(void) const { - return _elem->empty(); + return false; } //------------------------------dump2------------------------------------------ #ifndef PRODUCT -void TypeVect::dump2(Dict &d, uint depth, outputStream *st) const { +void TypeVect::dump2(Dict& d, uint depth, outputStream* st) const { switch (base()) { case VectorA: - st->print("vectora["); break; + st->print("vectora"); break; case VectorS: - st->print("vectors["); break; + st->print("vectors"); break; case VectorD: - st->print("vectord["); break; + st->print("vectord"); break; case VectorX: - st->print("vectorx["); break; + st->print("vectorx"); break; case VectorY: - st->print("vectory["); break; + st->print("vectory"); break; case VectorZ: - st->print("vectorz["); break; + st->print("vectorz"); break; case VectorMask: - st->print("vectormask["); break; + st->print("vectormask"); break; default: ShouldNotReachHere(); } - st->print("%d]:{", _length); - _elem->dump2(d, depth, st); - st->print("}"); + st->print("<%c,%u>", type2char(element_basic_type()), length()); } #endif -bool TypeVectMask::eq(const Type *t) const { - const TypeVectMask *v = t->is_vectmask(); - return (element_type() == v->element_type()) && (length() == v->length()); -} - -const Type *TypeVectMask::xdual() const { - return new TypeVectMask(element_type()->dual(), length()); -} - -const TypeVectMask *TypeVectMask::make(const BasicType elem_bt, uint length) { - return make(get_const_basic_type(elem_bt), length); -} - -const TypeVectMask *TypeVectMask::make(const Type* elem, uint length) { - const TypeVectMask* mtype = Matcher::predicate_reg_type(elem, length); - return (TypeVectMask*) const_cast(mtype)->hashcons(); +const TypeVectMask* TypeVectMask::make(const BasicType elem_bt, uint length) { + return (TypeVectMask*) (new TypeVectMask(elem_bt, length))->hashcons(); } //============================================================================= @@ -3132,8 +3111,8 @@ const TypeRawPtr *TypeRawPtr::make( enum PTR ptr ) { return (TypeRawPtr*)(new TypeRawPtr(ptr,nullptr))->hashcons(); } -const TypeRawPtr *TypeRawPtr::make( address bits ) { - assert( bits, "Use TypePtr for null" ); +const TypeRawPtr *TypeRawPtr::make(address bits) { + assert(bits != nullptr, "Use TypePtr for null"); return (TypeRawPtr*)(new TypeRawPtr(Constant,bits))->hashcons(); } @@ -3222,15 +3201,21 @@ const TypePtr* TypeRawPtr::add_offset(intptr_t offset) const { case TypePtr::BotPTR: case TypePtr::NotNull: return this; - case TypePtr::Null: case TypePtr::Constant: { - address bits = _bits+offset; - if ( bits == 0 ) return TypePtr::NULL_PTR; - return make( bits ); + uintptr_t bits = (uintptr_t)_bits; + uintptr_t sum = bits + offset; + if (( offset < 0 ) + ? ( sum > bits ) // Underflow? + : ( sum < bits )) { // Overflow? + return BOTTOM; + } else if ( sum == 0 ) { + return TypePtr::NULL_PTR; + } else { + return make( (address)sum ); + } } default: ShouldNotReachHere(); } - return nullptr; // Lint noise } //------------------------------eq--------------------------------------------- diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 902155e975d16..f6b7efcae3bcc 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -784,94 +784,79 @@ class TypeAry : public Type { //------------------------------TypeVect--------------------------------------- // Class of Vector Types class TypeVect : public Type { - const Type* _elem; // Vector's element type - const uint _length; // Elements in vector (power of 2) + const BasicType _elem_bt; // Vector's element type + const uint _length; // Elements in vector (power of 2) protected: - TypeVect(TYPES t, const Type* elem, uint length) : Type(t), - _elem(elem), _length(length) {} + TypeVect(TYPES t, BasicType elem_bt, uint length) : Type(t), + _elem_bt(elem_bt), _length(length) {} public: - const Type* element_type() const { return _elem; } - BasicType element_basic_type() const { return _elem->array_element_basic_type(); } + BasicType element_basic_type() const { return _elem_bt; } uint length() const { return _length; } uint length_in_bytes() const { - return _length * type2aelembytes(element_basic_type()); + return _length * type2aelembytes(element_basic_type()); } - virtual bool eq(const Type *t) const; + virtual bool eq(const Type* t) const; virtual uint hash() const; // Type specific hashing virtual bool singleton(void) const; // TRUE if type is a singleton virtual bool empty(void) const; // TRUE if type is vacuous - static const TypeVect *make(const BasicType elem_bt, uint length, bool is_mask = false) { - // Use bottom primitive type. - return make(get_const_basic_type(elem_bt), length, is_mask); - } - // Used directly by Replicate nodes to construct singleton vector. - static const TypeVect *make(const Type* elem, uint length, bool is_mask = false); - - static const TypeVect *makemask(const BasicType elem_bt, uint length) { - // Use bottom primitive type. - return makemask(get_const_basic_type(elem_bt), length); - } - static const TypeVect *makemask(const Type* elem, uint length); - + static const TypeVect* make(const BasicType elem_bt, uint length, bool is_mask = false); + static const TypeVect* makemask(const BasicType elem_bt, uint length); - virtual const Type *xmeet( const Type *t) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const Type* xmeet( const Type *t) const; + virtual const Type* xdual() const; // Compute dual right now. - static const TypeVect *VECTA; - static const TypeVect *VECTS; - static const TypeVect *VECTD; - static const TypeVect *VECTX; - static const TypeVect *VECTY; - static const TypeVect *VECTZ; - static const TypeVect *VECTMASK; + static const TypeVect* VECTA; + static const TypeVect* VECTS; + static const TypeVect* VECTD; + static const TypeVect* VECTX; + static const TypeVect* VECTY; + static const TypeVect* VECTZ; + static const TypeVect* VECTMASK; #ifndef PRODUCT - virtual void dump2(Dict &d, uint, outputStream *st) const; // Specialized per-Type dumping + virtual void dump2(Dict& d, uint, outputStream* st) const; // Specialized per-Type dumping #endif }; class TypeVectA : public TypeVect { friend class TypeVect; - TypeVectA(const Type* elem, uint length) : TypeVect(VectorA, elem, length) {} + TypeVectA(BasicType elem_bt, uint length) : TypeVect(VectorA, elem_bt, length) {} }; class TypeVectS : public TypeVect { friend class TypeVect; - TypeVectS(const Type* elem, uint length) : TypeVect(VectorS, elem, length) {} + TypeVectS(BasicType elem_bt, uint length) : TypeVect(VectorS, elem_bt, length) {} }; class TypeVectD : public TypeVect { friend class TypeVect; - TypeVectD(const Type* elem, uint length) : TypeVect(VectorD, elem, length) {} + TypeVectD(BasicType elem_bt, uint length) : TypeVect(VectorD, elem_bt, length) {} }; class TypeVectX : public TypeVect { friend class TypeVect; - TypeVectX(const Type* elem, uint length) : TypeVect(VectorX, elem, length) {} + TypeVectX(BasicType elem_bt, uint length) : TypeVect(VectorX, elem_bt, length) {} }; class TypeVectY : public TypeVect { friend class TypeVect; - TypeVectY(const Type* elem, uint length) : TypeVect(VectorY, elem, length) {} + TypeVectY(BasicType elem_bt, uint length) : TypeVect(VectorY, elem_bt, length) {} }; class TypeVectZ : public TypeVect { friend class TypeVect; - TypeVectZ(const Type* elem, uint length) : TypeVect(VectorZ, elem, length) {} + TypeVectZ(BasicType elem_bt, uint length) : TypeVect(VectorZ, elem_bt, length) {} }; class TypeVectMask : public TypeVect { public: friend class TypeVect; - TypeVectMask(const Type* elem, uint length) : TypeVect(VectorMask, elem, length) {} - virtual bool eq(const Type *t) const; - virtual const Type *xdual() const; + TypeVectMask(BasicType elem_bt, uint length) : TypeVect(VectorMask, elem_bt, length) {} static const TypeVectMask* make(const BasicType elem_bt, uint length); - static const TypeVectMask* make(const Type* elem, uint length); }; // Set of implemented interfaces. Referenced from TypeOopPtr and TypeKlassPtr. diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index 3753619822938..3d20b22a175e9 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -365,9 +365,12 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { } BasicType elem_bt = elem_type->basic_type(); + bool has_scalar_op = VectorSupport::has_scalar_op(opr->get_con()); + bool is_unsigned = VectorSupport::is_unsigned_op(opr->get_con()); + int num_elem = vlen->get_con(); int opc = VectorSupport::vop2ideal(opr->get_con(), elem_bt); - int sopc = VectorNode::opcode(opc, elem_bt); + int sopc = has_scalar_op ? VectorNode::opcode(opc, elem_bt) : opc; if ((opc != Op_CallLeafVector) && (sopc == 0)) { log_if_needed(" ** operation not supported: opc=%s bt=%s", NodeClassNames[opc], type2name(elem_bt)); return false; // operation not supported @@ -468,11 +471,11 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { Node* operation = nullptr; if (opc == Op_CallLeafVector) { assert(UseVectorStubs, "sanity"); - operation = gen_call_to_svml(opr->get_con(), elem_bt, num_elem, opd1, opd2); + operation = gen_call_to_vector_math(opr->get_con(), elem_bt, num_elem, opd1, opd2); if (operation == nullptr) { - log_if_needed(" ** svml call failed for %s_%s_%d", - (elem_bt == T_FLOAT)?"float":"double", - VectorSupport::svmlname[opr->get_con() - VectorSupport::VECTOR_OP_SVML_START], + log_if_needed(" ** Vector math call failed for %s_%s_%d", + (elem_bt == T_FLOAT) ? "float" : "double", + VectorSupport::mathname[opr->get_con() - VectorSupport::VECTOR_OP_MATH_START], num_elem * type2aelembytes(elem_bt)); return false; } @@ -481,7 +484,7 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { switch (n) { case 1: case 2: { - operation = VectorNode::make(sopc, opd1, opd2, vt, is_vector_mask(vbox_klass), VectorNode::is_shift_opcode(opc)); + operation = VectorNode::make(sopc, opd1, opd2, vt, is_vector_mask(vbox_klass), VectorNode::is_shift_opcode(opc), is_unsigned); break; } case 3: { @@ -524,17 +527,16 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { Node* LibraryCallKit::partially_wrap_indexes(Node* index_vec, int num_elem, BasicType elem_bt) { assert(elem_bt == T_BYTE, "Shuffles use byte array based backing storage."); const TypeVect* vt = TypeVect::make(elem_bt, num_elem); - const Type* type_bt = Type::get_const_basic_type(elem_bt); Node* mod_mask = gvn().makecon(TypeInt::make(num_elem-1)); - Node* bcast_mod_mask = gvn().transform(VectorNode::scalar2vector(mod_mask, num_elem, type_bt)); + Node* bcast_mod_mask = gvn().transform(VectorNode::scalar2vector(mod_mask, num_elem, elem_bt)); BoolTest::mask pred = BoolTest::ugt; ConINode* pred_node = (ConINode*)gvn().makecon(TypeInt::make(pred)); Node* lane_cnt = gvn().makecon(TypeInt::make(num_elem)); - Node* bcast_lane_cnt = gvn().transform(VectorNode::scalar2vector(lane_cnt, num_elem, type_bt)); - const TypeVect* vmask_type = TypeVect::makemask(type_bt, num_elem); - Node* mask = gvn().transform(new VectorMaskCmpNode(pred, bcast_lane_cnt, index_vec, pred_node, vmask_type)); + Node* bcast_lane_cnt = gvn().transform(VectorNode::scalar2vector(lane_cnt, num_elem, elem_bt)); + const TypeVect* vmask_type = TypeVect::makemask(elem_bt, num_elem); + Node* mask = gvn().transform(new VectorMaskCmpNode(pred, bcast_lane_cnt, index_vec, pred_node, vmask_type)); // Make the indices greater than lane count as -ve values to match the java side implementation. index_vec = gvn().transform(VectorNode::make(Op_AndV, index_vec, bcast_mod_mask, vt)); @@ -600,8 +602,7 @@ bool LibraryCallKit::inline_vector_shuffle_iota() { return false; } - const Type * type_bt = Type::get_const_basic_type(elem_bt); - const TypeVect * vt = TypeVect::make(type_bt, num_elem); + const TypeVect* vt = TypeVect::make(elem_bt, num_elem); Node* res = gvn().transform(new VectorLoadConstNode(gvn().makecon(TypeInt::ZERO), vt)); @@ -609,7 +610,7 @@ bool LibraryCallKit::inline_vector_shuffle_iota() { Node* step = argument(5); if (step_multiply) { - Node* bcast_step = gvn().transform(VectorNode::scalar2vector(step, num_elem, type_bt)); + Node* bcast_step = gvn().transform(VectorNode::scalar2vector(step, num_elem, elem_bt)); res = gvn().transform(VectorNode::make(Op_MulVB, res, bcast_step, vt)); } else if (step_val->get_con() > 1) { Node* cnt = gvn().makecon(TypeInt::make(log2i_exact(step_val->get_con()))); @@ -618,12 +619,12 @@ bool LibraryCallKit::inline_vector_shuffle_iota() { } if (!start_val->is_con() || start_val->get_con() != 0) { - Node* bcast_start = gvn().transform(VectorNode::scalar2vector(start, num_elem, type_bt)); + Node* bcast_start = gvn().transform(VectorNode::scalar2vector(start, num_elem, elem_bt)); res = gvn().transform(VectorNode::make(Op_AddVB, res, bcast_start, vt)); } - Node * mod_val = gvn().makecon(TypeInt::make(num_elem-1)); - Node * bcast_mod = gvn().transform(VectorNode::scalar2vector(mod_val, num_elem, type_bt)); + Node* mod_val = gvn().makecon(TypeInt::make(num_elem-1)); + Node* bcast_mod = gvn().transform(VectorNode::scalar2vector(mod_val, num_elem, elem_bt)); if (do_wrap) { // Wrap the indices greater than lane count. @@ -802,9 +803,8 @@ bool LibraryCallKit::inline_vector_wrap_shuffle_indexes() { Node* shuffle_vec = unbox_vector(shuffle, shuffle_box_type, shuffle_bt, num_elem, true); const TypeVect* vt = TypeVect::make(shuffle_bt, num_elem); - const Type* shuffle_type_bt = Type::get_const_basic_type(shuffle_bt); - Node* mod_mask = gvn().makecon(TypeInt::make(num_elem-1)); - Node* bcast_mod_mask = gvn().transform(VectorNode::scalar2vector(mod_mask, num_elem, shuffle_type_bt)); + Node* mod_mask = gvn().makecon(TypeInt::make(num_elem - 1)); + Node* bcast_mod_mask = gvn().transform(VectorNode::scalar2vector(mod_mask, num_elem, shuffle_bt)); // Wrap the indices greater than lane count. Node* res = gvn().transform(VectorNode::make(Op_AndV, shuffle_vec, bcast_mod_mask, vt)); @@ -908,7 +908,7 @@ bool LibraryCallKit::inline_vector_frombits_coerced() { } default: fatal("%s", type2name(elem_bt)); } - broadcast = VectorNode::scalar2vector(elem, num_elem, Type::get_const_basic_type(elem_bt), is_mask); + broadcast = VectorNode::scalar2vector(elem, num_elem, elem_bt, is_mask); broadcast = gvn().transform(broadcast); } @@ -1352,7 +1352,7 @@ bool LibraryCallKit::inline_vector_mem_masked_operation(bool is_store) { } else { // Use the vector blend to implement the masked load vector. The biased elements are zeros. Node* zero = gvn().transform(gvn().zerocon(mem_elem_bt)); - zero = gvn().transform(VectorNode::scalar2vector(zero, mem_num_elem, Type::get_const_basic_type(mem_elem_bt))); + zero = gvn().transform(VectorNode::scalar2vector(zero, mem_num_elem, mem_elem_bt)); vload = gvn().transform(LoadVectorNode::make(0, control(), memory(addr), addr, addr_type, mem_num_elem, mem_elem_bt)); vload = gvn().transform(new VectorBlendNode(zero, vload, mask)); } @@ -1678,7 +1678,7 @@ bool LibraryCallKit::inline_vector_reduction() { assert(mask != nullptr || !is_masked_op, "Masked op needs the mask value never null"); if (mask != nullptr && !use_predicate) { - Node* reduce_identity = gvn().transform(VectorNode::scalar2vector(init, num_elem, Type::get_const_basic_type(elem_bt))); + Node* reduce_identity = gvn().transform(VectorNode::scalar2vector(init, num_elem, elem_bt)); value = gvn().transform(new VectorBlendNode(reduce_identity, value, mask)); } @@ -2059,7 +2059,7 @@ bool LibraryCallKit::inline_vector_rearrange() { const TypeVect* vt = v1->bottom_type()->is_vect(); rearrange = gvn().transform(rearrange); Node* zero = gvn().makecon(Type::get_zero_type(elem_bt)); - Node* zerovec = gvn().transform(VectorNode::scalar2vector(zero, num_elem, Type::get_const_basic_type(elem_bt))); + Node* zerovec = gvn().transform(VectorNode::scalar2vector(zero, num_elem, elem_bt)); rearrange = new VectorBlendNode(zerovec, rearrange, mask); } } @@ -2071,12 +2071,12 @@ bool LibraryCallKit::inline_vector_rearrange() { return true; } -static address get_svml_address(int vop, int bits, BasicType bt, char* name_ptr, int name_len) { +static address get_vector_math_address(int vop, int bits, BasicType bt, char* name_ptr, int name_len) { address addr = nullptr; assert(UseVectorStubs, "sanity"); assert(name_ptr != nullptr, "unexpected"); - assert((vop >= VectorSupport::VECTOR_OP_SVML_START) && (vop <= VectorSupport::VECTOR_OP_SVML_END), "unexpected"); - int op = vop - VectorSupport::VECTOR_OP_SVML_START; + assert((vop >= VectorSupport::VECTOR_OP_MATH_START) && (vop <= VectorSupport::VECTOR_OP_MATH_END), "unexpected"); + int op = vop - VectorSupport::VECTOR_OP_MATH_START; switch(bits) { case 64: //fallthough @@ -2084,21 +2084,34 @@ static address get_svml_address(int vop, int bits, BasicType bt, char* name_ptr, case 256: //fallthough case 512: if (bt == T_FLOAT) { - snprintf(name_ptr, name_len, "vector_%s_float%d", VectorSupport::svmlname[op], bits); + snprintf(name_ptr, name_len, "vector_%s_float_%dbits_fixed", VectorSupport::mathname[op], bits); addr = StubRoutines::_vector_f_math[exact_log2(bits/64)][op]; } else { assert(bt == T_DOUBLE, "must be FP type only"); - snprintf(name_ptr, name_len, "vector_%s_double%d", VectorSupport::svmlname[op], bits); + snprintf(name_ptr, name_len, "vector_%s_double_%dbits_fixed", VectorSupport::mathname[op], bits); addr = StubRoutines::_vector_d_math[exact_log2(bits/64)][op]; } break; default: - snprintf(name_ptr, name_len, "invalid"); - addr = nullptr; - Unimplemented(); + if (!Matcher::supports_scalable_vector() || !Matcher::vector_size_supported(bt, bits/type2aelembytes(bt)) ) { + snprintf(name_ptr, name_len, "invalid"); + addr = nullptr; + Unimplemented(); + } break; } + if (addr == nullptr && Matcher::supports_scalable_vector()) { + if (bt == T_FLOAT) { + snprintf(name_ptr, name_len, "vector_%s_float_%dbits_scalable", VectorSupport::mathname[op], bits); + addr = StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_SCALABLE][op]; + } else { + assert(bt == T_DOUBLE, "must be FP type only"); + snprintf(name_ptr, name_len, "vector_%s_double_%dbits_scalable", VectorSupport::mathname[op], bits); + addr = StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_SCALABLE][op]; + } + } + return addr; } @@ -2202,18 +2215,17 @@ bool LibraryCallKit::inline_vector_select_from() { } // cast index vector from elem_bt vector to byte vector - const Type * byte_bt = Type::get_const_basic_type(T_BYTE); - const TypeVect * byte_vt = TypeVect::make(byte_bt, num_elem); + const TypeVect* byte_vt = TypeVect::make(T_BYTE, num_elem); Node* byte_shuffle = gvn().transform(VectorCastNode::make(cast_vopc, v1, T_BYTE, num_elem)); // wrap the byte vector lanes to (num_elem - 1) to form the shuffle vector where num_elem is vector length // this is a simple AND operation as we come here only for power of two vector length Node* mod_val = gvn().makecon(TypeInt::make(num_elem-1)); - Node* bcast_mod = gvn().transform(VectorNode::scalar2vector(mod_val, num_elem, byte_bt)); + Node* bcast_mod = gvn().transform(VectorNode::scalar2vector(mod_val, num_elem, T_BYTE)); byte_shuffle = gvn().transform(VectorNode::make(Op_AndV, byte_shuffle, bcast_mod, byte_vt)); // load the shuffle to use in rearrange - const TypeVect * shuffle_vt = TypeVect::make(elem_bt, num_elem); + const TypeVect* shuffle_vt = TypeVect::make(elem_bt, num_elem); Node* load_shuffle = gvn().transform(new VectorLoadShuffleNode(byte_shuffle, shuffle_vt)); // and finally rearrange @@ -2230,7 +2242,7 @@ bool LibraryCallKit::inline_vector_select_from() { // create a zero vector with each lane element set as zero Node* zero = gvn().makecon(Type::get_zero_type(elem_bt)); - Node* zerovec = gvn().transform(VectorNode::scalar2vector(zero, num_elem, Type::get_const_basic_type(elem_bt))); + Node* zerovec = gvn().transform(VectorNode::scalar2vector(zero, num_elem, elem_bt)); // For each lane for which mask is set, blend in the rearranged lane into zero vector rearrange = new VectorBlendNode(zerovec, rearrange, mask); @@ -2246,16 +2258,16 @@ bool LibraryCallKit::inline_vector_select_from() { return true; } -Node* LibraryCallKit::gen_call_to_svml(int vector_api_op_id, BasicType bt, int num_elem, Node* opd1, Node* opd2) { +Node* LibraryCallKit::gen_call_to_vector_math(int vector_api_op_id, BasicType bt, int num_elem, Node* opd1, Node* opd2) { assert(UseVectorStubs, "sanity"); - assert(vector_api_op_id >= VectorSupport::VECTOR_OP_SVML_START && vector_api_op_id <= VectorSupport::VECTOR_OP_SVML_END, "need valid op id"); + assert(vector_api_op_id >= VectorSupport::VECTOR_OP_MATH_START && vector_api_op_id <= VectorSupport::VECTOR_OP_MATH_END, "need valid op id"); assert(opd1 != nullptr, "must not be null"); const TypeVect* vt = TypeVect::make(bt, num_elem); const TypeFunc* call_type = OptoRuntime::Math_Vector_Vector_Type(opd2 != nullptr ? 2 : 1, vt, vt); char name[100] = ""; - // Get address for svml method. - address addr = get_svml_address(vector_api_op_id, vt->length_in_bytes() * BitsPerByte, bt, name, 100); + // Get address for vector math method. + address addr = get_vector_math_address(vector_api_op_id, vt->length_in_bytes() * BitsPerByte, bt, name, 100); if (addr == nullptr) { return nullptr; @@ -2347,9 +2359,10 @@ bool LibraryCallKit::inline_vector_broadcast_int() { } Node* cnt = argument(6); + const TypeInt* cnt_type = cnt->bottom_type()->isa_int(); + ciKlass* vbox_klass = vector_klass->const_oop()->as_instance()->java_lang_Class_klass(); const TypeInstPtr* vbox_type = TypeInstPtr::make_exact(TypePtr::NotNull, vbox_klass); - const TypeInt* cnt_type = cnt->bottom_type()->isa_int(); // If CPU supports vector constant rotate instructions pass it directly bool is_const_rotate = is_rotate && cnt_type && cnt_type->is_con() && @@ -2378,9 +2391,8 @@ bool LibraryCallKit::inline_vector_broadcast_int() { } else { assert(is_rotate, "unexpected operation"); if (!is_const_rotate) { - const Type * type_bt = Type::get_const_basic_type(elem_bt); cnt = elem_bt == T_LONG ? gvn().transform(new ConvI2LNode(cnt)) : cnt; - opd2 = gvn().transform(VectorNode::scalar2vector(cnt, num_elem, type_bt)); + opd2 = gvn().transform(VectorNode::scalar2vector(cnt, num_elem, elem_bt)); } else { // Constant shift value. opd2 = cnt; @@ -2833,6 +2845,188 @@ bool LibraryCallKit::inline_vector_extract() { return true; } +static Node* LowerSelectFromTwoVectorOperation(PhaseGVN& phase, Node* index_vec, Node* src1, Node* src2, const TypeVect* vt) { + int num_elem = vt->length(); + BasicType elem_bt = vt->element_basic_type(); + + // Lower selectFrom operation into its constituent operations. + // SelectFromTwoVectorNode = + // (VectorBlend + // (VectorRearrange SRC1 (WRAPED_INDEX AND (VLEN-1)) + // (VectorRearrange SRC2 (WRAPED_INDEX AND (VLEN-1)) + // MASK) + // Where + // WRAPED_INDEX are computed by wrapping incoming indexes + // to two vector index range [0, VLEN*2) and + // MASK = WRAPED_INDEX < VLEN + // + // IR lowering prevents intrinsification failure and associated argument + // boxing penalties. + // + + const TypeVect* index_vect_type = index_vec->bottom_type()->is_vect(); + BasicType index_elem_bt = index_vect_type->element_basic_type(); + + // Downcast index vector to a type agnostic shuffle representation, shuffle + // indices are held in a byte vector which are later transformed to target + // specific permutation index format by subsequent VectorLoadShuffle. + int cast_vopc = VectorCastNode::opcode(0, index_elem_bt, true); + Node* index_byte_vec = phase.transform(VectorCastNode::make(cast_vopc, index_vec, T_BYTE, num_elem)); + + // Wrap indexes into two vector index range [0, VLEN * 2) + Node* two_vect_lane_cnt_m1 = phase.makecon(TypeInt::make(2 * num_elem - 1)); + Node* bcast_two_vect_lane_cnt_m1_vec = phase.transform(VectorNode::scalar2vector(two_vect_lane_cnt_m1, num_elem, + T_BYTE, false)); + index_byte_vec = phase.transform(VectorNode::make(Op_AndV, index_byte_vec, bcast_two_vect_lane_cnt_m1_vec, + index_byte_vec->bottom_type()->is_vect())); + + // Compute the blend mask for merging two independently permitted vectors + // using shuffle index in two vector index range [0, VLEN * 2). + BoolTest::mask pred = BoolTest::le; + ConINode* pred_node = phase.makecon(TypeInt::make(pred))->as_ConI(); + const TypeVect* vmask_type = TypeVect::makemask(T_BYTE, num_elem); + Node* lane_cnt_m1 = phase.makecon(TypeInt::make(num_elem - 1)); + Node* bcast_lane_cnt_m1_vec = phase.transform(VectorNode::scalar2vector(lane_cnt_m1, num_elem, + T_BYTE, false)); + Node* mask = phase.transform(new VectorMaskCmpNode(pred, index_byte_vec, bcast_lane_cnt_m1_vec, pred_node, vmask_type)); + + // Rearrange expects the indexes to lie within single vector index range [0, VLEN). + index_byte_vec = phase.transform(VectorNode::make(Op_AndV, index_byte_vec, bcast_lane_cnt_m1_vec, + index_byte_vec->bottom_type()->is_vect())); + + // Load indexes from byte vector and appropriately transform them to target + // specific permutation index format. + index_vec = phase.transform(new VectorLoadShuffleNode(index_byte_vec, index_vect_type)); + + vmask_type = TypeVect::makemask(elem_bt, num_elem); + mask = phase.transform(new VectorMaskCastNode(mask, vmask_type)); + + Node* p1 = phase.transform(new VectorRearrangeNode(src1, index_vec)); + Node* p2 = phase.transform(new VectorRearrangeNode(src2, index_vec)); + + return new VectorBlendNode(p2, p1, mask); +} + +// public static +// , +// E> +// V selectFromTwoVectorOp(Class vClass, Class eClass, int length, +// V v1, V v2, V v3, +// SelectFromTwoVector defaultImpl) +bool LibraryCallKit::inline_vector_select_from_two_vectors() { + const TypeInstPtr* vector_klass = gvn().type(argument(0))->isa_instptr(); + const TypeInstPtr* elem_klass = gvn().type(argument(1))->isa_instptr(); + const TypeInt* vlen = gvn().type(argument(2))->isa_int(); + + if (vector_klass == nullptr || elem_klass == nullptr || vlen == nullptr || vector_klass->const_oop() == nullptr || + elem_klass->const_oop() == nullptr ||!vlen->is_con()) { + log_if_needed(" ** missing constant: vclass=%s etype=%s vlen=%s", + NodeClassNames[argument(0)->Opcode()], + NodeClassNames[argument(1)->Opcode()], + NodeClassNames[argument(2)->Opcode()]); + return false; // not enough info for intrinsification + } + + if (!is_klass_initialized(vector_klass)) { + log_if_needed(" ** klass argument not initialized"); + return false; + } + + ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type(); + if (!elem_type->is_primitive_type()) { + log_if_needed(" ** not a primitive bt=%d", elem_type->basic_type()); + return false; // should be primitive type + } + + int num_elem = vlen->get_con(); + if (!is_power_of_2(num_elem)) { + log_if_needed(" ** vlen is not power of two=%d", num_elem); + return false; + } + + BasicType elem_bt = elem_type->basic_type(); + BasicType index_elem_bt = elem_bt; + if (elem_bt == T_FLOAT) { + index_elem_bt = T_INT; + } else if (elem_bt == T_DOUBLE) { + index_elem_bt = T_LONG; + } + + bool lowerSelectFromOp = false; + if (!arch_supports_vector(Op_SelectFromTwoVector, num_elem, elem_bt, VecMaskNotUsed)) { + int cast_vopc = VectorCastNode::opcode(-1, elem_bt, true); + if (!arch_supports_vector(Op_VectorMaskCmp, num_elem, T_BYTE, VecMaskNotUsed) || + !arch_supports_vector(Op_AndV, num_elem, T_BYTE, VecMaskNotUsed) || + !arch_supports_vector(Op_VectorMaskCast, num_elem, elem_bt, VecMaskNotUsed) || + !arch_supports_vector(Op_VectorBlend, num_elem, elem_bt, VecMaskUseLoad) || + !arch_supports_vector(Op_VectorRearrange, num_elem, elem_bt, VecMaskNotUsed) || + !arch_supports_vector(cast_vopc, num_elem, T_BYTE, VecMaskNotUsed) || + !arch_supports_vector(Op_VectorLoadShuffle, num_elem, index_elem_bt, VecMaskNotUsed) || + !arch_supports_vector(Op_Replicate, num_elem, T_BYTE, VecMaskNotUsed)) { + log_if_needed(" ** not supported: opc=%d vlen=%d etype=%s ismask=useload", + Op_SelectFromTwoVector, num_elem, type2name(elem_bt)); + return false; // not supported + } + lowerSelectFromOp = true; + } + + int cast_vopc = VectorCastNode::opcode(-1, elem_bt, true); + if (!lowerSelectFromOp) { + if (!arch_supports_vector(Op_AndV, num_elem, index_elem_bt, VecMaskNotUsed) || + !arch_supports_vector(Op_Replicate, num_elem, index_elem_bt, VecMaskNotUsed) || + (is_floating_point_type(elem_bt) && + !arch_supports_vector(cast_vopc, num_elem, index_elem_bt, VecMaskNotUsed))) { + log_if_needed(" ** index wrapping not supported: vlen=%d etype=%s" , + num_elem, type2name(elem_bt)); + return false; // not supported + } + } + + ciKlass* vbox_klass = vector_klass->const_oop()->as_instance()->java_lang_Class_klass(); + const TypeInstPtr* vbox_type = TypeInstPtr::make_exact(TypePtr::NotNull, vbox_klass); + + Node* opd1 = unbox_vector(argument(3), vbox_type, elem_bt, num_elem); + if (opd1 == nullptr) { + log_if_needed(" ** unbox failed v1=%s", + NodeClassNames[argument(3)->Opcode()]); + return false; + } + Node* opd2 = unbox_vector(argument(4), vbox_type, elem_bt, num_elem); + if (opd2 == nullptr) { + log_if_needed(" ** unbox failed v2=%s", + NodeClassNames[argument(4)->Opcode()]); + return false; + } + Node* opd3 = unbox_vector(argument(5), vbox_type, elem_bt, num_elem); + if (opd3 == nullptr) { + log_if_needed(" ** unbox failed v3=%s", + NodeClassNames[argument(5)->Opcode()]); + return false; + } + + const TypeVect* vt = TypeVect::make(elem_bt, num_elem); + + Node* operation = nullptr; + if (lowerSelectFromOp) { + operation = gvn().transform(LowerSelectFromTwoVectorOperation(gvn(), opd1, opd2, opd3, vt)); + } else { + if (index_elem_bt != elem_bt) { + opd1 = gvn().transform(VectorCastNode::make(cast_vopc, opd1, index_elem_bt, num_elem)); + } + int indexRangeMask = 2 * num_elem - 1; + Node* wrap_mask = gvn().makecon(TypeInteger::make(indexRangeMask, indexRangeMask, Type::WidenMin, index_elem_bt != T_LONG ? T_INT : index_elem_bt)); + Node* wrap_mask_vec = gvn().transform(VectorNode::scalar2vector(wrap_mask, num_elem, index_elem_bt, false)); + opd1 = gvn().transform(VectorNode::make(Op_AndV, opd1, wrap_mask_vec, opd1->bottom_type()->is_vect())); + operation = gvn().transform(VectorNode::make(Op_SelectFromTwoVector, opd1, opd2, opd3, vt)); + } + + // Wrap it up in VectorBox to keep object type information. + Node* vbox = box_vector(operation, vbox_type, elem_bt, num_elem); + set_result(vbox); + C->set_max_vector_size(MAX2(C->max_vector_size(), (uint)(num_elem * type2aelembytes(elem_bt)))); + return true; +} + // public static // , // M extends VectorMask, @@ -3038,7 +3232,7 @@ bool LibraryCallKit::inline_index_vector() { } default: fatal("%s", type2name(elem_bt)); } - scale = gvn().transform(VectorNode::scalar2vector(scale, num_elem, Type::get_const_basic_type(elem_bt))); + scale = gvn().transform(VectorNode::scalar2vector(scale, num_elem, elem_bt)); index = gvn().transform(VectorNode::make(vmul_op, index, scale, vt)); } @@ -3151,7 +3345,7 @@ bool LibraryCallKit::inline_index_partially_in_upper_range() { } default: fatal("%s", type2name(elem_bt)); } - indexLimit = gvn().transform(VectorNode::scalar2vector(indexLimit, num_elem, Type::get_const_basic_type(elem_bt))); + indexLimit = gvn().transform(VectorNode::scalar2vector(indexLimit, num_elem, elem_bt)); // Load the "iota" vector. const TypeVect* vt = TypeVect::make(elem_bt, num_elem); diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 8d2d3868fe635..fc4eaccff5ce5 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -416,6 +416,10 @@ VPointer::VPointer(MemNode* const mem, const VLoop& vloop, #ifdef ASSERT _debug_invar(nullptr), _debug_negate_invar(false), _debug_invar_scale(nullptr), #endif + _has_int_index_after_convI2L(false), + _int_index_after_convI2L_offset(0), + _int_index_after_convI2L_invar(nullptr), + _int_index_after_convI2L_scale(0), _nstack(nstack), _analyze_only(analyze_only), _stack_idx(0) #ifndef PRODUCT , _tracer(vloop.is_trace_pointer_analysis()) @@ -495,6 +499,11 @@ VPointer::VPointer(MemNode* const mem, const VLoop& vloop, return; } + if (!is_safe_to_use_as_simple_form(base, adr)) { + assert(!valid(), "does not have simple form"); + return; + } + _base = base; _adr = adr; assert(valid(), "Usable"); @@ -508,6 +517,10 @@ VPointer::VPointer(VPointer* p) : #ifdef ASSERT _debug_invar(nullptr), _debug_negate_invar(false), _debug_invar_scale(nullptr), #endif + _has_int_index_after_convI2L(false), + _int_index_after_convI2L_offset(0), + _int_index_after_convI2L_invar(nullptr), + _int_index_after_convI2L_scale(0), _nstack(p->_nstack), _analyze_only(p->_analyze_only), _stack_idx(p->_stack_idx) #ifndef PRODUCT , _tracer(p->_tracer._is_trace_alignment) @@ -530,6 +543,354 @@ int VPointer::invar_factor() const { return 1; } +// We would like to make decisions about aliasing (i.e. removing memory edges) and adjacency +// (i.e. which loads/stores can be packed) based on the simple form: +// +// s_pointer = adr + offset + invar + scale * ConvI2L(iv) +// +// However, we parse the compound-long-int form: +// +// c_pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_index) +// int_index = int_offset + int_invar + int_scale * iv +// +// In general, the simple and the compound-long-int form do not always compute the same pointer +// at runtime. For example, the simple form would give a different result due to an overflow +// in the int_index. +// +// Example: +// For both forms, we have: +// iv = 0 +// scale = 1 +// +// We now account the offset and invar once to the long part and once to the int part: +// Pointer 1 (long offset and long invar): +// long_offset = min_int +// long_invar = min_int +// int_offset = 0 +// int_invar = 0 +// +// Pointer 2 (int offset and int invar): +// long_offset = 0 +// long_invar = 0 +// int_offset = min_int +// int_invar = min_int +// +// This gives us the following pointers: +// Compound-long-int form pointers: +// Form: +// c_pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_offset + int_invar + int_scale * iv) +// +// Pointers: +// c_pointer1 = adr + min_int + min_int + 1 * ConvI2L(0 + 0 + 1 * 0) +// = adr + min_int + min_int +// = adr - 2^32 +// +// c_pointer2 = adr + 0 + 0 + 1 * ConvI2L(min_int + min_int + 1 * 0) +// = adr + ConvI2L(min_int + min_int) +// = adr + 0 +// = adr +// +// Simple form pointers: +// Form: +// s_pointer = adr + offset + invar + scale * ConvI2L(iv) +// s_pointer = adr + (long_offset + int_offset) + (long_invar + int_invar) + (long_scale * int_scale) * ConvI2L(iv) +// +// Pointers: +// s_pointer1 = adr + (min_int + 0 ) + (min_int + 0 ) + 1 * 0 +// = adr + min_int + min_int +// = adr - 2^32 +// s_pointer2 = adr + (0 + min_int ) + (0 + min_int ) + 1 * 0 +// = adr + min_int + min_int +// = adr - 2^32 +// +// We see that the two addresses are actually 2^32 bytes apart (derived from the c_pointers), but their simple form look identical. +// +// Hence, we need to determine in which cases it is safe to make decisions based on the simple +// form, rather than the compound-long-int form. If we cannot prove that using the simple form +// is safe (i.e. equivalent to the compound-long-int form), then we do not get a valid VPointer, +// and the associated memop cannot be vectorized. +bool VPointer::is_safe_to_use_as_simple_form(Node* base, Node* adr) const { +#ifndef _LP64 + // On 32-bit platforms, there is never an explicit int_index with ConvI2L for the iv. Thus, the + // parsed pointer form is always the simple form, with int operations: + // + // pointer = adr + offset + invar + scale * iv + // + assert(!_has_int_index_after_convI2L, "32-bit never has an int_index with ConvI2L for the iv"); + return true; +#else + + // Array accesses that are not Unsafe always have a RangeCheck which ensures that there is no + // int_index overflow. This implies that the conversion to long can be done separately: + // + // ConvI2L(int_index) = ConvI2L(int_offset) + ConvI2L(int_invar) + ConvI2L(scale) * ConvI2L(iv) + // + // And hence, the simple form is guaranteed to be identical to the compound-long-int form at + // runtime and the VPointer is safe/valid to be used. + const TypeAryPtr* ary_ptr_t = _mem->adr_type()->isa_aryptr(); + if (ary_ptr_t != nullptr) { + if (!_mem->is_unsafe_access()) { + return true; + } + } + + // We did not find the int_index. Just to be safe, reject this VPointer. + if (!_has_int_index_after_convI2L) { + return false; + } + + int int_offset = _int_index_after_convI2L_offset; + Node* int_invar = _int_index_after_convI2L_invar; + int int_scale = _int_index_after_convI2L_scale; + int long_scale = _scale / int_scale; + + // If "int_index = iv", then the simple form is identical to the compound-long-int form. + // + // int_index = int_offset + int_invar + int_scale * iv + // = 0 0 1 * iv + // = iv + if (int_offset == 0 && int_invar == nullptr && int_scale == 1) { + return true; + } + + // Intuition: What happens if the int_index overflows? Let us look at two pointers on the "overflow edge": + // + // pointer1 = adr + ConvI2L(int_index1) + // pointer2 = adr + ConvI2L(int_index2) + // + // int_index1 = max_int + 0 = max_int -> very close to but before the overflow + // int_index2 = max_int + 1 = min_int -> just enough to get the overflow + // + // When looking at the difference of pointer1 and pointer2, we notice that it is very large + // (almost 2^32). Since arrays have at most 2^31 elements, chances are high that pointer2 is + // an actual out-of-bounds access at runtime. These would normally be prevented by range checks + // at runtime. However, if the access was done by using Unsafe, where range checks are omitted, + // then an out-of-bounds access constitutes undefined behavior. This means that we are allowed to + // do anything, including changing the behavior. + // + // If we can set the right conditions, we have a guarantee that an overflow is either impossible + // (no overflow or range checks preventing that) or undefined behavior. In both cases, we are + // safe to do a vectorization. + // + // Approach: We want to prove a lower bound for the distance between these two pointers, and an + // upper bound for the size of a memory object. We can derive such an upper bound for + // arrays. We know they have at most 2^31 elements. If we know the size of the elements + // in bytes, we have: + // + // array_element_size_in_bytes * 2^31 >= max_possible_array_size_in_bytes + // >= array_size_in_bytes (ARR) + // + // If some small difference "delta" leads to an int_index overflow, we know that the + // int_index1 before overflow must have been close to max_int, and the int_index2 after + // the overflow must be close to min_int: + // + // pointer1 = adr + long_offset + long_invar + long_scale * ConvI2L(int_index1) + // =approx adr + long_offset + long_invar + long_scale * max_int + // + // pointer2 = adr + long_offset + long_invar + long_scale * ConvI2L(int_index2) + // =approx adr + long_offset + long_invar + long_scale * min_int + // + // We realize that the pointer difference is very large: + // + // difference =approx long_scale * 2^32 + // + // Hence, if we set the right condition for long_scale and array_element_size_in_bytes, + // we can prove that an overflow is impossible (or would imply undefined behaviour). + // + // We must now take this intuition, and develop a rigorous proof. We start by stating the problem + // more precisely, with the help of some definitions and the Statement we are going to prove. + // + // Definition: + // Two VPointers are "comparable" (i.e. VPointer::comparable is true, set with VPointer::cmp()), + // iff all of these conditions apply for the simple form: + // 1) Both VPointers are valid. + // 2) The adr are identical, or both are array bases of different arrays. + // 3) They have identical scale. + // 4) They have identical invar. + // 5) The difference in offsets is limited: abs(offset1 - offset2) < 2^31. (DIFF) + // + // For the Vectorization Optimization, we pair-wise compare VPointers and determine if they are: + // 1) "not comparable": + // We do not optimize them (assume they alias, not assume adjacency). + // + // Whenever we chose this option based on the simple form, it is also correct based on the + // compound-long-int form, since we make no optimizations based on it. + // + // 2) "comparable" with different array bases at runtime: + // We assume they do not alias (remove memory edges), but not assume adjacency. + // + // Whenever we have two different array bases for the simple form, we also have different + // array bases for the compound-long-form. Since VPointers provably point to different + // memory objects, they can never alias. + // + // 3) "comparable" with the same base address: + // We compute the relative pointer difference, and based on the load/store size we can + // compute aliasing and adjacency. + // + // We must find a condition under which the pointer difference of the simple form is + // identical to the pointer difference of the compound-long-form. We do this with the + // Statement below, which we then proceed to prove. + // + // Statement: + // If two VPointers satisfy these 3 conditions: + // 1) They are "comparable". + // 2) They have the same base address. + // 3) Their long_scale is a multiple of the array element size in bytes: + // + // abs(long_scale) % array_element_size_in_bytes = 0 (A) + // + // Then their pointer difference of the simple form is identical to the pointer difference + // of the compound-long-int form. + // + // More precisely: + // Such two VPointers by definition have identical adr, invar, and scale. + // Their simple form is: + // + // s_pointer1 = adr + offset1 + invar + scale * ConvI2L(iv) (B1) + // s_pointer2 = adr + offset2 + invar + scale * ConvI2L(iv) (B2) + // + // Thus, the pointer difference of the simple forms collapses to the difference in offsets: + // + // s_difference = s_pointer1 - s_pointer2 = offset1 - offset2 (C) + // + // Their compound-long-int form for these VPointer is: + // + // c_pointer1 = adr + long_offset1 + long_invar1 + long_scale1 * ConvI2L(int_index1) (D1) + // int_index1 = int_offset1 + int_invar1 + int_scale1 * iv (D2) + // + // c_pointer2 = adr + long_offset2 + long_invar2 + long_scale2 * ConvI2L(int_index2) (D3) + // int_index2 = int_offset2 + int_invar2 + int_scale2 * iv (D4) + // + // And these are the offset1, offset2, invar and scale from the simple form (B1) and (B2): + // + // offset1 = long_offset1 + long_scale1 * ConvI2L(int_offset1) (D5) + // offset2 = long_offset2 + long_scale2 * ConvI2L(int_offset2) (D6) + // + // invar = long_invar1 + long_scale1 * ConvI2L(int_invar1) + // = long_invar2 + long_scale2 * ConvI2L(int_invar2) (D7) + // + // scale = long_scale1 * ConvI2L(int_scale1) + // = long_scale2 * ConvI2L(int_scale2) (D8) + // + // The pointer difference of the compound-long-int form is defined as: + // + // c_difference = c_pointer1 - c_pointer2 + // + // Thus, the statement claims that for the two VPointer we have: + // + // s_difference = c_difference (Statement) + // + // We prove the Statement with the help of a Lemma: + // + // Lemma: + // There is some integer x, such that: + // + // c_difference = s_difference + array_element_size_in_bytes * x * 2^32 (Lemma) + // + // From condition (DIFF), we can derive: + // + // abs(s_difference) < 2^31 (E) + // + // Assuming the Lemma, we prove the Statement: + // If "x = 0" (intuitively: the int_index does not overflow), then: + // c_difference = s_difference + // and hence the simple form computes the same pointer difference as the compound-long-int form. + // If "x != 0" (intuitively: the int_index overflows), then: + // abs(c_difference) >= abs(s_difference + array_element_size_in_bytes * x * 2^32) + // >= array_element_size_in_bytes * 2^32 - abs(s_difference) + // -- apply (E) -- + // > array_element_size_in_bytes * 2^32 - 2^31 + // >= array_element_size_in_bytes * 2^31 + // -- apply (ARR) -- + // >= max_possible_array_size_in_bytes + // >= array_size_in_bytes + // + // This shows that c_pointer1 and c_pointer2 have a distance that exceeds the maximum array size. + // Thus, at least one of the two pointers must be outside of the array bounds. But we can assume + // that out-of-bounds accesses do not happen. If they still do, it is undefined behavior. Hence, + // we are allowed to do anything. We can also "safely" use the simple form in this case even though + // it might not match the compound-long-int form at runtime. + // QED Statement. + // + // We must now prove the Lemma. + // + // ConvI2L always truncates by some power of 2^32, i.e. there is some integer y such that: + // + // ConvI2L(y1 + y2) = ConvI2L(y1) + ConvI2L(y2) + 2^32 * y (F) + // + // It follows, that there is an integer y1 such that: + // + // ConvI2L(int_index1) = ConvI2L(int_offset1 + int_invar1 + int_scale1 * iv) + // -- apply (F) -- + // = ConvI2L(int_offset1) + // + ConvI2L(int_invar1) + // + ConvI2L(int_scale1) * ConvI2L(iv) + // + y1 * 2^32 (G) + // + // Thus, we can write the compound-long-int form (D1) as: + // + // c_pointer1 = adr + long_offset1 + long_invar1 + long_scale1 * ConvI2L(int_index1) + // -- apply (G) -- + // = adr + // + long_offset1 + // + long_invar1 + // + long_scale1 * ConvI2L(int_offset1) + // + long_scale1 * ConvI2L(int_invar1) + // + long_scale1 * ConvI2L(int_scale1) * ConvI2L(iv) + // + long_scale1 * y1 * 2^32 (H) + // + // And we can write the simple form as: + // + // s_pointer1 = adr + offset1 + invar + scale * ConvI2L(iv) + // -- apply (D5, D7, D8) -- + // = adr + // + long_offset1 + // + long_scale1 * ConvI2L(int_offset1) + // + long_invar1 + // + long_scale1 * ConvI2L(int_invar1) + // + long_scale1 * ConvI2L(int_scale1) * ConvI2L(iv) (K) + // + // We now compute the pointer difference between the simple (K) and compound-long-int form (H). + // Most terms cancel out immediately: + // + // sc_difference1 = c_pointer1 - s_pointer1 = long_scale1 * y1 * 2^32 (L) + // + // Rearranging the equation (L), we get: + // + // c_pointer1 = s_pointer1 + long_scale1 * y1 * 2^32 (M) + // + // And since long_scale1 is a multiple of array_element_size_in_bytes, there is some integer + // x1, such that (M) implies: + // + // c_pointer1 = s_pointer1 + array_element_size_in_bytes * x1 * 2^32 (N) + // + // With an analogue equation for c_pointer2, we can now compute the pointer difference for + // the compound-long-int form: + // + // c_difference = c_pointer1 - c_pointer2 + // -- apply (N) -- + // = s_pointer1 + array_element_size_in_bytes * x1 * 2^32 + // -(s_pointer2 + array_element_size_in_bytes * x2 * 2^32) + // -- where "x = x1 - x2" -- + // = s_pointer1 - s_pointer2 + array_element_size_in_bytes * x * 2^32 + // -- apply (C) -- + // = s_difference + array_element_size_in_bytes * x * 2^32 + // QED Lemma. + if (ary_ptr_t != nullptr) { + BasicType array_element_bt = ary_ptr_t->elem()->array_element_basic_type(); + if (is_java_primitive(array_element_bt)) { + int array_element_size_in_bytes = type2aelembytes(array_element_bt); + if (abs(long_scale) % array_element_size_in_bytes == 0) { + return true; + } + } + } + + // General case: we do not know if it is safe to use the simple form. + return false; +#endif +} + bool VPointer::is_loop_member(Node* n) const { Node* n_c = phase()->get_ctrl(n); return lpt()->is_member(phase()->get_loop(n_c)); @@ -582,11 +943,40 @@ bool VPointer::scaled_iv_plus_offset(Node* n) { } } else if (opc == Op_SubI || opc == Op_SubL) { if (offset_plus_k(n->in(2), true) && scaled_iv_plus_offset(n->in(1))) { + // (offset1 + invar1 + scale * iv) - (offset2 + invar2) + // Subtraction handled via "negate" flag of "offset_plus_k". NOT_PRODUCT(_tracer.scaled_iv_plus_offset_6(n);) return true; } - if (offset_plus_k(n->in(1)) && scaled_iv_plus_offset(n->in(2))) { - _scale *= -1; + VPointer tmp(this); + if (offset_plus_k(n->in(1)) && tmp.scaled_iv_plus_offset(n->in(2))) { + // (offset1 + invar1) - (offset2 + invar2 + scale * iv) + // Subtraction handled explicitly below. + assert(_scale == 0, "shouldn't be set yet"); + // _scale = -tmp._scale + if (!try_MulI_no_overflow(-1, tmp._scale, _scale)) { + return false; // mul overflow. + } + // _offset -= tmp._offset + if (!try_SubI_no_overflow(_offset, tmp._offset, _offset)) { + return false; // sub overflow. + } + // _invar -= tmp._invar + if (tmp._invar != nullptr) { + maybe_add_to_invar(tmp._invar, true); +#ifdef ASSERT + _debug_invar_scale = tmp._debug_invar_scale; + _debug_negate_invar = !tmp._debug_negate_invar; +#endif + } + + // Forward info about the int_index: + assert(!_has_int_index_after_convI2L, "no previous int_index discovered"); + _has_int_index_after_convI2L = tmp._has_int_index_after_convI2L; + _int_index_after_convI2L_offset = tmp._int_index_after_convI2L_offset; + _int_index_after_convI2L_invar = tmp._int_index_after_convI2L_invar; + _int_index_after_convI2L_scale = tmp._int_index_after_convI2L_scale; + NOT_PRODUCT(_tracer.scaled_iv_plus_offset_7(n);) return true; } @@ -628,10 +1018,52 @@ bool VPointer::scaled_iv(Node* n) { } } else if (opc == Op_LShiftI) { if (n->in(1) == iv() && n->in(2)->is_Con()) { - _scale = 1 << n->in(2)->get_int(); + if (!try_LShiftI_no_overflow(1, n->in(2)->get_int(), _scale)) { + return false; // shift overflow. + } NOT_PRODUCT(_tracer.scaled_iv_6(n, _scale);) return true; } + } else if (opc == Op_ConvI2L && !has_iv()) { + // So far we have not found the iv yet, and are about to enter a ConvI2L subgraph, + // which may be the int index (that might overflow) for the memory access, of the form: + // + // int_index = int_offset + int_invar + int_scale * iv + // + // If we simply continue parsing with the current VPointer, then the int_offset and + // int_invar simply get added to the long offset and invar. But for the checks in + // VPointer::is_safe_to_use_as_simple_form() we need to have explicit access to the + // int_index. Thus, we must parse it explicitly here. For this, we use a temporary + // VPointer, to pattern match the int_index sub-expression of the address. + + NOT_PRODUCT(Tracer::Depth dddd;) + VPointer tmp(this); + NOT_PRODUCT(_tracer.scaled_iv_8(n, &tmp);) + + if (tmp.scaled_iv_plus_offset(n->in(1)) && tmp.has_iv()) { + // We successfully matched an integer index, of the form: + // int_index = int_offset + int_invar + int_scale * iv + // Forward scale. + assert(_scale == 0 && tmp._scale != 0, "iv only found just now"); + _scale = tmp._scale; + // Accumulate offset. + if (!try_AddI_no_overflow(_offset, tmp._offset, _offset)) { + return false; // add overflow. + } + // Accumulate invar. + if (tmp._invar != nullptr) { + maybe_add_to_invar(tmp._invar, false); + } + // Set info about the int_index: + assert(!_has_int_index_after_convI2L, "no previous int_index discovered"); + _has_int_index_after_convI2L = true; + _int_index_after_convI2L_offset = tmp._offset; + _int_index_after_convI2L_invar = tmp._invar; + _int_index_after_convI2L_scale = tmp._scale; + + NOT_PRODUCT(_tracer.scaled_iv_7(n);) + return true; + } } else if (opc == Op_ConvI2L || opc == Op_CastII) { if (scaled_iv_plus_offset(n->in(1))) { NOT_PRODUCT(_tracer.scaled_iv_7(n);) @@ -647,9 +1079,20 @@ bool VPointer::scaled_iv(Node* n) { NOT_PRODUCT(_tracer.scaled_iv_8(n, &tmp);) if (tmp.scaled_iv_plus_offset(n->in(1))) { - int scale = n->in(2)->get_int(); - _scale = tmp._scale << scale; - _offset += tmp._offset << scale; + int shift = n->in(2)->get_int(); + // Accumulate scale. + if (!try_LShiftI_no_overflow(tmp._scale, shift, _scale)) { + return false; // shift overflow. + } + // Accumulate offset. + int shifted_offset = 0; + if (!try_LShiftI_no_overflow(tmp._offset, shift, shifted_offset)) { + return false; // shift overflow. + } + if (!try_AddI_no_overflow(_offset, shifted_offset, _offset)) { + return false; // add overflow. + } + // Accumulate invar. if (tmp._invar != nullptr) { BasicType bt = tmp._invar->bottom_type()->basic_type(); assert(bt == T_INT || bt == T_LONG, ""); @@ -658,6 +1101,14 @@ bool VPointer::scaled_iv(Node* n) { _debug_invar_scale = n->in(2); #endif } + + // Forward info about the int_index: + assert(!_has_int_index_after_convI2L, "no previous int_index discovered"); + _has_int_index_after_convI2L = tmp._has_int_index_after_convI2L; + _int_index_after_convI2L_offset = tmp._int_index_after_convI2L_offset; + _int_index_after_convI2L_invar = tmp._int_index_after_convI2L_invar; + _int_index_after_convI2L_scale = tmp._int_index_after_convI2L_scale; + NOT_PRODUCT(_tracer.scaled_iv_9(n, _scale, _offset, _invar);) return true; } @@ -675,7 +1126,9 @@ bool VPointer::offset_plus_k(Node* n, bool negate) { int opc = n->Opcode(); if (opc == Op_ConI) { - _offset += negate ? -(n->get_int()) : n->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } NOT_PRODUCT(_tracer.offset_plus_k_2(n, _offset);) return true; } else if (opc == Op_ConL) { @@ -684,7 +1137,9 @@ bool VPointer::offset_plus_k(Node* n, bool negate) { if (t->higher_equal(TypeLong::INT)) { jlong loff = n->get_long(); jint off = (jint)loff; - _offset += negate ? -off : loff; + if (!try_AddSubI_no_overflow(_offset, off, negate, _offset)) { + return false; // add/sub overflow. + } NOT_PRODUCT(_tracer.offset_plus_k_3(n, _offset);) return true; } @@ -699,11 +1154,15 @@ bool VPointer::offset_plus_k(Node* n, bool negate) { if (opc == Op_AddI) { if (n->in(2)->is_Con() && invariant(n->in(1))) { maybe_add_to_invar(n->in(1), negate); - _offset += negate ? -(n->in(2)->get_int()) : n->in(2)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(2)->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } NOT_PRODUCT(_tracer.offset_plus_k_6(n, _invar, negate, _offset);) return true; } else if (n->in(1)->is_Con() && invariant(n->in(2))) { - _offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(1)->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } maybe_add_to_invar(n->in(2), negate); NOT_PRODUCT(_tracer.offset_plus_k_7(n, _invar, negate, _offset);) return true; @@ -712,11 +1171,15 @@ bool VPointer::offset_plus_k(Node* n, bool negate) { if (opc == Op_SubI) { if (n->in(2)->is_Con() && invariant(n->in(1))) { maybe_add_to_invar(n->in(1), negate); - _offset += !negate ? -(n->in(2)->get_int()) : n->in(2)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(2)->get_int(), !negate, _offset)) { + return false; // add/sub overflow. + } NOT_PRODUCT(_tracer.offset_plus_k_8(n, _invar, negate, _offset);) return true; } else if (n->in(1)->is_Con() && invariant(n->in(2))) { - _offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(1)->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } maybe_add_to_invar(n->in(2), !negate); NOT_PRODUCT(_tracer.offset_plus_k_9(n, _invar, !negate, _offset);) return true; @@ -806,6 +1269,57 @@ void VPointer::maybe_add_to_invar(Node* new_invar, bool negate) { _invar = register_if_new(add); } +bool VPointer::try_AddI_no_overflow(int offset1, int offset2, int& result) { + jlong long_offset = java_add((jlong)(offset1), (jlong)(offset2)); + jint int_offset = java_add( offset1, offset2); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + +bool VPointer::try_SubI_no_overflow(int offset1, int offset2, int& result) { + jlong long_offset = java_subtract((jlong)(offset1), (jlong)(offset2)); + jint int_offset = java_subtract( offset1, offset2); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + +bool VPointer::try_AddSubI_no_overflow(int offset1, int offset2, bool is_sub, int& result) { + if (is_sub) { + return try_SubI_no_overflow(offset1, offset2, result); + } else { + return try_AddI_no_overflow(offset1, offset2, result); + } +} + +bool VPointer::try_LShiftI_no_overflow(int offset, int shift, int& result) { + if (shift < 0 || shift > 31) { + return false; + } + jlong long_offset = java_shift_left((jlong)(offset), shift); + jint int_offset = java_shift_left( offset, shift); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + +bool VPointer::try_MulI_no_overflow(int offset1, int offset2, int& result) { + jlong long_offset = java_multiply((jlong)(offset1), (jlong)(offset2)); + jint int_offset = java_multiply( offset1, offset2); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + // We use two comparisons, because a subtraction could underflow. #define RETURN_CMP_VALUE_IF_NOT_EQUAL(a, b) \ if (a < b) { return -1; } \ diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index 3984407c5654b..b084edd44b339 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -670,13 +670,51 @@ class VLoopAnalyzer : StackObj { // A vectorization pointer (VPointer) has information about an address for // dependence checking and vector alignment. It's usually bound to a memory // operation in a counted loop for vectorizable analysis. +// +// We parse and represent pointers of the simple form: +// +// pointer = adr + offset + invar + scale * ConvI2L(iv) +// +// Where: +// +// adr: the base address of an array (base = adr) +// OR +// some address to off-heap memory (base = TOP) +// +// offset: a constant offset +// invar: a runtime variable, which is invariant during the loop +// scale: scaling factor +// iv: loop induction variable +// +// But more precisely, we parse the composite-long-int form: +// +// pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_offset + inv_invar + int_scale * iv) +// +// pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_index) +// int_index = int_offset + int_invar + int_scale * iv +// +// However, for aliasing and adjacency checks (e.g. VPointer::cmp()) we always use the simple form to make +// decisions. Hence, we must make sure to only create a "valid" VPointer if the optimisations based on the +// simple form produce the same result as the compound-long-int form would. Intuitively, this depends on +// if the int_index overflows, but the precise conditions are given in VPointer::is_safe_to_use_as_simple_form(). +// +// ConvI2L(int_index) = ConvI2L(int_offset + int_invar + int_scale * iv) +// = Convi2L(int_offset) + ConvI2L(int_invar) + ConvI2L(int_scale) * ConvI2L(iv) +// +// scale = long_scale * ConvI2L(int_scale) +// offset = long_offset + long_scale * ConvI2L(int_offset) +// invar = long_invar + long_scale * ConvI2L(int_invar) +// +// pointer = adr + offset + invar + scale * ConvI2L(iv) +// class VPointer : public ArenaObj { protected: MemNode* const _mem; // My memory reference node const VLoop& _vloop; - Node* _base; // null if unsafe nonheap reference - Node* _adr; // address pointer + // Components of the simple form: + Node* _base; // Base address of an array OR null if some off-heap memory. + Node* _adr; // Same as _base if an array pointer OR some off-heap memory pointer. int _scale; // multiplier for iv (in bytes), 0 if no loop iv int _offset; // constant offset (in bytes) @@ -687,6 +725,13 @@ class VPointer : public ArenaObj { Node* _debug_invar_scale; // multiplier for invariant #endif + // The int_index components of the compound-long-int form. Used to decide if it is safe to use the + // simple form rather than the compound-long-int form that was parsed. + bool _has_int_index_after_convI2L; + int _int_index_after_convI2L_offset; + Node* _int_index_after_convI2L_invar; + int _int_index_after_convI2L_scale; + Node_Stack* _nstack; // stack used to record a vpointer trace of variants bool _analyze_only; // Used in loop unrolling only for vpointer trace uint _stack_idx; // Used in loop unrolling only for vpointer trace @@ -726,6 +771,8 @@ class VPointer : public ArenaObj { VPointer(VPointer* p); NONCOPYABLE(VPointer); + bool is_safe_to_use_as_simple_form(Node* base, Node* adr) const; + public: bool valid() const { return _adr != nullptr; } bool has_iv() const { return _scale != 0; } @@ -751,10 +798,43 @@ class VPointer : public ArenaObj { return _invar == q._invar; } + // We compute if and how two VPointers can alias at runtime, i.e. if the two addressed regions of memory can + // ever overlap. There are essentially 3 relevant return states: + // - NotComparable: Synonymous to "unknown aliasing". + // We have no information about how the two VPointers can alias. They could overlap, refer + // to another location in the same memory object, or point to a completely different object. + // -> Memory edge required. Aliasing unlikely but possible. + // + // - Less / Greater: Synonymous to "never aliasing". + // The two VPointers may point into the same memory object, but be non-aliasing (i.e. we + // know both address regions inside the same memory object, but these regions are non- + // overlapping), or the VPointers point to entirely different objects. + // -> No memory edge required. Aliasing impossible. + // + // - Equal: Synonymous to "overlap, or point to different memory objects". + // The two VPointers either overlap on the same memory object, or point to two different + // memory objects. + // -> Memory edge required. Aliasing likely. + // + // In a future refactoring, we can simplify to two states: + // - NeverAlias: instead of Less / Greater + // - MayAlias: instead of Equal / NotComparable + // + // Two VPointer are "comparable" (Less / Greater / Equal), iff all of these conditions apply: + // 1) Both are valid, i.e. expressible in the compound-long-int or simple form. + // 2) The adr are identical, or both are array bases of different arrays. + // 3) They have identical scale. + // 4) They have identical invar. + // 5) The difference in offsets is limited: abs(offset0 - offset1) < 2^31. int cmp(const VPointer& q) const { if (valid() && q.valid() && (_adr == q._adr || (_base == _adr && q._base == q._adr)) && _scale == q._scale && invar_equals(q)) { + jlong difference = abs(java_subtract((jlong)_offset, (jlong)q._offset)); + jlong max_diff = (jlong)1 << 31; + if (difference >= max_diff) { + return NotComparable; + } bool overlap = q._offset < _offset + memory_size() && _offset < q._offset + q.memory_size(); return overlap ? Equal : (_offset < q._offset ? Less : Greater); @@ -859,6 +939,12 @@ class VPointer : public ArenaObj { void maybe_add_to_invar(Node* new_invar, bool negate); + static bool try_AddI_no_overflow(int offset1, int offset2, int& result); + static bool try_SubI_no_overflow(int offset1, int offset2, int& result); + static bool try_AddSubI_no_overflow(int offset1, int offset2, bool is_sub, int& result); + static bool try_LShiftI_no_overflow(int offset1, int offset2, int& result); + static bool try_MulI_no_overflow(int offset1, int offset2, int& result); + Node* register_if_new(Node* n) const; }; diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 72b49c043b6b6..cc2fff23accc2 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -667,7 +667,7 @@ VectorNode* VectorNode::make_mask_node(int vopc, Node* n1, Node* n2, uint vlen, } // Make a vector node for binary operation -VectorNode* VectorNode::make(int vopc, Node* n1, Node* n2, const TypeVect* vt, bool is_mask, bool is_var_shift) { +VectorNode* VectorNode::make(int vopc, Node* n1, Node* n2, const TypeVect* vt, bool is_mask, bool is_var_shift, bool is_unsigned) { // This method should not be called for unimplemented vectors. guarantee(vopc > 0, "vopc must be > 0"); @@ -739,6 +739,9 @@ VectorNode* VectorNode::make(int vopc, Node* n1, Node* n2, const TypeVect* vt, b case Op_RShiftVI: return new RShiftVINode(n1, n2, vt, is_var_shift); case Op_RShiftVL: return new RShiftVLNode(n1, n2, vt, is_var_shift); + case Op_UMinV: return new UMinVNode(n1, n2, vt); + case Op_UMaxV: return new UMaxVNode(n1, n2, vt); + case Op_URShiftVB: return new URShiftVBNode(n1, n2, vt, is_var_shift); case Op_URShiftVS: return new URShiftVSNode(n1, n2, vt, is_var_shift); case Op_URShiftVI: return new URShiftVINode(n1, n2, vt, is_var_shift); @@ -759,6 +762,10 @@ VectorNode* VectorNode::make(int vopc, Node* n1, Node* n2, const TypeVect* vt, b case Op_ExpandBitsV: return new ExpandBitsVNode(n1, n2, vt); case Op_CountLeadingZerosV: return new CountLeadingZerosVNode(n1, vt); case Op_CountTrailingZerosV: return new CountTrailingZerosVNode(n1, vt); + + case Op_SaturatingAddV: return new SaturatingAddVNode(n1, n2, vt, is_unsigned); + case Op_SaturatingSubV: return new SaturatingSubVNode(n1, n2, vt, is_unsigned); + default: fatal("Missed vector creation for '%s'", NodeClassNames[vopc]); return nullptr; @@ -781,6 +788,7 @@ VectorNode* VectorNode::make(int vopc, Node* n1, Node* n2, Node* n3, const TypeV switch (vopc) { case Op_FmaVD: return new FmaVDNode(n1, n2, n3, vt); case Op_FmaVF: return new FmaVFNode(n1, n2, n3, vt); + case Op_SelectFromTwoVector: return new SelectFromTwoVectorNode(n1, n2, n3, vt); case Op_SignumVD: return new SignumVDNode(n1, n2, n3, vt); case Op_SignumVF: return new SignumVFNode(n1, n2, n3, vt); default: @@ -799,15 +807,13 @@ VectorNode* VectorNode::make(int opc, Node* n1, Node* n2, Node* n3, uint vlen, B } // Scalar promotion -VectorNode* VectorNode::scalar2vector(Node* s, uint vlen, const Type* opd_t, bool is_mask) { - BasicType bt = opd_t->array_element_basic_type(); +VectorNode* VectorNode::scalar2vector(Node* s, uint vlen, BasicType bt, bool is_mask) { if (is_mask && Matcher::match_rule_supported_vector(Op_MaskAll, vlen, bt)) { - const TypeVect* vt = TypeVect::make(opd_t, vlen, true); + const TypeVect* vt = TypeVect::make(bt, vlen, true); return new MaskAllNode(s, vt); } - const TypeVect* vt = opd_t->singleton() ? TypeVect::make(opd_t, vlen) - : TypeVect::make(bt, vlen); + const TypeVect* vt = TypeVect::make(bt, vlen); return new ReplicateNode(s, vt); } @@ -1626,8 +1632,6 @@ Node* VectorNode::degenerate_vector_rotate(Node* src, Node* cnt, bool is_rotate_ Node* const_one_node = nullptr; assert(cnt->bottom_type()->isa_vect(), "Unexpected shift"); - const Type* elem_ty = Type::get_const_basic_type(bt); - if (bt == T_LONG) { shift_mask_node = phase->longcon(shift_mask); const_one_node = phase->longcon(1L); @@ -1639,8 +1643,8 @@ Node* VectorNode::degenerate_vector_rotate(Node* src, Node* cnt, bool is_rotate_ subVopc = VectorNode::opcode(Op_SubI, bt); addVopc = VectorNode::opcode(Op_AddI, bt); } - Node* vector_mask = phase->transform(VectorNode::scalar2vector(shift_mask_node, vlen, elem_ty)); - Node* vector_one = phase->transform(VectorNode::scalar2vector(const_one_node, vlen, elem_ty)); + Node* vector_mask = phase->transform(VectorNode::scalar2vector(shift_mask_node, vlen, bt)); + Node* vector_one = phase->transform(VectorNode::scalar2vector(const_one_node, vlen, bt)); shiftRCnt = cnt; shiftRCnt = phase->transform(VectorNode::make(Op_AndV, shiftRCnt, vector_mask, vt)); @@ -1882,12 +1886,12 @@ Node* NegVNode::degenerate_integral_negate(PhaseGVN* phase, bool is_predicated) const_one = phase->intcon(1); add_opc = Op_AddI; } - const_minus_one = phase->transform(VectorNode::scalar2vector(const_minus_one, vlen, Type::get_const_basic_type(bt))); + const_minus_one = phase->transform(VectorNode::scalar2vector(const_minus_one, vlen, bt)); Node* xorv = VectorNode::make(Op_XorV, in(1), const_minus_one, vt); xorv->add_req(in(2)); xorv->add_flag(Node::Flag_is_predicated_vector); phase->transform(xorv); - const_one = phase->transform(VectorNode::scalar2vector(const_one, vlen, Type::get_const_basic_type(bt))); + const_one = phase->transform(VectorNode::scalar2vector(const_one, vlen, bt)); Node* addv = VectorNode::make(VectorNode::opcode(add_opc, bt), xorv, const_one, vt); addv->add_req(in(2)); addv->add_flag(Node::Flag_is_predicated_vector); @@ -1904,7 +1908,7 @@ Node* NegVNode::degenerate_integral_negate(PhaseGVN* phase, bool is_predicated) const_zero = phase->intcon(0); sub_opc = Op_SubI; } - const_zero = phase->transform(VectorNode::scalar2vector(const_zero, vlen, Type::get_const_basic_type(bt))); + const_zero = phase->transform(VectorNode::scalar2vector(const_zero, vlen, bt)); return VectorNode::make(VectorNode::opcode(sub_opc, bt), const_zero, in(1), vt); } @@ -2069,8 +2073,7 @@ Node* XorVNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (!is_predicated_vector() && (in(1) == in(2))) { BasicType bt = vect_type()->element_basic_type(); Node* zero = phase->transform(phase->zerocon(bt)); - return VectorNode::scalar2vector(zero, length(), Type::get_const_basic_type(bt), - bottom_type()->isa_vectmask() != nullptr); + return VectorNode::scalar2vector(zero, length(), bt, bottom_type()->isa_vectmask() != nullptr); } return nullptr; } @@ -2087,5 +2090,4 @@ Node* VectorBlendNode::Identity(PhaseGVN* phase) { void VectorBoxAllocateNode::dump_spec(outputStream *st) const { CallStaticJavaNode::dump_spec(st); } - #endif // !PRODUCT diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index 23ddebaf33889..25a381408ca5c 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -75,10 +75,10 @@ class VectorNode : public TypeNode { virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); - static VectorNode* scalar2vector(Node* s, uint vlen, const Type* opd_t, bool is_mask = false); + static VectorNode* scalar2vector(Node* s, uint vlen, BasicType bt, bool is_mask = false); static VectorNode* shift_count(int opc, Node* cnt, uint vlen, BasicType bt); static VectorNode* make(int opc, Node* n1, Node* n2, uint vlen, BasicType bt, bool is_var_shift = false); - static VectorNode* make(int vopc, Node* n1, Node* n2, const TypeVect* vt, bool is_mask = false, bool is_var_shift = false); + static VectorNode* make(int vopc, Node* n1, Node* n2, const TypeVect* vt, bool is_mask = false, bool is_var_shift = false, bool is_unsigned = false); static VectorNode* make(int opc, Node* n1, Node* n2, Node* n3, uint vlen, BasicType bt); static VectorNode* make(int vopc, Node* n1, Node* n2, Node* n3, const TypeVect* vt); static VectorNode* make_mask_node(int vopc, Node* n1, Node* n2, uint vlen, BasicType bt); @@ -144,6 +144,32 @@ class VectorNode : public TypeNode { }; //===========================Vector=ALU=Operations============================= +// Base IR node for saturating signed / unsigned operations. +// Saturating operation prevents wrapping result value in over/underflowing +// scenarios, instead returns delimiting MAX/MIN value of result type. +class SaturatingVectorNode : public VectorNode { + private: + const bool _is_unsigned; + + public: + SaturatingVectorNode(Node* in1, Node* in2, const TypeVect* vt, bool is_unsigned) : VectorNode(in1, in2, vt), _is_unsigned(is_unsigned) { + init_class_id(Class_SaturatingVector); + } + + // Needed for proper cloning. + virtual uint size_of() const { return sizeof(*this); } + +#ifndef PRODUCT + // Print node specific info + virtual void dump_spec(outputStream *st) const { + TypeNode::dump_spec(st); + st->print("%s", _is_unsigned ? "{unsigned_vector_node}" : "{signed_vector_node}"); + } +#endif + virtual uint hash() const { return Node::hash() + _is_unsigned; } + + bool is_unsigned() { return _is_unsigned; } +}; //------------------------------AddVBNode-------------------------------------- // Vector add byte @@ -355,6 +381,22 @@ class SubVLNode : public VectorNode { virtual int Opcode() const; }; +//------------------------------SaturatingAddVNode----------------------------- +// Vector saturating addition. +class SaturatingAddVNode : public SaturatingVectorNode { + public: + SaturatingAddVNode(Node* in1, Node* in2, const TypeVect* vt, bool is_unsigned) : SaturatingVectorNode(in1, in2, vt, is_unsigned) {} + virtual int Opcode() const; +}; + +//------------------------------SaturatingSubVNode----------------------------- +// Vector saturating subtraction. +class SaturatingSubVNode : public SaturatingVectorNode { + public: + SaturatingSubVNode(Node* in1, Node* in2, const TypeVect* vt, bool is_unsigned) : SaturatingVectorNode(in1, in2, vt, is_unsigned) {} + virtual int Opcode() const; +}; + //------------------------------SubVFNode-------------------------------------- // Vector subtract float class SubVFNode : public VectorNode { @@ -561,6 +603,14 @@ class MinVNode : public VectorNode { virtual int Opcode() const; }; +class UMinVNode : public VectorNode { + public: + UMinVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2 ,vt) { + assert(is_integral_type(vt->element_basic_type()), ""); + } + virtual int Opcode() const; +}; + //------------------------------MaxVNode-------------------------------------- // Vector Max class MaxVNode : public VectorNode { @@ -569,6 +619,14 @@ class MaxVNode : public VectorNode { virtual int Opcode() const; }; +class UMaxVNode : public VectorNode { + public: + UMaxVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) { + assert(is_integral_type(vt->element_basic_type()), ""); + } + virtual int Opcode() const; +}; + //------------------------------AbsVINode-------------------------------------- // Vector Abs int class AbsVINode : public VectorNode { @@ -1612,6 +1670,21 @@ class VectorRearrangeNode : public VectorNode { Node* vec_shuffle() const { return in(2); } }; + +// Select elements from two source vectors based on the wrapped indexes held in +// the first vector. +class SelectFromTwoVectorNode : public VectorNode { +public: + SelectFromTwoVectorNode(Node* indexes, Node* src1, Node* src2, const TypeVect* vt) + : VectorNode(indexes, src1, src2, vt) { + assert(is_integral_type(indexes->bottom_type()->is_vect()->element_basic_type()), + "indexes must be an integral vector"); + } + + virtual int Opcode() const; +}; + + class VectorLoadShuffleNode : public VectorNode { public: VectorLoadShuffleNode(Node* in, const TypeVect* vt) diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index e40157caa362b..7c7aca3b90e7c 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -422,8 +422,7 @@ void VTransformScalarNode::print_spec() const { } void VTransformReplicateNode::print_spec() const { - tty->print("vlen=%d element_type=", _vlen); - _element_type->dump(); + tty->print("vlen=%d element_type=%s", _vlen, type2name(_element_type)); } void VTransformShiftCountNode::print_spec() const { diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 071674533a798..ee298e7fe723f 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -354,9 +354,9 @@ class VTransformInputScalarNode : public VTransformScalarNode { class VTransformReplicateNode : public VTransformNode { private: int _vlen; - const Type* _element_type; + BasicType _element_type; public: - VTransformReplicateNode(VTransform& vtransform, int vlen, const Type* element_type) : + VTransformReplicateNode(VTransform& vtransform, int vlen, BasicType element_type) : VTransformNode(vtransform, 2), _vlen(vlen), _element_type(element_type) {} virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, const GrowableArray& vnode_idx_to_transformed_node) const override; diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index a869e9821a0b2..6efe45caf1415 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -3849,6 +3849,9 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae return JNI_ERR; } + // Want this inside 'attaching via jni'. + JFR_ONLY(Jfr::on_thread_start(thread);) + // mark the thread as no longer attaching // this uses a fence to push the change through so we don't have // to regrab the threads_lock @@ -3863,8 +3866,6 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae JvmtiExport::post_thread_start(thread); } - JFR_ONLY(Jfr::on_thread_start(thread);) - *(JNIEnv**)penv = thread->jni_environment(); // Now leaving the VM, so change thread_state. This is normally automatically taken care diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index a246c2c50d674..f0f14a0503162 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -2948,9 +2948,10 @@ JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) // We must release the Threads_lock before we can post a jvmti event // in Thread::start. { + ConditionalMutexLocker throttle_ml(ThreadsLockThrottle_lock, UseThreadsLockThrottleLock); // Ensure that the C++ Thread and OSThread structures aren't freed before // we operate. - MutexLocker mu(Threads_lock); + MutexLocker ml(Threads_lock); // Since JDK 5 the java.lang.Thread threadStatus is used to prevent // re-starting an already started thread, so we should usually find @@ -3277,10 +3278,7 @@ JVM_ENTRY(jobject, JVM_LatestUserDefinedLoader(JNIEnv *env)) InstanceKlass* ik = vfst.method()->method_holder(); oop loader = ik->class_loader(); if (loader != nullptr && !SystemDictionary::is_platform_class_loader(loader)) { - // Skip reflection related frames - if (!ik->is_subclass_of(vmClasses::reflect_SerializationConstructorAccessorImpl_klass())) { - return JNIHandles::make_local(THREAD, loader); - } + return JNIHandles::make_local(THREAD, loader); } } return nullptr; @@ -3943,19 +3941,6 @@ JVM_ENTRY(void, JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean #endif JVM_END -// Always update the temporary VTMS transition bit. -JVM_ENTRY(void, JVM_VirtualThreadHideFrames(JNIEnv* env, jclass clazz, jboolean hide)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - assert(!thread->is_in_VTMS_transition(), "sanity check"); - assert(thread->is_in_tmp_VTMS_transition() != (bool)hide, "sanity check"); - thread->toggle_is_in_tmp_VTMS_transition(); -#endif -JVM_END - // Notification from VirtualThread about disabling JVMTI Suspend in a sync critical section. // Needed to avoid deadlocks with JVMTI suspend mechanism. JVM_ENTRY(void, JVM_VirtualThreadDisableSuspend(JNIEnv* env, jclass clazz, jboolean enter)) diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 167ca557cde31..c28afbb1c51d0 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -584,7 +584,6 @@ JvmtiEnvBase::jvf_for_thread_and_depth(JavaThread* java_thread, jint depth) { javaVFrame *jvf = java_thread->last_java_vframe(®_map); jvf = JvmtiEnvBase::check_and_skip_hidden_frames(java_thread, jvf); - for (int d = 0; jvf != nullptr && d < depth; d++) { jvf = jvf->java_sender(); } @@ -652,22 +651,42 @@ JavaThread* JvmtiEnvBase::get_JavaThread_or_null(oop vthread) { return Continuation::is_continuation_mounted(java_thread, cont) ? java_thread : nullptr; } +// An unmounted vthread may have an empty stack. +// Otherwise, it always has the yield0() and yield() frames we need to hide. +// The methods yield0() and yield() are annotated with the @JvmtiHideEvents. +javaVFrame* +JvmtiEnvBase::skip_yield_frames_for_unmounted_vthread(javaVFrame* jvf) { + if (jvf == nullptr) { + return jvf; // empty stack is possible + } + assert(jvf->method()->jvmti_hide_events(), "sanity check"); + assert(jvf->method()->method_holder() == vmClasses::Continuation_klass(), "expected Continuation class"); + jvf = jvf->java_sender(); // skip yield0 frame + + assert(jvf != nullptr && jvf->method()->jvmti_hide_events(), "sanity check"); + assert(jvf->method()->method_holder() == vmClasses::Continuation_klass(), "expected Continuation class"); + jvf = jvf->java_sender(); // skip yield frame + return jvf; +} + +// A thread may have an empty stack. +// Otherwise, some top frames may heed to be hidden. +// Two cases are processed below: +// - top frame is annotated with @JvmtiMountTransition: just skip top frames with annotated methods +// - JavaThread is in VTMS transition: skip top frames until a frame annotated with @ChangesCurrentThread is found javaVFrame* JvmtiEnvBase::check_and_skip_hidden_frames(bool is_in_VTMS_transition, javaVFrame* jvf) { - // The second condition is needed to hide notification methods. - if (!is_in_VTMS_transition && (jvf == nullptr || !jvf->method()->jvmti_mount_transition())) { - return jvf; // No frames to skip. + if (jvf == nullptr) { + return jvf; // empty stack is possible } - // Find jvf with a method annotated with @JvmtiMountTransition. - for ( ; jvf != nullptr; jvf = jvf->java_sender()) { - if (jvf->method()->jvmti_mount_transition()) { // Cannot actually appear in an unmounted continuation; they're never frozen. - jvf = jvf->java_sender(); // Skip annotated method. - break; + if (jvf->method()->jvmti_mount_transition()) { + // Skip frames annotated with @JvmtiMountTransition. + for ( ; jvf != nullptr && jvf->method()->jvmti_mount_transition(); jvf = jvf->java_sender()) { } - if (jvf->method()->changes_current_thread()) { - break; + } else if (is_in_VTMS_transition) { + // Skip frames above the frame annotated with @ChangesCurrentThread. + for ( ; jvf != nullptr && !jvf->method()->changes_current_thread(); jvf = jvf->java_sender()) { } - // Skip frame above annotated method. } return jvf; } @@ -678,17 +697,6 @@ JvmtiEnvBase::check_and_skip_hidden_frames(JavaThread* jt, javaVFrame* jvf) { return jvf; } -javaVFrame* -JvmtiEnvBase::check_and_skip_hidden_frames(oop vthread, javaVFrame* jvf) { - JvmtiThreadState* state = java_lang_Thread::jvmti_thread_state(vthread); - if (state == nullptr) { - // nothing to skip - return jvf; - } - jvf = check_and_skip_hidden_frames(java_lang_Thread::is_in_VTMS_transition(vthread), jvf); - return jvf; -} - javaVFrame* JvmtiEnvBase::get_vthread_jvf(oop vthread) { assert(java_lang_VirtualThread::state(vthread) != java_lang_VirtualThread::NEW, "sanity check"); @@ -707,12 +715,13 @@ JvmtiEnvBase::get_vthread_jvf(oop vthread) { return nullptr; } vframeStream vfs(java_thread); + assert(!java_thread->is_in_VTMS_transition(), "invariant"); jvf = vfs.at_end() ? nullptr : vfs.asJavaVFrame(); - jvf = check_and_skip_hidden_frames(java_thread, jvf); + jvf = check_and_skip_hidden_frames(false, jvf); } else { vframeStream vfs(cont); jvf = vfs.at_end() ? nullptr : vfs.asJavaVFrame(); - jvf = check_and_skip_hidden_frames(vthread, jvf); + jvf = skip_yield_frames_for_unmounted_vthread(jvf); } return jvf; } @@ -725,11 +734,9 @@ JvmtiEnvBase::get_cthread_last_java_vframe(JavaThread* jt, RegisterMap* reg_map_ bool cthread_with_cont = JvmtiEnvBase::is_cthread_with_continuation(jt); javaVFrame *jvf = cthread_with_cont ? jt->carrier_last_java_vframe(reg_map_p) : jt->last_java_vframe(reg_map_p); - // Skip hidden frames only for carrier threads - // which are in non-temporary VTMS transition. - if (jt->is_in_VTMS_transition()) { - jvf = check_and_skip_hidden_frames(jt, jvf); - } + + // Skip hidden frames for carrier threads only. + jvf = check_and_skip_hidden_frames(jt, jvf); return jvf; } @@ -1332,7 +1339,9 @@ JvmtiEnvBase::set_frame_pop(JvmtiThreadState* state, javaVFrame* jvf, jint depth if (jvf == nullptr) { return JVMTI_ERROR_NO_MORE_FRAMES; } - if (jvf->method()->is_native()) { + if (jvf->method()->is_native() || + (depth == 0 && state->top_frame_is_exiting()) || + (state->is_virtual() && jvf->method()->jvmti_hide_events())) { return JVMTI_ERROR_OPAQUE_FRAME; } assert(jvf->frame_pointer() != nullptr, "frame pointer mustn't be null"); @@ -1989,7 +1998,6 @@ void JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, jthread target) { JavaThread* current = JavaThread::current(); HandleMark hm(current); - JvmtiVTMSTransitionDisabler disabler(target); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; diff --git a/src/hotspot/share/prims/jvmtiEnvBase.hpp b/src/hotspot/share/prims/jvmtiEnvBase.hpp index c6891fdeb1ff0..e8769d423c531 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.hpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.hpp @@ -366,9 +366,9 @@ class JvmtiEnvBase : public CHeapObj { static bool get_field_descriptor(Klass* k, jfieldID field, fieldDescriptor* fd); // check and skip frames hidden in mount/unmount transitions + static javaVFrame* skip_yield_frames_for_unmounted_vthread(javaVFrame* jvf); static javaVFrame* check_and_skip_hidden_frames(bool is_in_VTMS_transition, javaVFrame* jvf); static javaVFrame* check_and_skip_hidden_frames(JavaThread* jt, javaVFrame* jvf); - static javaVFrame* check_and_skip_hidden_frames(oop vthread, javaVFrame* jvf); // check if virtual thread is not terminated (alive) static bool is_vthread_alive(oop vt); diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 95cc54d93134f..b2e9fb9a4ab92 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -929,7 +929,7 @@ 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"); + assert(!_thread->is_in_VTMS_transition(), "CFLH events are not allowed in VTMS transition"); _state = JvmtiExport::get_jvmti_thread_state(_thread); if (_state != nullptr) { @@ -1091,8 +1091,8 @@ bool JvmtiExport::post_class_file_load_hook(Symbol* h_name, return false; } - if (JavaThread::current()->is_in_any_VTMS_transition()) { - return false; // no events should be posted if thread is in any VTMS transition + if (JavaThread::current()->is_in_VTMS_transition()) { + return false; // no events should be posted if thread is in VTMS transition } JvmtiClassFileLoadHookPoster poster(h_name, class_loader, @@ -1228,8 +1228,8 @@ void JvmtiExport::post_raw_breakpoint(JavaThread *thread, Method* method, addres if (state == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_BREAKPOINT, ("[%s] Trg Breakpoint triggered", @@ -1368,8 +1368,8 @@ void JvmtiExport::post_class_load(JavaThread *thread, Klass* klass) { if (state == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_LOAD, ("[%s] Trg Class Load triggered", @@ -1405,8 +1405,8 @@ void JvmtiExport::post_class_prepare(JavaThread *thread, Klass* klass) { if (state == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_PREPARE, ("[%s] Trg Class Prepare triggered", @@ -1743,8 +1743,8 @@ void JvmtiExport::post_object_free(JvmtiEnv* env, GrowableArray* objects) assert(objects != nullptr, "Nothing to post"); JavaThread *javaThread = JavaThread::current(); - if (javaThread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (javaThread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } if (!env->is_enabled(JVMTI_EVENT_OBJECT_FREE)) { return; // the event type has been already disabled @@ -1767,8 +1767,8 @@ void JvmtiExport::post_resource_exhausted(jint resource_exhausted_flags, const c JavaThread *thread = JavaThread::current(); - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } log_error(jvmti)("Posting Resource Exhausted event: %s", @@ -1810,8 +1810,8 @@ void JvmtiExport::post_method_entry(JavaThread *thread, Method* method, frame cu // for any thread that actually wants method entry, interp_only_mode is set return; } - if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_ENTRY, ("[%s] Trg Method Entry triggered %s.%s", JvmtiTrace::safe_get_thread_name(thread), @@ -1874,6 +1874,10 @@ void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame cur } } + // Do not allow NotifyFramePop to add new FramePop event request at + // depth 0 as it is already late in the method exiting dance. + state->set_top_frame_is_exiting(); + // Deferred transition to VM, so we can stash away the return oop before GC // Note that this transition is not needed when throwing an exception, because // there is no oop to retain. @@ -1882,6 +1886,10 @@ void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame cur post_method_exit_inner(thread, mh, state, exception_exit, current_frame, value); JRT_BLOCK_END + // The JRT_BLOCK_END can safepoint in ThreadInVMfromJava desctructor. Now it is safe to allow + // adding FramePop event requests as no safepoint can happen before removing activation. + state->clr_top_frame_is_exiting(); + if (result.not_null() && !mh->is_native()) { // We have to restore the oop on the stack for interpreter frames *(oop*)current_frame.interpreter_frame_tos_address() = result(); @@ -1894,8 +1902,8 @@ void JvmtiExport::post_method_exit_inner(JavaThread* thread, bool exception_exit, frame current_frame, jvalue& value) { - if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_EXIT, ("[%s] Trg Method Exit triggered %s.%s", @@ -1970,8 +1978,8 @@ void JvmtiExport::post_single_step(JavaThread *thread, Method* method, address l if (state == nullptr) { return; } - if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } JvmtiEnvThreadStateIterator it(state); @@ -2012,8 +2020,8 @@ void JvmtiExport::post_exception_throw(JavaThread *thread, Method* method, addre if (state == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_EXCEPTION, ("[%s] Trg Exception thrown triggered", @@ -2134,8 +2142,8 @@ void JvmtiExport::notice_unwind_due_to_exception(JavaThread *thread, Method* met assert(!state->is_exception_caught(), "exception must not be caught yet."); state->set_exception_caught(); - if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } JvmtiEnvThreadStateIterator it(state); for (JvmtiEnvThreadState* ets = it.first(); ets != nullptr; ets = it.next(ets)) { @@ -2180,8 +2188,8 @@ void JvmtiExport::post_field_access_by_jni(JavaThread *thread, oop obj, // function don't make the call unless there is a Java context. assert(thread->has_last_Java_frame(), "must be called with a Java context"); - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } ResourceMark rm; @@ -2216,8 +2224,8 @@ void JvmtiExport::post_field_access(JavaThread *thread, Method* method, if (state == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_FIELD_ACCESS, ("[%s] Trg Field Access event triggered", @@ -2266,8 +2274,8 @@ void JvmtiExport::post_field_modification_by_jni(JavaThread *thread, oop obj, // function don't make the call unless there is a Java context. assert(thread->has_last_Java_frame(), "must be called with Java context"); - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } ResourceMark rm; @@ -2297,8 +2305,8 @@ void JvmtiExport::post_raw_field_modification(JavaThread *thread, Method* method address location, Klass* field_klass, Handle object, jfieldID field, char sig_type, jvalue *value) { - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } if (sig_type == JVM_SIGNATURE_INT || sig_type == JVM_SIGNATURE_BOOLEAN || @@ -2372,8 +2380,8 @@ void JvmtiExport::post_field_modification(JavaThread *thread, Method* method, if (state == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_FIELD_MODIFICATION, @@ -2411,8 +2419,8 @@ void JvmtiExport::post_native_method_bind(Method* method, address* function_ptr) HandleMark hm(thread); methodHandle mh(thread, method); - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_NATIVE_METHOD_BIND, ("[%s] Trg Native Method Bind event triggered", JvmtiTrace::safe_get_thread_name(thread))); @@ -2485,7 +2493,7 @@ void JvmtiExport::post_compiled_method_load(nmethod *nm) { } JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_any_VTMS_transition(), "compiled method load events are not allowed in any VTMS transition"); + assert(!thread->is_in_VTMS_transition(), "compiled method load events are not allowed in VTMS transition"); EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, ("[%s] method compile load event triggered", @@ -2508,7 +2516,7 @@ void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, nmethod *nm) { } JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_any_VTMS_transition(), "compiled method load events are not allowed in any VTMS transition"); + assert(!thread->is_in_VTMS_transition(), "compiled method load events are not allowed in VTMS transition"); EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, ("[%s] method compile load event sent %s.%s ", @@ -2533,7 +2541,7 @@ void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const v JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_any_VTMS_transition(), "dynamic code generated events are not allowed in any VTMS transition"); + assert(!thread->is_in_VTMS_transition(), "dynamic code generated events are not allowed in VTMS transition"); // In theory everyone coming thru here is in_vm but we need to be certain // because a callee will do a vm->native transition @@ -2581,7 +2589,7 @@ void JvmtiExport::post_dynamic_code_generated(JvmtiEnv* env, const char *name, { JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_any_VTMS_transition(), "dynamic code generated events are not allowed in any VTMS transition"); + assert(!thread->is_in_VTMS_transition(), "dynamic code generated events are not allowed in VTMS transition"); EVT_TRIG_TRACE(JVMTI_EVENT_DYNAMIC_CODE_GENERATED, ("[%s] dynamic code generated event triggered (by GenerateEvents)", @@ -2736,8 +2744,8 @@ void JvmtiExport::post_monitor_contended_enter(JavaThread *thread, ObjectMonitor if (state == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_CONTENDED_ENTER, @@ -2769,8 +2777,8 @@ void JvmtiExport::post_monitor_contended_entered(JavaThread *thread, ObjectMonit if (state == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, @@ -2803,8 +2811,8 @@ void JvmtiExport::post_monitor_wait(JavaThread *thread, oop object, if (state == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_WAIT, @@ -2837,8 +2845,8 @@ void JvmtiExport::post_monitor_waited(JavaThread *thread, ObjectMonitor *obj_mnt if (state == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_WAITED, @@ -2866,8 +2874,8 @@ void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) { if (object == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } HandleMark hm(thread); Handle h(thread, object); @@ -2903,8 +2911,8 @@ void JvmtiExport::post_sampled_object_alloc(JavaThread *thread, oop object) { if (object == nullptr) { return; } - if (thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition + if (thread->is_in_VTMS_transition()) { + return; // no events should be posted if thread is in VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, diff --git a/src/hotspot/share/prims/jvmtiImpl.cpp b/src/hotspot/share/prims/jvmtiImpl.cpp index 7b9821fe28a2c..ac7143e02b8ec 100644 --- a/src/hotspot/share/prims/jvmtiImpl.cpp +++ b/src/hotspot/share/prims/jvmtiImpl.cpp @@ -833,11 +833,6 @@ VM_VirtualThreadGetOrSetLocal::VM_VirtualThreadGetOrSetLocal(JvmtiEnv* env, Hand } javaVFrame *VM_VirtualThreadGetOrSetLocal::get_java_vframe() { - Thread* cur_thread = Thread::current(); - oop cont = java_lang_VirtualThread::continuation(_vthread_h()); - assert(cont != nullptr, "vthread contintuation must not be null"); - - javaVFrame* jvf = nullptr; JavaThread* java_thread = JvmtiEnvBase::get_JavaThread_or_null(_vthread_h()); bool is_cont_mounted = (java_thread != nullptr); @@ -845,22 +840,8 @@ javaVFrame *VM_VirtualThreadGetOrSetLocal::get_java_vframe() { _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED; return nullptr; } + javaVFrame* jvf = JvmtiEnvBase::get_vthread_jvf(_vthread_h()); - if (is_cont_mounted) { - vframeStream vfs(java_thread); - - if (!vfs.at_end()) { - jvf = vfs.asJavaVFrame(); - jvf = JvmtiEnvBase::check_and_skip_hidden_frames(java_thread, jvf); - } - } else { - vframeStream vfs(cont); - - if (!vfs.at_end()) { - jvf = vfs.asJavaVFrame(); - jvf = JvmtiEnvBase::check_and_skip_hidden_frames(_vthread_h(), jvf); - } - } int d = 0; while ((jvf != nullptr) && (d < _depth)) { jvf = jvf->java_sender(); diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index 931071c7f00a4..d175aa6c78d1f 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -84,6 +84,7 @@ JvmtiThreadState::JvmtiThreadState(JavaThread* thread, oop thread_oop) _earlyret_value.j = 0L; _earlyret_oop = nullptr; _jvmti_event_queue = nullptr; + _top_frame_is_exiting = false; _is_virtual = false; _thread_oop_h = OopHandle(JvmtiExport::jvmti_oop_storage(), thread_oop); @@ -252,7 +253,7 @@ JvmtiVTMSTransitionDisabler::print_info() { #endif // disable VTMS transitions for one virtual thread -// no-op if thread is non-null and not a virtual thread +// disable VTMS transitions for all threads if thread is nullptr or a platform thread JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread) : _is_SR(false), _thread(thread) { @@ -265,6 +266,17 @@ JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread) if (!sync_protocol_enabled_permanently()) { JvmtiVTMSTransitionDisabler::inc_sync_protocol_enabled_count(); } + oop thread_oop = JNIHandles::resolve_external_guard(thread); + + // Target can be virtual or platform thread. + // If target is a platform thread then we have to disable VTMS transitions for all threads. + // It is by several reasons: + // - carrier threads can mount virtual threads which may cause incorrect behavior + // - there is no mechanism to disable transitions for a specific carrier thread yet + if (!java_lang_VirtualThread::is_instance(thread_oop)) { + _thread = nullptr; // target is a platform thread, switch to disabling VTMS transitions for all threads + } + if (_thread != nullptr) { VTMS_transition_disable_for_one(); // disable VTMS transitions for one virtual thread } else { @@ -315,9 +327,8 @@ JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_one() { JavaThread* thread = JavaThread::current(); HandleMark hm(thread); Handle vth = Handle(thread, JNIHandles::resolve_external_guard(_thread)); - if (!java_lang_VirtualThread::is_instance(vth())) { - return; // no-op if _thread is not a virtual thread - } + assert(java_lang_VirtualThread::is_instance(vth()), "sanity check"); + MonitorLocker ml(JvmtiVTMSTransition_lock); while (_SR_mode) { // suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist @@ -342,7 +353,6 @@ JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_all() { { MonitorLocker ml(JvmtiVTMSTransition_lock); - assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check"); while (_SR_mode) { // Suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist. ml.wait(10); // Wait while there is an active suspender or resumer. @@ -467,7 +477,7 @@ JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_moun JvmtiVTSuspender::is_vthread_suspended(thread_id) ) { // Block while transitions are disabled or there are suspend requests. - if (ml.wait(10)) { + if (ml.wait(200)) { attempts--; } DEBUG_ONLY(if (attempts == 0) break;) @@ -524,7 +534,7 @@ JvmtiVTMSTransitionDisabler::finish_VTMS_transition(jthread vthread, bool is_mou (is_mount && JvmtiVTSuspender::is_vthread_suspended(thread_id)) ) { // Block while there are suspend requests. - if (ml.wait(10)) { + if (ml.wait(200)) { attempts--; } DEBUG_ONLY(if (attempts == 0) break;) @@ -556,7 +566,6 @@ JvmtiVTMSTransitionDisabler::VTMS_vthread_start(jobject vthread) { JavaThread* thread = JavaThread::current(); assert(!thread->is_in_VTMS_transition(), "sanity check"); - assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); // If interp_only_mode has been enabled then we must eagerly create JvmtiThreadState // objects for globally enabled virtual thread filtered events. Otherwise, @@ -582,7 +591,6 @@ JvmtiVTMSTransitionDisabler::VTMS_vthread_end(jobject vthread) { JavaThread* thread = JavaThread::current(); assert(!thread->is_in_VTMS_transition(), "sanity check"); - assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); // post VirtualThreadUnmount event before VirtualThreadEnd if (JvmtiExport::should_post_vthread_unmount()) { @@ -627,7 +635,6 @@ JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(jobject vthread, bool hide) { void JvmtiVTMSTransitionDisabler::VTMS_mount_begin(jobject vthread) { JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); assert(!thread->is_in_VTMS_transition(), "sanity check"); start_VTMS_transition(vthread, /* is_mount */ true); } @@ -640,7 +647,6 @@ JvmtiVTMSTransitionDisabler::VTMS_mount_end(jobject vthread) { thread->rebind_to_jvmti_thread_state_of(vt); assert(thread->is_in_VTMS_transition(), "sanity check"); - assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); finish_VTMS_transition(vthread, /* is_mount */ true); } @@ -648,7 +654,6 @@ void JvmtiVTMSTransitionDisabler::VTMS_unmount_begin(jobject vthread, bool last_unmount) { JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); assert(!thread->is_in_VTMS_transition(), "sanity check"); start_VTMS_transition(vthread, /* is_mount */ false); @@ -661,7 +666,6 @@ void JvmtiVTMSTransitionDisabler::VTMS_unmount_end(jobject vthread) { JavaThread* thread = JavaThread::current(); assert(thread->is_in_VTMS_transition(), "sanity check"); - assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); finish_VTMS_transition(vthread, /* is_mount */ false); } diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 41d52dd2486f4..c9362d5b8cb6e 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -190,6 +190,7 @@ class JvmtiThreadState : public CHeapObj { bool _pending_interp_only_mode; bool _pending_step_for_popframe; bool _pending_step_for_earlyret; + bool _top_frame_is_exiting; int _hide_level; public: @@ -357,6 +358,11 @@ class JvmtiThreadState : public CHeapObj { bool is_pending_step_for_earlyret() { return _pending_step_for_earlyret; } void process_pending_step_for_earlyret(); + // For synchronization between NotifyFramePop and FramePop posting code. + void set_top_frame_is_exiting() { _top_frame_is_exiting = true; } + void clr_top_frame_is_exiting() { _top_frame_is_exiting = false; } + bool top_frame_is_exiting() { return _top_frame_is_exiting; } + // Setter and getter method is used to send redefined class info // when class file load hook event is posted. // It is set while loading redefined class and cleared before the diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 498da559cf526..1e44ea957311e 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -1464,15 +1464,15 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) ThreadToNativeFromVM ttnfv(thread); int status = env->RegisterNatives(MHN_class, MHN_methods, sizeof(MHN_methods)/sizeof(JNINativeMethod)); - guarantee(status == JNI_OK && !env->ExceptionOccurred(), + guarantee(status == JNI_OK && !env->ExceptionCheck(), "register java.lang.invoke.MethodHandleNative natives"); status = env->RegisterNatives(MH_class, MH_methods, sizeof(MH_methods)/sizeof(JNINativeMethod)); - guarantee(status == JNI_OK && !env->ExceptionOccurred(), + guarantee(status == JNI_OK && !env->ExceptionCheck(), "register java.lang.invoke.MethodHandle natives"); status = env->RegisterNatives(VH_class, VH_methods, sizeof(VH_methods)/sizeof(JNINativeMethod)); - guarantee(status == JNI_OK && !env->ExceptionOccurred(), + guarantee(status == JNI_OK && !env->ExceptionCheck(), "register java.lang.invoke.VarHandle natives"); } diff --git a/src/hotspot/share/prims/nativeEntryPoint.cpp b/src/hotspot/share/prims/nativeEntryPoint.cpp index 2dbff08a7cb78..81c6058c11b72 100644 --- a/src/hotspot/share/prims/nativeEntryPoint.cpp +++ b/src/hotspot/share/prims/nativeEntryPoint.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 @@ -116,6 +116,6 @@ static JNINativeMethod NEP_methods[] = { JNI_ENTRY(void, JVM_RegisterNativeEntryPointMethods(JNIEnv *env, jclass NEP_class)) ThreadToNativeFromVM ttnfv(thread); int status = env->RegisterNatives(NEP_class, NEP_methods, sizeof(NEP_methods)/sizeof(JNINativeMethod)); - guarantee(status == JNI_OK && !env->ExceptionOccurred(), + guarantee(status == JNI_OK && !env->ExceptionCheck(), "register jdk.internal.foreign.abi.NativeEntryPoint natives"); JNI_END diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 239ae480030f5..46f9bfc3ef95a 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -669,7 +669,7 @@ static jclass Unsafe_DefineClass_impl(JNIEnv *env, jstring name, jbyteArray data } env->GetByteArrayRegion(data, offset, length, body); - if (env->ExceptionOccurred()) { + if (env->ExceptionCheck()) { goto free_body; } diff --git a/src/hotspot/share/prims/upcallLinker.cpp b/src/hotspot/share/prims/upcallLinker.cpp index b02746911a808..7511e278c69e3 100644 --- a/src/hotspot/share/prims/upcallLinker.cpp +++ b/src/hotspot/share/prims/upcallLinker.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 @@ -22,7 +22,7 @@ */ #include "precompiled.hpp" -#include "classfile/javaClasses.hpp" +#include "classfile/javaClasses.inline.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "compiler/compilationPolicy.hpp" @@ -73,7 +73,7 @@ JavaThread* UpcallLinker::maybe_attach_and_get_thread() { } // modelled after JavaCallWrapper::JavaCallWrapper -JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context, jobject receiver) { +JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context) { JavaThread* thread = maybe_attach_and_get_thread(); guarantee(thread->thread_state() == _thread_in_native, "wrong thread state for upcall"); context->thread = thread; @@ -108,8 +108,6 @@ JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context, jobject recei debug_only(thread->inc_java_call_counter()); thread->set_active_handles(context->new_handles); // install new handle block and reset Java frame linkage - thread->set_vm_result(JNIHandles::resolve(receiver)); - return thread; } @@ -138,11 +136,10 @@ void UpcallLinker::on_exit(UpcallStub::FrameData* context) { } void UpcallLinker::handle_uncaught_exception(oop exception) { - ResourceMark rm; - // Based on CATCH macro tty->print_cr("Uncaught exception:"); - exception->print(); - ShouldNotReachHere(); + Handle exception_h(Thread::current(), exception); + java_lang_Throwable::print_stack_trace(exception_h, tty); + fatal("Unrecoverable uncaught exception encountered"); } JVM_ENTRY(jlong, UL_MakeUpcallStub(JNIEnv *env, jclass unused, jobject mh, jobject abi, jobject conv, @@ -150,36 +147,30 @@ JVM_ENTRY(jlong, UL_MakeUpcallStub(JNIEnv *env, jclass unused, jobject mh, jobje ResourceMark rm(THREAD); Handle mh_h(THREAD, JNIHandles::resolve(mh)); jobject mh_j = JNIHandles::make_global(mh_h); + oop type = java_lang_invoke_MethodHandle::type(mh_h()); - oop lform = java_lang_invoke_MethodHandle::form(mh_h()); - oop vmentry = java_lang_invoke_LambdaForm::vmentry(lform); - Method* entry = java_lang_invoke_MemberName::vmtarget(vmentry); - const methodHandle mh_entry(THREAD, entry); - - assert(entry->method_holder()->is_initialized(), "no clinit barrier"); - CompilationPolicy::compile_if_required(mh_entry, CHECK_0); - - assert(entry->is_static(), "static only"); // Fill in the signature array, for the calling-convention call. - const int total_out_args = entry->size_of_parameters(); - assert(total_out_args > 0, "receiver arg"); + const int total_out_args = java_lang_invoke_MethodType::ptype_slot_count(type) + 1; // +1 for receiver + bool create_new = true; + TempNewSymbol signature = java_lang_invoke_MethodType::as_signature(type, create_new); BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_out_args); BasicType ret_type; { int i = 0; - SignatureStream ss(entry->signature()); + out_sig_bt[i++] = T_OBJECT; // receiver MH + SignatureStream ss(signature); for (; !ss.at_return_type(); ss.next()) { out_sig_bt[i++] = ss.type(); // Collect remaining bits of signature if (ss.type() == T_LONG || ss.type() == T_DOUBLE) out_sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots } - assert(i == total_out_args, ""); + assert(i == total_out_args, "%d != %d", i, total_out_args); ret_type = ss.type(); } return (jlong) UpcallLinker::make_upcall_stub( - mh_j, entry, out_sig_bt, total_out_args, ret_type, + mh_j, signature, out_sig_bt, total_out_args, ret_type, abi, conv, needs_return_buffer, checked_cast(ret_buf_size)); JVM_END @@ -196,6 +187,6 @@ static JNINativeMethod UL_methods[] = { JNI_ENTRY(void, JVM_RegisterUpcallLinkerMethods(JNIEnv *env, jclass UL_class)) ThreadToNativeFromVM ttnfv(thread); int status = env->RegisterNatives(UL_class, UL_methods, sizeof(UL_methods)/sizeof(JNINativeMethod)); - guarantee(status == JNI_OK && !env->ExceptionOccurred(), + guarantee(status == JNI_OK && !env->ExceptionCheck(), "register jdk.internal.foreign.abi.UpcallLinker natives"); JNI_END diff --git a/src/hotspot/share/prims/upcallLinker.hpp b/src/hotspot/share/prims/upcallLinker.hpp index d80516b256678..765ed63fc5a56 100644 --- a/src/hotspot/share/prims/upcallLinker.hpp +++ b/src/hotspot/share/prims/upcallLinker.hpp @@ -34,10 +34,10 @@ class UpcallLinker { private: static JavaThread* maybe_attach_and_get_thread(); - static JavaThread* on_entry(UpcallStub::FrameData* context, jobject receiver); + static JavaThread* on_entry(UpcallStub::FrameData* context); static void on_exit(UpcallStub::FrameData* context); public: - static address make_upcall_stub(jobject mh, Method* entry, + static address make_upcall_stub(jobject mh, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, diff --git a/src/hotspot/share/prims/upcallStubs.cpp b/src/hotspot/share/prims/upcallStubs.cpp index 19737575fcdb5..3c70b671c9d67 100644 --- a/src/hotspot/share/prims/upcallStubs.cpp +++ b/src/hotspot/share/prims/upcallStubs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ static JNINativeMethod UH_methods[] = { */ JVM_LEAF(void, JVM_RegisterUpcallHandlerMethods(JNIEnv *env, jclass UH_class)) int status = env->RegisterNatives(UH_class, UH_methods, sizeof(UH_methods)/sizeof(JNINativeMethod)); - guarantee(status == JNI_OK && !env->ExceptionOccurred(), + guarantee(status == JNI_OK && !env->ExceptionCheck(), "register jdk.internal.foreign.abi.UpcallStubs natives"); JVM_END diff --git a/src/hotspot/share/prims/vectorSupport.cpp b/src/hotspot/share/prims/vectorSupport.cpp index e0517c91e957d..9eb0b46131be0 100644 --- a/src/hotspot/share/prims/vectorSupport.cpp +++ b/src/hotspot/share/prims/vectorSupport.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 @@ -43,7 +43,7 @@ #endif // COMPILER2 #ifdef COMPILER2 -const char* VectorSupport::svmlname[VectorSupport::NUM_SVML_OP] = { +const char* VectorSupport::mathname[VectorSupport::NUM_VECTOR_OP_MATH] = { "tan", "tanh", "sin", @@ -199,6 +199,36 @@ instanceOop VectorSupport::allocate_vector(InstanceKlass* ik, frame* fr, Registe } #ifdef COMPILER2 +bool VectorSupport::has_scalar_op(jint id) { + VectorOperation vop = (VectorOperation)id; + switch (vop) { + case VECTOR_OP_COMPRESS: + case VECTOR_OP_EXPAND: + case VECTOR_OP_SADD: + case VECTOR_OP_SUADD: + case VECTOR_OP_SSUB: + case VECTOR_OP_SUSUB: + case VECTOR_OP_UMIN: + case VECTOR_OP_UMAX: + return false; + default: + return true; + } +} + +bool VectorSupport::is_unsigned_op(jint id) { + VectorOperation vop = (VectorOperation)id; + switch (vop) { + case VECTOR_OP_SUADD: + case VECTOR_OP_SUSUB: + case VECTOR_OP_UMIN: + case VECTOR_OP_UMAX: + return true; + default: + return false; + } +} + int VectorSupport::vop2ideal(jint id, BasicType bt) { VectorOperation vop = (VectorOperation)id; switch (vop) { @@ -274,6 +304,26 @@ int VectorSupport::vop2ideal(jint id, BasicType bt) { } break; } + case VECTOR_OP_UMIN: { + switch (bt) { + case T_BYTE: + case T_SHORT: + case T_INT: + case T_LONG: return Op_UMinV; + default: fatal("MIN: %s", type2name(bt)); + } + break; + } + case VECTOR_OP_UMAX: { + switch (bt) { + case T_BYTE: + case T_SHORT: + case T_INT: + case T_LONG: return Op_UMaxV; + default: fatal("MAX: %s", type2name(bt)); + } + break; + } case VECTOR_OP_ABS: { switch (bt) { case T_BYTE: // fall-through @@ -533,6 +583,28 @@ int VectorSupport::vop2ideal(jint id, BasicType bt) { } break; } + case VECTOR_OP_SADD: + case VECTOR_OP_SUADD: { + switch(bt) { + case T_BYTE: // fall-through + case T_SHORT: // fall-through + case T_INT: // fall-through + case T_LONG: return Op_SaturatingAddV; + default: fatal("S[U]ADD: %s", type2name(bt)); + } + break; + } + case VECTOR_OP_SSUB: + case VECTOR_OP_SUSUB: { + switch(bt) { + case T_BYTE: // fall-through + case T_SHORT: // fall-through + case T_INT: // fall-through + case T_LONG: return Op_SaturatingSubV; + default: fatal("S[U}SUB: %s", type2name(bt)); + } + break; + } case VECTOR_OP_COMPRESS_BITS: { switch (bt) { case T_INT: diff --git a/src/hotspot/share/prims/vectorSupport.hpp b/src/hotspot/share/prims/vectorSupport.hpp index 7302e0060648b..001484874e258 100644 --- a/src/hotspot/share/prims/vectorSupport.hpp +++ b/src/hotspot/share/prims/vectorSupport.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,9 +121,16 @@ class VectorSupport : AllStatic { VECTOR_OP_EXPM1 = 117, VECTOR_OP_HYPOT = 118, - VECTOR_OP_SVML_START = VECTOR_OP_TAN, - VECTOR_OP_SVML_END = VECTOR_OP_HYPOT, - NUM_SVML_OP = VECTOR_OP_SVML_END - VECTOR_OP_SVML_START + 1 + VECTOR_OP_SADD = 119, + VECTOR_OP_SSUB = 120, + VECTOR_OP_SUADD = 121, + VECTOR_OP_SUSUB = 122, + VECTOR_OP_UMIN = 123, + VECTOR_OP_UMAX = 124, + + VECTOR_OP_MATH_START = VECTOR_OP_TAN, + VECTOR_OP_MATH_END = VECTOR_OP_HYPOT, + NUM_VECTOR_OP_MATH = VECTOR_OP_MATH_END - VECTOR_OP_MATH_START + 1 }; enum { @@ -131,7 +138,8 @@ class VectorSupport : AllStatic { VEC_SIZE_128 = 1, VEC_SIZE_256 = 2, VEC_SIZE_512 = 3, - NUM_VEC_SIZES = 4 + VEC_SIZE_SCALABLE = 4, + NUM_VEC_SIZES = 5 }; enum { @@ -139,9 +147,11 @@ class VectorSupport : AllStatic { MODE_BITS_COERCED_LONG_TO_MASK = 1 }; - static const char* svmlname[VectorSupport::NUM_SVML_OP]; + static const char* mathname[VectorSupport::NUM_VECTOR_OP_MATH]; static int vop2ideal(jint vop, BasicType bt); + static bool has_scalar_op(jint id); + static bool is_unsigned_op(jint id); static instanceOop allocate_vector(InstanceKlass* holder, frame* fr, RegisterMap* reg_map, ObjectValue* sv, TRAPS); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index ca440b69913fa..54c5279512ecf 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -424,11 +424,7 @@ WB_ENTRY(jboolean, WB_isObjectInOldGen(JNIEnv* env, jobject o, jobject obj)) #endif #if INCLUDE_ZGC if (UseZGC) { - if (ZGenerational) { - return ZHeap::heap()->is_old(to_zaddress(p)); - } else { - return Universe::heap()->is_in(p); - } + return ZHeap::heap()->is_old(to_zaddress(p)); } #endif #if INCLUDE_SHENANDOAHGC @@ -1751,7 +1747,7 @@ WB_ENTRY(jlong, WB_GetTotalUsedWordsInMetaspaceTestContext(JNIEnv* env, jobject WB_END WB_ENTRY(jlong, WB_CreateArenaInTestContext(JNIEnv* env, jobject wb, jlong context, jboolean is_micro)) - const Metaspace::MetaspaceType type = is_micro ? Metaspace::ReflectionMetaspaceType : Metaspace::StandardMetaspaceType; + const Metaspace::MetaspaceType type = is_micro ? Metaspace::ClassMirrorHolderMetaspaceType : Metaspace::StandardMetaspaceType; metaspace::MetaspaceTestContext* context0 = (metaspace::MetaspaceTestContext*) context; return (jlong)p2i(context0->create_arena(type)); WB_END diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 0d0b58412aefa..bcb6b9190232b 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -85,6 +85,7 @@ char** Arguments::_jvm_flags_array = nullptr; int Arguments::_num_jvm_flags = 0; char** Arguments::_jvm_args_array = nullptr; int Arguments::_num_jvm_args = 0; +unsigned int Arguments::_addmods_count = 0; char* Arguments::_java_command = nullptr; SystemProperty* Arguments::_system_properties = nullptr; size_t Arguments::_conservative_max_heap_alignment = 0; @@ -336,6 +337,15 @@ bool Arguments::is_internal_module_property(const char* property) { return false; } +bool Arguments::is_add_modules_property(const char* key) { + return (strcmp(key, MODULE_PROPERTY_PREFIX ADDMODS) == 0); +} + +// Return true if the key matches the --module-path property name ("jdk.module.path"). +bool Arguments::is_module_path_property(const char* key) { + return (strcmp(key, MODULE_PROPERTY_PREFIX PATH) == 0); +} + // Process java launcher properties. void Arguments::process_sun_java_launcher_properties(JavaVMInitArgs* args) { // See if sun.java.launcher or sun.java.launcher.is_altjvm is defined. @@ -500,7 +510,6 @@ static SpecialFlag const special_jvm_flags[] = { // --- Non-alias flags - sorted by obsolete_in then expired_in: { "AllowRedefinitionToAddDeleteMethods", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() }, { "FlightRecorder", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() }, - { "ZGenerational", JDK_Version::jdk(23), JDK_Version::undefined(), JDK_Version::undefined() }, { "DumpSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "DynamicDumpSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "RequireSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, @@ -516,7 +525,7 @@ static SpecialFlag const special_jvm_flags[] = { // -------------- Obsolete Flags - sorted by expired_in -------------- { "MetaspaceReclaimPolicy", JDK_Version::undefined(), JDK_Version::jdk(21), JDK_Version::undefined() }, - + { "ZGenerational", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::undefined() }, { "UseNotificationThread", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "PreserveAllAnnotations", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "UseEmptySlotsInSupers", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, @@ -1769,7 +1778,6 @@ bool Arguments::sun_java_launcher_is_altjvm() { unsigned int addreads_count = 0; unsigned int addexports_count = 0; unsigned int addopens_count = 0; -unsigned int addmods_count = 0; unsigned int patch_mod_count = 0; unsigned int enable_native_access_count = 0; @@ -1795,7 +1803,7 @@ bool Arguments::check_vm_args_consistency() { PropertyList_unique_add(&_system_properties, "jdk.internal.vm.ci.enabled", "true", AddProperty, UnwriteableProperty, InternalProperty); if (ClassLoader::is_module_observable("jdk.internal.vm.ci")) { - if (!create_numbered_module_property("jdk.module.addmods", "jdk.internal.vm.ci", addmods_count++)) { + if (!create_numbered_module_property("jdk.module.addmods", "jdk.internal.vm.ci", _addmods_count++)) { return false; } } @@ -1804,7 +1812,7 @@ bool Arguments::check_vm_args_consistency() { #if INCLUDE_JFR if (status && (FlightRecorderOptions || StartFlightRecording)) { - if (!create_numbered_module_property("jdk.module.addmods", "jdk.jfr", addmods_count++)) { + if (!create_numbered_module_property("jdk.module.addmods", "jdk.jfr", _addmods_count++)) { return false; } } @@ -1817,17 +1825,6 @@ bool Arguments::check_vm_args_consistency() { } #endif -#if !defined(X86) && !defined(AARCH64) && !defined(RISCV64) && !defined(ARM) && !defined(PPC64) && !defined(S390) - if (LockingMode == LM_LIGHTWEIGHT) { - FLAG_SET_CMDLINE(LockingMode, LM_LEGACY); - warning("New lightweight locking not supported on this platform"); - } - if (UseObjectMonitorTable) { - FLAG_SET_CMDLINE(UseObjectMonitorTable, false); - warning("UseObjectMonitorTable not supported on this platform"); - } -#endif - if (UseObjectMonitorTable && LockingMode != LM_LIGHTWEIGHT) { // ObjectMonitorTable requires lightweight locking. FLAG_SET_CMDLINE(UseObjectMonitorTable, false); @@ -2242,7 +2239,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m return JNI_ENOMEM; } } else if (match_option(option, "--add-modules=", &tail)) { - if (!create_numbered_module_property("jdk.module.addmods", tail, addmods_count++)) { + if (!create_numbered_module_property("jdk.module.addmods", tail, _addmods_count++)) { return JNI_ENOMEM; } } else if (match_option(option, "--enable-native-access=", &tail)) { @@ -2329,7 +2326,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m FREE_C_HEAP_ARRAY(char, options); // java agents need module java.instrument - if (!create_numbered_module_property("jdk.module.addmods", "java.instrument", addmods_count++)) { + if (!create_numbered_module_property("jdk.module.addmods", "java.instrument", _addmods_count++)) { return JNI_ENOMEM; } } @@ -2510,7 +2507,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m return JNI_EINVAL; } // management agent in module jdk.management.agent - if (!create_numbered_module_property("jdk.module.addmods", "jdk.management.agent", addmods_count++)) { + if (!create_numbered_module_property("jdk.module.addmods", "jdk.management.agent", _addmods_count++)) { return JNI_ENOMEM; } #else diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 8251db3d0d59a..ac842285fd8a4 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -196,6 +196,8 @@ class Arguments : AllStatic { static int _num_jvm_args; // string containing all java command (class/jarfile name and app args) static char* _java_command; + // number of unique modules specified in the --add-modules option + static unsigned int _addmods_count; // Property list static SystemProperty* _system_properties; @@ -461,6 +463,9 @@ class Arguments : AllStatic { static int PropertyList_readable_count(SystemProperty* pl); static bool is_internal_module_property(const char* option); + static bool is_add_modules_property(const char* key); + static unsigned int addmods_count() { return _addmods_count; } + static bool is_module_path_property(const char* key); // Miscellaneous System property value getter and setters. static void set_dll_dir(const char *value) { _sun_boot_library_path->set_value(value); } diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp index 30abd575da46a..1090241c3e1f0 100644 --- a/src/hotspot/share/runtime/basicLock.inline.hpp +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -39,7 +39,7 @@ inline void BasicLock::set_displaced_header(markWord header) { inline ObjectMonitor* BasicLock::object_monitor_cache() const { assert(UseObjectMonitorTable, "must be"); -#if defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390) +#if !defined(ZERO) && (defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390)) return reinterpret_cast(get_metadata()); #else // Other platforms do not make use of the cache yet, diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp index cd55b4a9cff16..fb697dd4920dd 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -428,5 +428,5 @@ void CONT_RegisterNativeMethods(JNIEnv *env, jclass cls) { ThreadToNativeFromVM trans(thread); int status = env->RegisterNatives(cls, CONT_methods, sizeof(CONT_methods)/sizeof(JNINativeMethod)); guarantee(status == JNI_OK, "register jdk.internal.vm.Continuation natives"); - guarantee(!env->ExceptionOccurred(), "register jdk.internal.vm.Continuation natives"); + guarantee(!env->ExceptionCheck(), "register jdk.internal.vm.Continuation natives"); } diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index e36b252362b78..ce2e2bdb9ff80 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -1442,9 +1442,7 @@ stackChunkOop Freeze::allocate_chunk(size_t stack_size, int argsize_md) #if INCLUDE_ZGC if (UseZGC) { - if (ZGenerational) { - ZStackChunkGCData::initialize(chunk); - } + ZStackChunkGCData::initialize(chunk); assert(!chunk->requires_barriers(), "ZGC always allocates in the young generation"); _barriers = false; } else diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index e193271eff658..17078a69ab991 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -719,6 +719,8 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose st->print("v ~MethodHandlesAdapterBlob " PTR_FORMAT, p2i(pc())); } else if (_cb->is_uncommon_trap_stub()) { st->print("v ~UncommonTrapBlob " PTR_FORMAT, p2i(pc())); + } else if (_cb->is_upcall_stub()) { + st->print("v ~UpcallStub::%s " PTR_FORMAT, _cb->name(), p2i(pc())); } else { st->print("v blob " PTR_FORMAT, p2i(pc())); } @@ -1116,6 +1118,19 @@ void frame::oops_entry_do(OopClosure* f, const RegisterMap* map) const { entry_frame_call_wrapper()->oops_do(f); } +void frame::oops_upcall_do(OopClosure* f, const RegisterMap* map) const { + assert(map != nullptr, "map must be set"); + if (map->include_argument_oops()) { + // Upcall stubs call a MethodHandle impl method of which only the receiver + // is ever an oop. + // Currently we should not be able to get here, since there are no + // safepoints in the one resolve stub we can get into (handle_wrong_method) + // Leave this here as a trap in case we ever do: + ShouldNotReachHere(); // not implemented + } + _cb->as_upcall_stub()->oops_do(f, *this); +} + bool frame::is_deoptimized_frame() const { assert(_deopt_state != unknown, "not answerable"); if (_deopt_state == is_deoptimized) { @@ -1147,7 +1162,7 @@ void frame::oops_do_internal(OopClosure* f, NMethodClosure* cf, } else if (is_entry_frame()) { oops_entry_do(f, map); } else if (is_upcall_stub_frame()) { - _cb->as_upcall_stub()->oops_do(f, *this); + oops_upcall_do(f, map); } else if (CodeCache::contains(pc())) { oops_nmethod_do(f, cf, df, derived_mode, map); } else { diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index 1c57e3de4daa6..50aafce3837ac 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.hpp @@ -464,6 +464,7 @@ class frame { const RegisterMap* map, bool use_interpreter_oop_map_cache) const; void oops_entry_do(OopClosure* f, const RegisterMap* map) const; + void oops_upcall_do(OopClosure* f, const RegisterMap* map) const; void oops_nmethod_do(OopClosure* f, NMethodClosure* cf, DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, const RegisterMap* map) const; diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 2bcc26043cd96..b568e76930476 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1991,6 +1991,10 @@ const int ObjectAlignmentInBytes = 8; \ product(bool, StressSecondarySupers, false, DIAGNOSTIC, \ "Use a terrible hash function in order to generate many collisions.") \ + \ + product(bool, UseThreadsLockThrottleLock, true, DIAGNOSTIC, \ + "Use an extra lock during Thread start and exit to alleviate" \ + "contention on Threads_lock.") \ // end of RUNTIME_FLAGS diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index 3919a89789cc0..20399452eb9af 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, 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 @@ -251,8 +251,13 @@ class VM_HandshakeAllThreads: public VM_Operation { thr->handshake_state()->add_operation(_op); number_of_threads_issued++; } + + // Separate the arming of the poll in add_operation() above from + // the read of JavaThread state in the try_process() call below. if (UseSystemMemoryBarrier) { SystemMemoryBarrier::emit(); + } else { + OrderAccess::fence(); } if (number_of_threads_issued < 1) { @@ -380,6 +385,8 @@ void Handshake::execute(HandshakeClosure* hs_cl, ThreadsListHandle* tlh, JavaThr // the read of JavaThread state in the try_process() call below. if (UseSystemMemoryBarrier) { SystemMemoryBarrier::emit(); + } else { + OrderAccess::fence(); } // Keeps count on how many of own emitted handshakes @@ -559,6 +566,10 @@ bool HandshakeState::process_by_self(bool allow_suspend, bool check_async_except // Threads shouldn't block if they are in the middle of printing, but... ttyLocker::break_tty_lock_for_safepoint(os::current_thread_id()); + // Separate all the writes above for other threads reading state + // set by this thread in case the operation is ThreadSuspendHandshake. + OrderAccess::fence(); + while (has_operation()) { // Handshakes cannot safely safepoint. The exceptions to this rule are // the asynchronous suspension and unsafe access error handshakes. diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 14528f6d908fc..285c2de17fa26 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -446,7 +446,6 @@ JavaThread::JavaThread(MemTag mem_tag) : #if INCLUDE_JVMTI _carrier_thread_suspended(false), _is_in_VTMS_transition(false), - _is_in_tmp_VTMS_transition(false), _is_disable_suspend(false), _VTMS_transition_mark(false), #ifdef ASSERT diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 20bb08a4acbca..249a1e4dc8739 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -238,8 +238,6 @@ class JavaThread: public Thread { // Safepoint support public: // Expose _thread_state for SafeFetchInt() volatile JavaThreadState _thread_state; - private: - SafepointMechanism::ThreadData _poll_data; ThreadSafepointState* _safepoint_state; // Holds information about a thread during a safepoint address _saved_exception_pc; // Saved pc of instruction where last implicit exception happened NOT_PRODUCT(bool _requires_cross_modify_fence;) // State used by VerifyCrossModifyFence @@ -313,7 +311,6 @@ class JavaThread: public Thread { #if INCLUDE_JVMTI volatile bool _carrier_thread_suspended; // Carrier thread is externally suspended bool _is_in_VTMS_transition; // thread is in virtual thread mount state transition - bool _is_in_tmp_VTMS_transition; // thread is in temporary virtual thread mount state transition bool _is_disable_suspend; // JVMTI suspend is temporarily disabled; used on current thread only bool _VTMS_transition_mark; // used for sync between VTMS transitions and disablers #ifdef ASSERT @@ -598,6 +595,22 @@ class JavaThread: public Thread { SafepointMechanism::ThreadData* poll_data() { return &_poll_data; } + static ByteSize polling_word_offset() { + ByteSize offset = byte_offset_of(Thread, _poll_data) + + byte_offset_of(SafepointMechanism::ThreadData, _polling_word); + // At least on x86_64, safepoint polls encode the offset as disp8 imm. + assert(in_bytes(offset) < 128, "Offset >= 128"); + return offset; + } + + static ByteSize polling_page_offset() { + ByteSize offset = byte_offset_of(Thread, _poll_data) + + byte_offset_of(SafepointMechanism::ThreadData, _polling_page); + // At least on x86_64, safepoint polls encode the offset as disp8 imm. + assert(in_bytes(offset) < 128, "Offset >= 128"); + return offset; + } + void set_requires_cross_modify_fence(bool val) PRODUCT_RETURN NOT_PRODUCT({ _requires_cross_modify_fence = val; }) // Continuation support @@ -661,11 +674,7 @@ class JavaThread: public Thread { } bool is_in_VTMS_transition() const { return _is_in_VTMS_transition; } - bool is_in_tmp_VTMS_transition() const { return _is_in_tmp_VTMS_transition; } - bool is_in_any_VTMS_transition() const { return _is_in_VTMS_transition || _is_in_tmp_VTMS_transition; } - void set_is_in_VTMS_transition(bool val); - void toggle_is_in_tmp_VTMS_transition() { _is_in_tmp_VTMS_transition = !_is_in_tmp_VTMS_transition; }; bool is_disable_suspend() const { return _is_disable_suspend; } void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; }; @@ -787,8 +796,6 @@ class JavaThread: public Thread { static ByteSize vm_result_offset() { return byte_offset_of(JavaThread, _vm_result); } static ByteSize vm_result_2_offset() { return byte_offset_of(JavaThread, _vm_result_2); } static ByteSize thread_state_offset() { return byte_offset_of(JavaThread, _thread_state); } - static ByteSize polling_word_offset() { return byte_offset_of(JavaThread, _poll_data) + byte_offset_of(SafepointMechanism::ThreadData, _polling_word);} - static ByteSize polling_page_offset() { return byte_offset_of(JavaThread, _poll_data) + byte_offset_of(SafepointMechanism::ThreadData, _polling_page);} static ByteSize saved_exception_pc_offset() { return byte_offset_of(JavaThread, _saved_exception_pc); } static ByteSize osthread_offset() { return byte_offset_of(JavaThread, _osthread); } #if INCLUDE_JVMCI @@ -839,7 +846,6 @@ class JavaThread: public Thread { #if INCLUDE_JVMTI static ByteSize is_in_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_VTMS_transition); } - static ByteSize is_in_tmp_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_tmp_VTMS_transition); } static ByteSize is_disable_suspend_offset() { return byte_offset_of(JavaThread, _is_disable_suspend); } #endif diff --git a/src/hotspot/share/runtime/lightweightSynchronizer.cpp b/src/hotspot/share/runtime/lightweightSynchronizer.cpp index 5037bb9607b5d..7cf7c201faf74 100644 --- a/src/hotspot/share/runtime/lightweightSynchronizer.cpp +++ b/src/hotspot/share/runtime/lightweightSynchronizer.cpp @@ -635,8 +635,11 @@ void LightweightSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* bool entered = monitor->enter_for(locking_thread); assert(entered, "recursive ObjectMonitor::enter_for must succeed"); } else { - // It is assumed that enter_for must enter on an object without contention. - monitor = inflate_and_enter(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, locking_thread, current); + do { + // It is assumed that enter_for must enter on an object without contention. + monitor = inflate_and_enter(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, locking_thread, current); + // But there may still be a race with deflation. + } while (monitor == nullptr); } assert(monitor != nullptr, "LightweightSynchronizer::enter_for must succeed"); diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index a0ba783c36408..76d0674e8c6f8 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -36,7 +36,6 @@ // Mutexes used in the VM (see comment in mutexLocker.hpp): -Mutex* Patching_lock = nullptr; Mutex* NMethodState_lock = nullptr; Monitor* SystemDictionary_lock = nullptr; Mutex* InvokeMethodTypeTable_lock = nullptr; @@ -66,6 +65,7 @@ Monitor* CodeCache_lock = nullptr; Mutex* TouchedMethodLog_lock = nullptr; Mutex* RetData_lock = nullptr; Monitor* VMOperation_lock = nullptr; +Monitor* ThreadsLockThrottle_lock = nullptr; Monitor* Threads_lock = nullptr; Mutex* NonJavaThreadsList_lock = nullptr; Mutex* NonJavaThreadsListSync_lock = nullptr; @@ -135,6 +135,7 @@ Mutex* SharedDecoder_lock = nullptr; Mutex* DCmdFactory_lock = nullptr; Mutex* NMTQuery_lock = nullptr; Mutex* NMTCompilationCostHistory_lock = nullptr; +Mutex* NmtVirtualMemory_lock = nullptr; #if INCLUDE_CDS #if INCLUDE_JVMTI @@ -232,7 +233,6 @@ void mutex_init() { MUTEX_DEFN(Metaspace_lock , PaddedMutex , nosafepoint-3); MUTEX_DEFN(MetaspaceCritical_lock , PaddedMonitor, nosafepoint-1); - MUTEX_DEFN(Patching_lock , PaddedMutex , nosafepoint); // used for safepointing and code patching. MUTEX_DEFN(MonitorDeflation_lock , PaddedMonitor, nosafepoint); // used for monitor deflation thread operations MUTEX_DEFN(Service_lock , PaddedMonitor, service); // used for service thread operations MUTEX_DEFN(Notification_lock , PaddedMonitor, service); // used for notification thread operations @@ -294,10 +294,11 @@ void mutex_init() { MUTEX_DEFN(CodeHeapStateAnalytics_lock , PaddedMutex , safepoint); MUTEX_DEFN(ThreadsSMRDelete_lock , PaddedMonitor, service-2); // Holds ConcurrentHashTableResize_lock MUTEX_DEFN(ThreadIdTableCreate_lock , PaddedMutex , safepoint); - MUTEX_DEFN(SharedDecoder_lock , PaddedMutex , tty-1); + MUTEX_DEFN(SharedDecoder_lock , PaddedMutex , service-5); // Must be lower than NmtVirtualMemory_lock due to MemTracker::print_containing_region MUTEX_DEFN(DCmdFactory_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(NMTQuery_lock , PaddedMutex , safepoint); MUTEX_DEFN(NMTCompilationCostHistory_lock , PaddedMutex , nosafepoint); + MUTEX_DEFN(NmtVirtualMemory_lock , PaddedMutex , service-4); #if INCLUDE_CDS #if INCLUDE_JVMTI MUTEX_DEFN(CDSClassFileStream_lock , PaddedMutex , safepoint); @@ -317,6 +318,8 @@ void mutex_init() { MUTEX_DEFN(JVMCIRuntime_lock , PaddedMonitor, safepoint, true); #endif + MUTEX_DEFN(ThreadsLockThrottle_lock , PaddedMonitor, safepoint); + // These locks have relative rankings, and inherit safepoint checking attributes from that rank. MUTEX_DEFL(VtableStubs_lock , PaddedMutex , CompiledIC_lock); // Also holds DumpTimeTable_lock MUTEX_DEFL(CodeCache_lock , PaddedMonitor, VtableStubs_lock); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 3da859585019b..07bea6b614d89 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -28,10 +28,10 @@ #include "memory/allocation.hpp" #include "runtime/flags/flagSetting.hpp" #include "runtime/mutex.hpp" +#include "runtime/thread.hpp" // Mutexes used in the VM. -extern Mutex* Patching_lock; // a lock used to guard code patching of compiled code extern Mutex* NMethodState_lock; // a lock used to guard a compiled method state extern Monitor* SystemDictionary_lock; // a lock on the system dictionary extern Mutex* InvokeMethodTypeTable_lock; @@ -61,6 +61,8 @@ extern Monitor* CodeCache_lock; // a lock on the CodeCache extern Mutex* TouchedMethodLog_lock; // a lock on allocation of LogExecutedMethods info extern Mutex* RetData_lock; // a lock on installation of RetData inside method data extern Monitor* VMOperation_lock; // a lock on queue of vm_operations waiting to execute +extern Monitor* ThreadsLockThrottle_lock; // used by Thread start/exit to reduce competition for Threads_lock, + // so a VM thread calling a safepoint is prioritized extern Monitor* Threads_lock; // a lock on the Threads table of active Java threads // (also used by Safepoints too to block threads creation/destruction) extern Mutex* NonJavaThreadsList_lock; // a lock on the NonJavaThreads list @@ -114,6 +116,7 @@ extern Mutex* SharedDecoder_lock; // serializes access to the dec extern Mutex* DCmdFactory_lock; // serialize access to DCmdFactory information extern Mutex* NMTQuery_lock; // serialize NMT Dcmd queries extern Mutex* NMTCompilationCostHistory_lock; // guards NMT compilation cost history +extern Mutex* NmtVirtualMemory_lock; // guards NMT virtual memory updates #if INCLUDE_CDS #if INCLUDE_JVMTI extern Mutex* CDSClassFileStream_lock; // FileMapInfo::open_stream_for_jvmti diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 755d49d2c6c58..3ea987801db6a 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -1133,6 +1133,14 @@ void ObjectMonitor::UnlinkAfterAcquire(JavaThread* current, ObjectWaiter* curren // or drain _cxq, we need to reacquire the lock before we can wake up // (unpark) a waiting thread. // +// Note that we read the EntryList and then the cxq after dropping the +// lock, so the values need not form a stable snapshot. In particular, +// after reading the (empty) EntryList, another thread could acquire +// and release the lock, moving any entries in the cxq to the +// EntryList, causing the current thread to see an empty cxq and +// conclude there are no waiters. But this is okay as the thread that +// moved the cxq is responsible for waking the successor. +// // The CAS() in enter provides for safety and exclusion, while the // MEMBAR in exit provides for progress and avoids stranding. // diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 8b1c52a5d33cc..2395510f27f81 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1290,7 +1290,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { } // Check if in metaspace and print types that have vptrs - if (Metaspace::contains(addr)) { + if (Metaspace::initialized() && Metaspace::contains(addr)) { if (Klass::is_valid((Klass*)addr)) { st->print_cr(INTPTR_FORMAT " is a pointer to class: ", p2i(addr)); ((Klass*)addr)->print_on(st); @@ -2166,7 +2166,7 @@ bool os::uncommit_memory(char* addr, size_t bytes, bool executable) { assert_nonempty_range(addr, bytes); bool res; if (MemTracker::enabled()) { - ThreadCritical tc; + NmtVirtualMemoryLocker ml; res = pd_uncommit_memory(addr, bytes, executable); if (res) { MemTracker::record_virtual_memory_uncommit((address)addr, bytes); @@ -2188,7 +2188,7 @@ bool os::release_memory(char* addr, size_t bytes) { assert_nonempty_range(addr, bytes); bool res; if (MemTracker::enabled()) { - ThreadCritical tc; + NmtVirtualMemoryLocker ml; res = pd_release_memory(addr, bytes); if (res) { MemTracker::record_virtual_memory_release((address)addr, bytes); @@ -2273,7 +2273,7 @@ char* os::map_memory(int fd, const char* file_name, size_t file_offset, bool os::unmap_memory(char *addr, size_t bytes) { bool result; if (MemTracker::enabled()) { - ThreadCritical tc; + NmtVirtualMemoryLocker ml; result = pd_unmap_memory(addr, bytes); if (result) { MemTracker::record_virtual_memory_release((address)addr, bytes); @@ -2312,7 +2312,7 @@ char* os::reserve_memory_special(size_t size, size_t alignment, size_t page_size bool os::release_memory_special(char* addr, size_t bytes) { bool res; if (MemTracker::enabled()) { - ThreadCritical tc; + NmtVirtualMemoryLocker ml; res = pd_release_memory_special(addr, bytes); if (res) { MemTracker::record_virtual_memory_release((address)addr, bytes); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 35a5be77b6058..323b8d2df8dbe 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -668,6 +668,13 @@ class os: AllStatic { static void flockfile(FILE* fp); static void funlockfile(FILE* fp); + // A safe implementation of realpath which will not cause a buffer overflow if the resolved path + // is longer than PATH_MAX. + // On success, returns 'outbuf', which now contains the path. + // On error, it will return null and set errno. The content of 'outbuf' is undefined. + // On truncation error ('outbuf' too small), it will return null and set errno to ENAMETOOLONG. + static char* realpath(const char* filename, char* outbuf, size_t outbuflen); + static int compare_file_modified_times(const char* file1, const char* file2); static bool same_files(const char* file1, const char* file2); @@ -939,7 +946,7 @@ class os: AllStatic { // provided buffer as a scratch buffer. The status message which will be written // into the error log either is file location or a short error message, depending // on the checking result. - static void check_dump_limit(char* buffer, size_t bufferSize); + static void check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only = false); // Get the default path to the core file // Returns the length of the string diff --git a/src/hotspot/share/runtime/osThread.hpp b/src/hotspot/share/runtime/osThread.hpp index b0e0588a6a2b6..597cf8e4d3fcb 100644 --- a/src/hotspot/share/runtime/osThread.hpp +++ b/src/hotspot/share/runtime/osThread.hpp @@ -25,111 +25,8 @@ #ifndef SHARE_RUNTIME_OSTHREAD_HPP #define SHARE_RUNTIME_OSTHREAD_HPP -#include "runtime/frame.hpp" -#include "runtime/handles.hpp" -#include "runtime/javaFrameAnchor.hpp" -#include "runtime/objectMonitor.hpp" -#include "runtime/suspendedThreadTask.hpp" #include "utilities/macros.hpp" - -#if defined(LINUX) || defined(AIX) || defined(BSD) -#include "suspendResume_posix.hpp" -#endif - -class Monitor; - -// The OSThread class holds OS-specific thread information. It is equivalent -// to the sys_thread_t structure of the classic JVM implementation. - -// The thread states represented by the ThreadState values are platform-specific -// and are likely to be only approximate, because most OSes don't give you access -// to precise thread state information. - -// Note: the ThreadState is legacy code and is not correctly implemented. -// Uses of ThreadState need to be replaced by the state in the JavaThread. - -enum ThreadState { - ALLOCATED, // Memory has been allocated but not initialized - INITIALIZED, // The thread has been initialized but yet started - RUNNABLE, // Has been started and is runnable, but not necessarily running - MONITOR_WAIT, // Waiting on a contended monitor lock - CONDVAR_WAIT, // Waiting on a condition variable - OBJECT_WAIT, // Waiting on an Object.wait() call - BREAKPOINTED, // Suspended at breakpoint - SLEEPING, // Thread.sleep() - ZOMBIE // All done, but not reclaimed yet -}; - -typedef int (*OSThreadStartFunc)(void*); - -class OSThread: public CHeapObj { - friend class VMStructs; - friend class JVMCIVMStructs; - private: - volatile ThreadState _state; // Thread state *hint* - - // Methods - public: - void set_state(ThreadState state) { _state = state; } - ThreadState get_state() { return _state; } - - OSThread(); - ~OSThread(); - - // Printing - void print_on(outputStream* st) const; - void print() const; - - // Platform dependent stuff +// The actual class declaration is platform specific. #include OS_HEADER(osThread) - public: - - thread_id_t thread_id() const { return _thread_id; } - - void set_thread_id(thread_id_t id) { _thread_id = id; } - - private: - // _thread_id is kernel thread id (similar to LWP id on Solaris). Each - // thread has a unique thread_id (BsdThreads or NPTL). It can be used - // to access /proc. - thread_id_t _thread_id; -}; - - -// Utility class for use with condition variables: -class OSThreadWaitState : public StackObj { - OSThread* _osthread; - ThreadState _old_state; - public: - OSThreadWaitState(OSThread* osthread, bool is_object_wait) { - _osthread = osthread; - _old_state = osthread->get_state(); - if (is_object_wait) { - osthread->set_state(OBJECT_WAIT); - } else { - osthread->set_state(CONDVAR_WAIT); - } - } - ~OSThreadWaitState() { - _osthread->set_state(_old_state); - } -}; - - -// Utility class for use with contended monitors: -class OSThreadContendState : public StackObj { - OSThread* _osthread; - ThreadState _old_state; - public: - OSThreadContendState(OSThread* osthread) { - _osthread = osthread; - _old_state = osthread->get_state(); - osthread->set_state(MONITOR_WAIT); - } - ~OSThreadContendState() { - _osthread->set_state(_old_state); - } -}; - #endif // SHARE_RUNTIME_OSTHREAD_HPP diff --git a/src/hotspot/share/runtime/osThread.cpp b/src/hotspot/share/runtime/osThreadBase.cpp similarity index 87% rename from src/hotspot/share/runtime/osThread.cpp rename to src/hotspot/share/runtime/osThreadBase.cpp index edaefaa1070d2..7bb7ae6aa69f8 100644 --- a/src/hotspot/share/runtime/osThread.cpp +++ b/src/hotspot/share/runtime/osThreadBase.cpp @@ -24,19 +24,11 @@ #include "precompiled.hpp" #include "oops/oop.inline.hpp" -#include "runtime/osThread.hpp" - -OSThread::OSThread() { - pd_initialize(); -} - -OSThread::~OSThread() { - pd_destroy(); -} +#include "runtime/osThreadBase.hpp" // Printing -void OSThread::print_on(outputStream *st) const { - st->print("nid=" UINT64_FORMAT " ", (uint64_t)thread_id()); +void OSThreadBase::print_on(outputStream *st) const { + st->print("nid=" UINTX_FORMAT " ", thread_id_for_printing()); switch (_state) { case ALLOCATED: st->print("allocated "); break; case INITIALIZED: st->print("initialized "); break; @@ -51,4 +43,4 @@ void OSThread::print_on(outputStream *st) const { } } -void OSThread::print() const { print_on(tty); } +void OSThreadBase::print() const { print_on(tty); } diff --git a/src/hotspot/share/runtime/osThreadBase.hpp b/src/hotspot/share/runtime/osThreadBase.hpp new file mode 100644 index 0000000000000..4063da18519d5 --- /dev/null +++ b/src/hotspot/share/runtime/osThreadBase.hpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_OSTHREAD_BASE_HPP +#define SHARE_RUNTIME_OSTHREAD_BASE_HPP + +#include "memory/allocation.hpp" + +class Monitor; + +// The OSThread class holds OS-specific thread information. It is equivalent +// to the sys_thread_t structure of the classic JVM implementation. + +// The thread states represented by the ThreadState values are platform-specific +// and are likely to be only approximate, because most OSes don't give you access +// to precise thread state information. + +// Note: the ThreadState is legacy code and is not correctly implemented. +// Uses of ThreadState need to be replaced by the state in the JavaThread. + +enum ThreadState { + ALLOCATED, // Memory has been allocated but not initialized + INITIALIZED, // The thread has been initialized but yet started + RUNNABLE, // Has been started and is runnable, but not necessarily running + MONITOR_WAIT, // Waiting on a contended monitor lock + CONDVAR_WAIT, // Waiting on a condition variable + OBJECT_WAIT, // Waiting on an Object.wait() call + BREAKPOINTED, // Suspended at breakpoint + SLEEPING, // Thread.sleep() + ZOMBIE // All done, but not reclaimed yet +}; + +typedef int (*OSThreadStartFunc)(void*); + +class OSThreadBase: public CHeapObj { + friend class VMStructs; + friend class JVMCIVMStructs; + private: + volatile ThreadState _state; // Thread state *hint* + + // Methods + public: + OSThreadBase() {} + virtual ~OSThreadBase() {} + NONCOPYABLE(OSThreadBase); + + void set_state(ThreadState state) { _state = state; } + ThreadState get_state() { return _state; } + + + virtual uintx thread_id_for_printing() const = 0; + + // Printing + void print_on(outputStream* st) const; + void print() const; +}; + + +// Utility class for use with condition variables: +class OSThreadWaitState : public StackObj { + OSThreadBase* _osthread; + ThreadState _old_state; + public: + OSThreadWaitState(OSThreadBase* osthread, bool is_object_wait) { + _osthread = osthread; + _old_state = osthread->get_state(); + if (is_object_wait) { + osthread->set_state(OBJECT_WAIT); + } else { + osthread->set_state(CONDVAR_WAIT); + } + } + ~OSThreadWaitState() { + _osthread->set_state(_old_state); + } +}; + + +// Utility class for use with contended monitors: +class OSThreadContendState : public StackObj { + OSThreadBase* _osthread; + ThreadState _old_state; + public: + OSThreadContendState(OSThreadBase* osthread) { + _osthread = osthread; + _old_state = osthread->get_state(); + osthread->set_state(MONITOR_WAIT); + } + ~OSThreadContendState() { + _osthread->set_state(_old_state); + } +}; + +#endif // SHARE_RUNTIME_OSTHREAD_BASE_HPP diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index 15172b7f4c3d8..97fc26a599f7e 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -448,12 +448,6 @@ Reflection::VerifyClassAccessResults Reflection::verify_class_access( is_same_class_package(current_class, new_class)) { return ACCESS_OK; } - // Allow all accesses from jdk/internal/reflect/SerializationConstructorAccessorImpl subclasses to - // succeed trivially. - if (vmClasses::reflect_SerializationConstructorAccessorImpl_klass_is_loaded() && - current_class->is_subclass_of(vmClasses::reflect_SerializationConstructorAccessorImpl_klass())) { - return ACCESS_OK; - } // module boundaries if (new_class->is_public()) { @@ -658,12 +652,6 @@ bool Reflection::verify_member_access(const Klass* current_class, } } - // Allow all accesses from jdk/internal/reflect/SerializationConstructorAccessorImpl subclasses to - // succeed trivially. - if (current_class->is_subclass_of(vmClasses::reflect_SerializationConstructorAccessorImpl_klass())) { - return true; - } - // Check for special relaxations return can_relax_access_check_for(current_class, member_class, classloader_only); } diff --git a/src/hotspot/share/runtime/sharedRuntimeTrans.cpp b/src/hotspot/share/runtime/sharedRuntimeTrans.cpp index 491705d8d7f06..5285819ee963d 100644 --- a/src/hotspot/share/runtime/sharedRuntimeTrans.cpp +++ b/src/hotspot/share/runtime/sharedRuntimeTrans.cpp @@ -26,6 +26,9 @@ #include "jni.h" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/sharedRuntime.hpp" +#include "sanitizers/ub.hpp" + +#include // This file contains copies of the fdlibm routines used by // StrictMath. It turns out that it is almost always required to use @@ -110,11 +113,14 @@ ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ static double zero = 0.0; +ATTRIBUTE_NO_UBSAN static double __ieee754_log(double x) { double hfsq,f,s,z,R,w,t1,t2,dk; int k,hx,i,j; unsigned lx; + static_assert(std::numeric_limits::is_iec559, "IEEE 754 required"); + hx = high(x); /* high word of x */ lx = low(x); /* low word of x */ @@ -204,11 +210,14 @@ ivln10 = 4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */ log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */ log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ +ATTRIBUTE_NO_UBSAN static double __ieee754_log10(double x) { double y,z; int i,k,hx; unsigned lx; + static_assert(std::numeric_limits::is_iec559, "IEEE 754 required"); + hx = high(x); /* high word of x */ lx = low(x); /* low word of x */ @@ -440,6 +449,7 @@ bp[] = {1.0, 1.5,}, ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ +ATTRIBUTE_NO_UBSAN static double __ieee754_pow(double x, double y) { double z,ax,z_h,z_l,p_h,p_l; double y1,t1,t2,r,s,t,u,v,w; @@ -447,6 +457,8 @@ static double __ieee754_pow(double x, double y) { int hx,hy,ix,iy; unsigned lx,ly; + static_assert(std::numeric_limits::is_iec559, "IEEE 754 required"); + i0 = ((*(int*)&one)>>29)^1; i1=1-i0; hx = high(x); lx = low(x); hy = high(y); ly = low(y); diff --git a/src/hotspot/share/runtime/statSampler.cpp b/src/hotspot/share/runtime/statSampler.cpp index 5fd038bf845c1..bbd8d3096bba0 100644 --- a/src/hotspot/share/runtime/statSampler.cpp +++ b/src/hotspot/share/runtime/statSampler.cpp @@ -201,7 +201,8 @@ void StatSampler::assert_system_property(const char* name, const char* value, TR // convert Java String to utf8 string char* system_value = java_lang_String::as_utf8_string(value_oop); - assert(strcmp(value, system_value) == 0, "property value mustn't differ from System.getProperty"); + assert(strcmp(value, system_value) == 0, "property value mustn't differ from System.getProperty. Our value is: %s, System.getProperty is: %s", + value, system_value); #endif // ASSERT } diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index a2b8c1da64490..c881b64b59280 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -176,8 +176,8 @@ address StubRoutines::_dtanh = nullptr; address StubRoutines::_f2hf = nullptr; address StubRoutines::_hf2f = nullptr; -address StubRoutines::_vector_f_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP] = {{nullptr}, {nullptr}}; -address StubRoutines::_vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP] = {{nullptr}, {nullptr}}; +address StubRoutines::_vector_f_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_VECTOR_OP_MATH] = {{nullptr}, {nullptr}}; +address StubRoutines::_vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_VECTOR_OP_MATH] = {{nullptr}, {nullptr}}; address StubRoutines::_method_entry_barrier = nullptr; address StubRoutines::_array_sort = nullptr; @@ -188,6 +188,7 @@ address StubRoutines::_cont_returnBarrier = nullptr; address StubRoutines::_cont_returnBarrierExc = nullptr; address StubRoutines::_upcall_stub_exception_handler = nullptr; +address StubRoutines::_upcall_stub_load_target = nullptr; address StubRoutines::_lookup_secondary_supers_table_slow_path_stub = nullptr; address StubRoutines::_lookup_secondary_supers_table_stubs[Klass::SECONDARY_SUPERS_TABLE_SIZE] = { nullptr }; diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index b58c591bbf75c..f025742b60585 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -294,10 +294,11 @@ class StubRoutines: AllStatic { static address _cont_returnBarrierExc; // Vector Math Routines - static address _vector_f_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP]; - static address _vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP]; + static address _vector_f_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_VECTOR_OP_MATH]; + static address _vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_VECTOR_OP_MATH]; static address _upcall_stub_exception_handler; + static address _upcall_stub_load_target; static address _lookup_secondary_supers_table_stubs[]; static address _lookup_secondary_supers_table_slow_path_stub; @@ -506,6 +507,11 @@ class StubRoutines: AllStatic { return _upcall_stub_exception_handler; } + static address upcall_stub_load_target() { + assert(_upcall_stub_load_target != nullptr, "not implemented"); + return _upcall_stub_load_target; + } + static address lookup_secondary_supers_table_stub(u1 slot) { assert(slot < Klass::SECONDARY_SUPERS_TABLE_SIZE, "out of bounds"); assert(_lookup_secondary_supers_table_stubs[slot] != nullptr, "not implemented"); diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index df6a660a0aa21..b02166ce681b9 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -62,8 +62,6 @@ THREAD_LOCAL Thread* Thread::_thr_current = nullptr; // Base class for all threads: VMThread, WatcherThread, ConcurrentMarkSweepThread, // JavaThread -DEBUG_ONLY(Thread* Thread::_starting_thread = nullptr;) - Thread::Thread(MemTag mem_tag) { DEBUG_ONLY(_run_state = PRE_CALL_RUN;) @@ -538,14 +536,22 @@ void Thread::print_owned_locks_on(outputStream* st) const { } } } + +Thread* Thread::_starting_thread = nullptr; + +bool Thread::is_starting_thread(const Thread* t) { + assert(_starting_thread != nullptr, "invariant"); + return t == _starting_thread; +} #endif // ASSERT -bool Thread::set_as_starting_thread() { +bool Thread::set_as_starting_thread(JavaThread* jt) { + assert(jt != nullptr, "invariant"); assert(_starting_thread == nullptr, "already initialized: " "_starting_thread=" INTPTR_FORMAT, p2i(_starting_thread)); - // NOTE: this must be called inside the main thread. - DEBUG_ONLY(_starting_thread = this;) - return os::create_main_thread(JavaThread::cast(this)); + // NOTE: this must be called from Threads::create_vm(). + DEBUG_ONLY(_starting_thread = jt;) + return os::create_main_thread(jt); } // Ad-hoc mutual exclusion primitives: SpinLock diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 45c39eae151d2..82f31ece47903 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -33,6 +33,7 @@ #include "runtime/atomic.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" +#include "runtime/safepointMechanism.hpp" #include "runtime/threadHeapSampler.hpp" #include "runtime/threadLocalStorage.hpp" #include "runtime/threadStatisticalInfo.hpp" @@ -109,6 +110,7 @@ class Thread: public ThreadShadow { friend class VMErrorCallbackMark; friend class VMStructs; friend class JVMCIVMStructs; + friend class JavaThread; private: #ifndef USE_LIBRARY_BASED_TLS_ONLY @@ -135,6 +137,11 @@ class Thread: public ThreadShadow { } private: + // Poll data is used in generated code for safepoint polls. + // It is important for performance to put this at lower offset + // in Thread. The accessors are in JavaThread. + SafepointMechanism::ThreadData _poll_data; + // Thread local data area available to the GC. The internal // structure and contents of this data area is GC-specific. // Only GC and GC barrier code should access this data area. @@ -156,9 +163,6 @@ class Thread: public ThreadShadow { // const char* _exception_file; // file information for exception (debugging only) // int _exception_line; // line information for exception (debugging only) protected: - - DEBUG_ONLY(static Thread* _starting_thread;) - // JavaThread lifecycle support: friend class SafeThreadsListPtr; // for _threads_list_ptr, cmpxchg_threads_hazard_ptr(), {dec_,inc_,}nested_threads_hazard_ptr_cnt(), {g,s}et_threads_hazard_ptr(), inc_nested_handle_cnt(), tag_hazard_ptr() access friend class ScanHazardPtrGatherProtectedThreadsClosure; // for cmpxchg_threads_hazard_ptr(), get_threads_hazard_ptr(), is_hazard_ptr_tagged() access @@ -204,12 +208,15 @@ class Thread: public ThreadShadow { static bool is_JavaThread_protected_by_TLH(const JavaThread* target); private: + DEBUG_ONLY(static Thread* _starting_thread;) DEBUG_ONLY(bool _suspendible_thread;) DEBUG_ONLY(bool _indirectly_suspendible_thread;) DEBUG_ONLY(bool _indirectly_safepoint_thread;) public: #ifdef ASSERT + static bool is_starting_thread(const Thread* t); + void set_suspendible_thread() { _suspendible_thread = true; } void clear_suspendible_thread() { _suspendible_thread = false; } bool is_suspendible_thread() { return _suspendible_thread; } @@ -493,9 +500,9 @@ class Thread: public ThreadShadow { return is_in_stack_range_incl(adr, os::current_stack_pointer()); } - // Sets this thread as starting thread. Returns failure if thread + // Sets the argument thread as starting thread. Returns failure if thread // creation fails due to lack of memory, too many threads etc. - bool set_as_starting_thread(); + static bool set_as_starting_thread(JavaThread* jt); protected: // OS data associated with the thread diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 8266bd86a9682..76ee237ae5ebe 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -65,6 +65,7 @@ #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" @@ -165,6 +166,9 @@ static void create_initial_thread(Handle thread_group, JavaThread* thread, string, CHECK); + JFR_ONLY(assert(JFR_JVM_THREAD_ID(thread) == static_cast(java_lang_Thread::thread_id(thread_oop())), + "initial tid mismatch");) + // Set thread status to running since main thread has // been started and running. java_lang_Thread::set_thread_status(thread_oop(), @@ -531,7 +535,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { main_thread->set_active_handles(JNIHandleBlock::allocate_block()); MACOS_AARCH64_ONLY(main_thread->init_wx()); - if (!main_thread->set_as_starting_thread()) { + if (!Thread::set_as_starting_thread(main_thread)) { vm_shutdown_during_initialization( "Failed necessary internal allocation. Out of swap space"); main_thread->smr_delete(); @@ -539,6 +543,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { return JNI_ENOMEM; } + JFR_ONLY(Jfr::initialize_main_thread(main_thread);) + // Enable guard page *after* os::create_main_thread(), otherwise it would // crash Linux VM, see notes in os_linux.cpp. main_thread->stack_overflow_state()->create_stack_guard_pages(); @@ -665,6 +671,11 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { log_info(os)("Initialized VM with process ID %d", os::current_process_id()); + if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && CreateCoredumpOnCrash) { + char buffer[2*JVM_MAXPATHLEN]; + os::check_core_dump_prerequisites(buffer, sizeof(buffer), true); + } + // Signal Dispatcher needs to be started before VMInit event is posted os::initialize_jdk_signal_support(CHECK_JNI_ERR); @@ -1028,7 +1039,9 @@ void Threads::add(JavaThread* p, bool force_daemon) { void Threads::remove(JavaThread* p, bool is_daemon) { // Extra scope needed for Thread_lock, so we can check // that we do not remove thread without safepoint code notice - { MonitorLocker ml(Threads_lock); + { + ConditionalMutexLocker throttle_ml(ThreadsLockThrottle_lock, UseThreadsLockThrottleLock); + MonitorLocker ml(Threads_lock); if (ThreadIdTable::is_initialized()) { // This cleanup must be done before the current thread's GC barrier @@ -1076,7 +1089,7 @@ void Threads::remove(JavaThread* p, bool is_daemon) { // Notify threads waiting in EscapeBarriers EscapeBarrier::thread_removed(p); - } // unlock Threads_lock + } // unlock Threads_lock and ThreadsLockThrottle_lock // Reduce the ObjectMonitor ceiling for the exiting thread. ObjectSynchronizer::dec_in_use_list_ceiling(); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index e0a36330687dc..3060e225427a8 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1590,7 +1590,6 @@ declare_c2_type(StorePNode, StoreNode) \ declare_c2_type(StoreNNode, StoreNode) \ declare_c2_type(StoreNKlassNode, StoreNode) \ - declare_c2_type(StoreCMNode, StoreNode) \ declare_c2_type(SCMemProjNode, ProjNode) \ declare_c2_type(LoadStoreNode, Node) \ declare_c2_type(CompareAndSwapNode, LoadStoreConditionalNode) \ diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp index 36931531a4e02..90f5930cce0a9 100644 --- a/src/hotspot/share/services/attachListener.cpp +++ b/src/hotspot/share/services/attachListener.cpp @@ -50,6 +50,38 @@ volatile AttachListenerState AttachListener::_state = AL_NOT_INITIALIZED; +AttachAPIVersion AttachListener::_supported_version = ATTACH_API_V1; + +static bool get_bool_sys_prop(const char* name, bool default_value, TRAPS) { + ResourceMark rm(THREAD); + HandleMark hm(THREAD); + + // setup the arguments to getProperty + Handle key_str = java_lang_String::create_from_str(name, CHECK_(default_value)); + // return value + JavaValue result(T_OBJECT); + // public static String getProperty(String key, String def); + JavaCalls::call_static(&result, + vmClasses::System_klass(), + vmSymbols::getProperty_name(), + vmSymbols::string_string_signature(), + key_str, + CHECK_(default_value)); + oop value_oop = result.get_oop(); + if (value_oop != nullptr) { + // convert Java String to utf8 string + char* value = java_lang_String::as_utf8_string(value_oop); + if (strcasecmp(value, "true") == 0) { + return true; + } + if (strcasecmp(value, "false") == 0) { + return false; + } + } + return default_value; +} + + // Implementation of "properties" command. // // Invokes VMSupport.serializePropertiesToByteArray to serialize @@ -351,6 +383,12 @@ static jint print_flag(AttachOperation* op, outputStream* out) { return JNI_OK; } +// Implementation of "getversion" command +static jint get_version(AttachOperation* op, outputStream* out) { + out->print("%d", (int)AttachListener::get_supported_version()); + return JNI_OK; +} + // Table to map operation names to functions. // names must be of length <= AttachOperation::name_length_max @@ -365,6 +403,7 @@ static AttachOperationFunctionInfo funcs[] = { { "setflag", set_flag }, { "printflag", print_flag }, { "jcmd", jcmd }, + { "getversion", get_version }, { nullptr, nullptr } }; @@ -472,3 +511,175 @@ void AttachListener::detachall() { // call the platform dependent clean-up pd_detachall(); } + +void AttachListener::set_supported_version(AttachAPIVersion version) { +// _supported_version = version; + const char* prop_name = "jdk.attach.compat"; + if (!get_bool_sys_prop(prop_name, false, JavaThread::current())) { + _supported_version = version; + } +} + +AttachAPIVersion AttachListener::get_supported_version() { + return _supported_version; +} + + +int AttachOperation::RequestReader::read_uint() { + const int MAX_VALUE = INT_MAX / 20; + char ch; + int value = 0; + while (true) { + int n = read(&ch, 1); + if (n != 1) { + // IO errors (n < 0) are logged by read(). + if (n == 0) { // EOF + log_error(attach)("Failed to read int value: EOF"); + } + return -1; + } + if (ch == '\0') { + return value; + } + if (ch < '0' || ch > '9') { + log_error(attach)("Failed to read int value: unexpected symbol: %c", ch); + return -1; + } + // Ensure there is no integer overflow. + if (value >= MAX_VALUE) { + log_error(attach)("Failed to read int value: too big"); + return -1; + } + value = value * 10 + (ch - '0'); + } +} + +// Reads operation name and arguments. +// buffer_size: maximum data size; +// min_str_count: minimum number of strings in the request (name + arguments); +// min_read_size: minimum data size. +bool AttachOperation::read_request_data(AttachOperation::RequestReader* reader, + int buffer_size, int min_str_count, int min_read_size) { + char* buffer = (char*)os::malloc(buffer_size, mtServiceability); + int str_count = 0; + int off = 0; + int left = buffer_size; + + // Read until all (expected) strings or expected bytes have been read, the buffer is full, or EOF. + do { + int n = reader->read(buffer + off, left); + if (n < 0) { + os::free(buffer); + return false; + } + if (n == 0) { // EOF + break; + } + if (min_str_count > 0) { // need to count arguments + for (int i = 0; i < n; i++) { + if (buffer[off + i] == '\0') { + str_count++; + } + } + } + off += n; + left -= n; + } while (left > 0 && (off < min_read_size || str_count < min_str_count)); + + if (off < min_read_size || str_count < min_str_count) { // unexpected EOF + log_error(attach)("Failed to read request: incomplete request"); + os::free(buffer); + return false; + } + // Request must ends with '\0'. + if (buffer[off - 1] != '\0') { + log_error(attach)("Failed to read request: not terminated"); + os::free(buffer); + return false; + } + + // Parse request. + // Command name is the 1st string. + set_name(buffer); + log_debug(attach)("read request: cmd = %s", buffer); + + // Arguments. + char* end = buffer + off; + for (char* cur = strchr(buffer, '\0') + 1; cur < end; cur = strchr(cur, '\0') + 1) { + log_debug(attach)("read request: arg = %s", cur); + append_arg(cur); + } + + os::free(buffer); + + return true; +} + +bool AttachOperation::read_request(RequestReader* reader) { + uint ver = reader->read_uint(); + int buffer_size = 0; + // Read conditions: + int min_str_count = 0; // expected number of strings in the request + int min_read_size = 1; // expected size of the request data (by default 1 symbol for terminating '\0') + switch (ver) { + case ATTACH_API_V1: // 00000 + // Always contain a command (up to name_length_max chars) + // and arg_count_max(3) arguments (each up to arg_length_max chars). + buffer_size = (name_length_max + 1) + arg_count_max * (arg_length_max + 1); + min_str_count = 1 /*name*/ + arg_count_max; + break; + case ATTACH_API_V2: // 000000 + if (AttachListener::get_supported_version() < 2) { + log_error(attach)("Failed to read request: v2 is unsupported ot disabled"); + return false; + } + + // read size of the data + buffer_size = reader->read_uint(); + if (buffer_size < 0) { + return false; + } + log_debug(attach)("v2 request, data size = %d", buffer_size); + + // Sanity check: max request size is 256K. + if (buffer_size > 256 * 1024) { + log_error(attach)("Failed to read request: too big"); + return false; + } + // Must contain exact 'buffer_size' bytes. + min_read_size = buffer_size; + break; + default: + log_error(attach)("Failed to read request: unknown version (%d)", ver); + return false; + } + + return read_request_data(reader, buffer_size, min_str_count, min_read_size); +} + +bool AttachOperation::ReplyWriter::write_fully(const void* buffer, int size) { + const char* buf = (const char*)buffer; + do { + int n = write(buf, size); + if (n < 0) { + return false; + } + buf += n; + size -= n; + } while (size > 0); + return true; +} + +bool AttachOperation::write_reply(ReplyWriter* writer, jint result, bufferedStream* result_stream) { + char msg[32]; + os::snprintf_checked(msg, sizeof(msg), "%d\n", result); + if (!writer->write_fully(msg, (int)strlen(msg))) { + return false; + } + if (!writer->write_fully(result_stream->base(), (int)result_stream->size())) { + return false; + } + writer->flush(); + return true; +} + diff --git a/src/hotspot/share/services/attachListener.hpp b/src/hotspot/share/services/attachListener.hpp index c49f996cdb438..093fa410d123e 100644 --- a/src/hotspot/share/services/attachListener.hpp +++ b/src/hotspot/share/services/attachListener.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include "utilities/debug.hpp" #include "utilities/exceptions.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/growableArray.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" @@ -59,6 +60,20 @@ enum AttachListenerState { AL_INITIALIZED }; +/* +Version 1 (since jdk6): attach operations always have 3 (AttachOperation::arg_count_max) + arguments, each up to 1024 (AttachOperation::arg_length_max) chars. +Version 2 (since jdk24): attach operations may have any number of arguments of any length; + for safety default implementation restricts attach operation request size by 256KB. + To detect if target VM supports version 2, client sends "getversion" command. + Old VM reports "Operation not recognized" error, newer VM reports version supported by the implementation. + If the target VM does not support version 2, client uses version 1 to enqueue operations. +*/ +enum AttachAPIVersion: int { + ATTACH_API_V1 = 1, + ATTACH_API_V2 = 2 +}; + class AttachListenerThread : public JavaThread { private: static void thread_entry(JavaThread* thread, TRAPS); @@ -93,7 +108,12 @@ class AttachListener: AllStatic { private: static volatile AttachListenerState _state; + static AttachAPIVersion _supported_version; + public: + static void set_supported_version(AttachAPIVersion version); + static AttachAPIVersion get_supported_version(); + static void set_state(AttachListenerState new_state) { Atomic::store(&_state, new_state); } @@ -136,8 +156,9 @@ class AttachListener: AllStatic { }; #if INCLUDE_SERVICES -class AttachOperation: public CHeapObj { - public: +class AttachOperation: public CHeapObj { +public: + // v1 constants enum { name_length_max = 16, // maximum length of name arg_length_max = 1024, // maximum length of argument @@ -148,51 +169,100 @@ class AttachOperation: public CHeapObj { // clients detach static char* detachall_operation_name() { return (char*)"detachall"; } - private: - char _name[name_length_max+1]; - char _arg[arg_count_max][arg_length_max+1]; +private: + char* _name; + GrowableArrayCHeap _args; - public: - const char* name() const { return _name; } + static char* copy_str(const char* value) { + return value == nullptr ? nullptr : os::strdup(value, mtServiceability); + } + +public: + const char* name() const { return _name; } // set the operation name void set_name(const char* name) { - assert(strlen(name) <= name_length_max, "exceeds maximum name length"); - size_t len = MIN2(strlen(name), (size_t)name_length_max); - memcpy(_name, name, len); - _name[len] = '\0'; + os::free(_name); + _name = copy_str(name); + } + + int arg_count() const { + return _args.length(); } // get an argument value const char* arg(int i) const { - assert(i>=0 && i= _args.length() || _args.at(i) == nullptr) { + static char empty_str[] = ""; + return empty_str; + } + return _args.at(i); + } + + // appends an argument + void append_arg(const char* arg) { + _args.append(copy_str(arg)); } // set an argument value - void set_arg(int i, char* arg) { - assert(i>=0 && i it = _args.begin(); it != _args.end(); ++it) { + os::free(*it); + } + } + // complete operation by sending result code and any result data to the client virtual void complete(jint result, bufferedStream* result_stream) = 0; + + // Helper classes/methods for platform-specific implementations. + class RequestReader { + public: + // Returns number of bytes read, + // 0 on EOF, negative value on error. + virtual int read(void* buffer, int size) = 0; + + // Reads unsigned value, returns -1 on error. + int read_uint(); + }; + + // Reads standard operation request (v1 or v2). + bool read_request(RequestReader* reader); + + class ReplyWriter { + public: + // Returns number of bytes written, negative value on error. + virtual int write(const void* buffer, int size) = 0; + + virtual void flush() {} + + bool write_fully(const void* buffer, int size); + }; + + // Writes standard operation reply (to be called from 'complete' method). + bool write_reply(ReplyWriter* writer, jint result, bufferedStream* result_stream); + +private: + bool read_request_data(AttachOperation::RequestReader* reader, int buffer_size, int min_str_count, int min_read_size); + }; + #endif // INCLUDE_SERVICES #endif // SHARE_SERVICES_ATTACHLISTENER_HPP diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 78c655a43fcf2..ac711520065b9 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -52,7 +52,6 @@ #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/handles.inline.hpp" -#include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/jniHandles.hpp" #include "runtime/os.hpp" @@ -160,11 +159,6 @@ void DCmd::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags, true,false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags, true,false)); - // Debug on cmd (only makes sense with JVMTI since the agentlib needs it). -#if INCLUDE_JVMTI - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, true)); -#endif // INCLUDE_JVMTI - #if INCLUDE_CDS DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); #endif // INCLUDE_CDS @@ -1058,45 +1052,6 @@ void DumpSharedArchiveDCmd::execute(DCmdSource source, TRAPS) { } #endif // INCLUDE_CDS -#if INCLUDE_JVMTI -extern "C" typedef char const* (JNICALL *debugInit_startDebuggingViaCommandPtr)(JNIEnv* env, jthread thread, char const** transport_name, - char const** address, jboolean* first_start); -static debugInit_startDebuggingViaCommandPtr dvc_start_ptr = nullptr; - -void DebugOnCmdStartDCmd::execute(DCmdSource source, TRAPS) { - char const* transport = nullptr; - char const* addr = nullptr; - jboolean is_first_start = JNI_FALSE; - JavaThread* thread = THREAD; - jthread jt = JNIHandles::make_local(thread->threadObj()); - ThreadToNativeFromVM ttn(thread); - const char *error = "Could not find jdwp agent."; - - if (!dvc_start_ptr) { - JvmtiAgentList::Iterator it = JvmtiAgentList::agents(); - while (it.has_next()) { - JvmtiAgent* agent = it.next(); - if ((strcmp("jdwp", agent->name()) == 0) && (dvc_start_ptr == nullptr)) { - char const* func = "debugInit_startDebuggingViaCommand"; - dvc_start_ptr = (debugInit_startDebuggingViaCommandPtr) os::find_agent_function(agent, false, &func, 1); - } - } - } - - if (dvc_start_ptr) { - error = dvc_start_ptr(thread->jni_environment(), jt, &transport, &addr, &is_first_start); - } - - if (error != nullptr) { - output()->print_cr("Debugging has not been started: %s", error); - } else { - output()->print_cr(is_first_start ? "Debugging has been started." : "Debugging is already active."); - output()->print_cr("Transport : %s", transport ? transport : "#unknown"); - output()->print_cr("Address : %s", addr ? addr : "#unknown"); - } -} -#endif // INCLUDE_JVMTI - ThreadDumpToFileDCmd::ThreadDumpToFileDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), _overwrite("-overwrite", "May overwrite existing file", "BOOLEAN", false, "false"), @@ -1202,12 +1157,10 @@ void SystemDumpMapDCmd::execute(DCmdSource source, TRAPS) { output()->print_cr("(NMT is disabled, will not annotate mappings)."); } MemMapPrinter::print_all_mappings(&fs); -#ifndef _WIN64 // For the readers convenience, resolve path name. char tmp[JVM_MAXPATHLEN]; - const char* absname = os::Posix::realpath(name, tmp, sizeof(tmp)); + const char* absname = os::realpath(name, tmp, sizeof(tmp)); name = absname != nullptr ? absname : name; -#endif output()->print_cr("Memory map dumped to \"%s\".", name); } else { output()->print_cr("Failed to open \"%s\" for writing (%s).", name, os::strerror(errno)); diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp index 99b5a3510645a..c8e26504ece83 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -886,27 +886,6 @@ class ClassesDCmd : public DCmdWithParser { virtual void execute(DCmdSource source, TRAPS); }; -#if INCLUDE_JVMTI -class DebugOnCmdStartDCmd : public DCmd { -public: - DebugOnCmdStartDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} - static const char* name() { - return "VM.start_java_debugging"; - } - static const char* description() { - return "Starts up the Java debugging if the jdwp agentlib was enabled with the option onjcmd=y."; - } - static const char* impact() { - return "High: Switches the VM into Java debug mode."; - } - static const JavaPermission permission() { - JavaPermission p = { "java.lang.management.ManagementPermission", "control", nullptr }; - return p; - } - virtual void execute(DCmdSource source, TRAPS); -}; -#endif // INCLUDE_JVMTI - class EventLogDCmd : public DCmdWithParser { protected: DCmdArgument _log; diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 119d1cf17fd2d..88730c1e6ec9c 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -725,10 +725,22 @@ void disarm_assert_poison() { static void store_context(const void* context) { memcpy(&g_stored_assertion_context, context, sizeof(ucontext_t)); -#if defined(LINUX) && defined(PPC64) +#if defined(LINUX) // on Linux ppc64, ucontext_t contains pointers into itself which have to be patched up // after copying the context (see comment in sys/ucontext.h): +#if defined(PPC64) *((void**) &g_stored_assertion_context.uc_mcontext.regs) = &(g_stored_assertion_context.uc_mcontext.gp_regs); +#elif defined(AMD64) + // In the copied version, fpregs should point to the copied contents. + // Sanity check: fpregs should point into the context. + if ((address)((const ucontext_t*)context)->uc_mcontext.fpregs > (address)context) { + size_t fpregs_offset = pointer_delta(((const ucontext_t*)context)->uc_mcontext.fpregs, context, 1); + if (fpregs_offset < sizeof(ucontext_t)) { + // Preserve the offset. + *((void**) &g_stored_assertion_context.uc_mcontext.fpregs) = (void*)((address)(void*)&g_stored_assertion_context + fpregs_offset); + } + } +#endif #endif } diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 6d385165b8b1b..25af626c6286b 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -210,7 +210,7 @@ FORBID_C_FUNCTION(char* strdup(const char *s), "use os::strdup"); FORBID_C_FUNCTION(char* strndup(const char *s, size_t n), "don't use"); FORBID_C_FUNCTION(int posix_memalign(void **memptr, size_t alignment, size_t size), "don't use"); FORBID_C_FUNCTION(void* aligned_alloc(size_t alignment, size_t size), "don't use"); -FORBID_C_FUNCTION(char* realpath(const char* path, char* resolved_path), "use os::Posix::realpath"); +FORBID_C_FUNCTION(char* realpath(const char* path, char* resolved_path), "use os::realpath"); FORBID_C_FUNCTION(char* get_current_dir_name(void), "use os::get_current_directory()"); FORBID_C_FUNCTION(char* getwd(char *buf), "use os::get_current_directory()"); FORBID_C_FUNCTION(wchar_t* wcsdup(const wchar_t *s), "don't use"); diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index 1034dec0d9aaa..23094c9e8c4ac 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -338,6 +338,7 @@ #define NOT_PRODUCT_ARG(arg) #define PRODUCT_RETURN {} #define PRODUCT_RETURN0 { return 0; } +#define PRODUCT_RETURN_NULL { return nullptr; } #define PRODUCT_RETURN_(code) { code } #else // PRODUCT #define PRODUCT_ONLY(code) @@ -345,6 +346,7 @@ #define NOT_PRODUCT_ARG(arg) arg, #define PRODUCT_RETURN /*next token must be ;*/ #define PRODUCT_RETURN0 /*next token must be ;*/ +#define PRODUCT_RETURN_NULL /* next token must be ;*/ #define PRODUCT_RETURN_(code) /*next token must be ;*/ #endif // PRODUCT diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 0b3ccf9c747aa..0df77689a048f 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.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. * Copyright (c) 2017, 2020 SAP SE. All rights reserved. * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -717,6 +717,10 @@ void VMError::report(outputStream* st, bool _verbose) { address lastpc = nullptr; BEGIN + if (MemTracker::enabled() && NmtVirtualMemory_lock != nullptr && NmtVirtualMemory_lock->owned_by_self()) { + // Manually unlock to avoid reentrancy due to mallocs in detailed mode. + NmtVirtualMemory_lock->unlock(); + } STEP("printing fatal error message") st->print_cr("#"); @@ -1696,7 +1700,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt ShowMessageBoxOnError = false; } - os::check_dump_limit(buffer, sizeof(buffer)); + os::check_core_dump_prerequisites(buffer, sizeof(buffer)); // reset signal handlers or exception filter; make sure recursive crashes // are handled properly. @@ -1862,7 +1866,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt if (DumpReplayDataOnError && _thread && _thread->is_Compiler_thread() && !skip_replay) { skip_replay = true; ciEnv* env = ciEnv::current(); - if (env != nullptr) { + if (env != nullptr && env->task() != nullptr) { const bool overwrite = false; // We do not overwrite an existing replay file. int fd = prepare_log_file(ReplayDataFile, "replay_pid%p.log", overwrite, buffer, sizeof(buffer)); if (fd != -1) { diff --git a/src/java.base/macosx/native/libjli/java_md_macosx.m b/src/java.base/macosx/native/libjli/java_md_macosx.m index 7aeb32be859f2..354efc697690c 100644 --- a/src/java.base/macosx/native/libjli/java_md_macosx.m +++ b/src/java.base/macosx/native/libjli/java_md_macosx.m @@ -149,7 +149,7 @@ /* * Exports the JNI interface from libjli * - * This allows client code to link against the .jre/.jdk bundles, + * This allows client code to link against the JDK bundles, * and not worry about trying to pick a HotSpot to link against. * * Switching architectures is unsupported, since client code has @@ -162,10 +162,10 @@ static InvocationFunctions *GetExportedJNIFunctions() { if (sExportedJNIFunctions != NULL) return sExportedJNIFunctions; - char jrePath[PATH_MAX]; - jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE); - if (!gotJREPath) { - JLI_ReportErrorMessage("Failed to GetJREPath()"); + char jdkRoot[PATH_MAX]; + jboolean got = GetJDKInstallRoot(jdkRoot, sizeof(jdkRoot), JNI_FALSE); + if (!got) { + JLI_ReportErrorMessage("Failed to determine JDK installation root"); return NULL; } @@ -183,7 +183,7 @@ } char jvmPath[PATH_MAX]; - jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath)); + jboolean gotJVMPath = GetJVMPath(jdkRoot, preferredJVM, jvmPath, sizeof(jvmPath)); if (!gotJVMPath) { JLI_ReportErrorMessage("Failed to GetJVMPath()"); return NULL; @@ -326,9 +326,9 @@ static void MacOSXStartup(int argc, char *argv[]) { void CreateExecutionEnvironment(int *pargc, char ***pargv, - char jrepath[], jint so_jrepath, + char jdkroot[], jint so_jdkroot, char jvmpath[], jint so_jvmpath, - char jvmcfg[], jint so_jvmcfg) { + char jvmcfg[], jint so_jvmcfg) { /* Compute/set the name of the executable */ SetExecname(*pargv); @@ -336,13 +336,13 @@ static void MacOSXStartup(int argc, char *argv[]) { int argc = *pargc; char **argv = *pargv; - /* Find out where the JRE is that we will be using. */ - if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) { - JLI_ReportErrorMessage(JRE_ERROR1); + /* Find out where the JDK is that we will be using. */ + if (!GetJDKInstallRoot(jdkroot, so_jdkroot, JNI_FALSE) ) { + JLI_ReportErrorMessage(LAUNCHER_ERROR1); exit(2); } JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg", - jrepath, FILESEP, FILESEP); + jdkroot, FILESEP, FILESEP); /* Find the specified JVM type */ if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) { JLI_ReportErrorMessage(CFG_ERROR7); @@ -356,7 +356,7 @@ static void MacOSXStartup(int argc, char *argv[]) { exit(4); } - if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { + if (!GetJVMPath(jdkroot, jvmtype, jvmpath, so_jvmpath)) { JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } @@ -378,7 +378,7 @@ static void MacOSXStartup(int argc, char *argv[]) { * VM choosing is done by the launcher (java.c). */ static jboolean -GetJVMPath(const char *jrepath, const char *jvmtype, +GetJVMPath(const char *jdkroot, const char *jvmtype, char *jvmpath, jint jvmpathsize) { struct stat s; @@ -390,7 +390,7 @@ static void MacOSXStartup(int argc, char *argv[]) { * macosx client library is built thin, i386 only. * 64 bit client requests must load server library */ - JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype); + JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jdkroot, jvmtype); } JLI_TraceLauncher("Does `%s' exist ... ", jvmpath); @@ -408,15 +408,15 @@ static void MacOSXStartup(int argc, char *argv[]) { } /* - * Find path to JRE based on .exe's location or registry settings. + * Find path to the JDK installation root */ static jboolean -GetJREPath(char *path, jint pathsize, jboolean speculative) +GetJDKInstallRoot(char *path, jint pathsize, jboolean speculative) { char libjava[MAXPATHLEN]; if (GetApplicationHome(path, pathsize)) { - /* Is JRE co-located with the application? */ + /* Is the JDK co-located with the application? */ if (JLI_IsStaticallyLinked()) { char jvm_cfg[MAXPATHLEN]; JLI_Snprintf(jvm_cfg, sizeof(jvm_cfg), "%s/lib/jvm.cfg", path); @@ -445,7 +445,7 @@ static void MacOSXStartup(int argc, char *argv[]) { /* try to find ourselves instead */ Dl_info selfInfo; - dladdr(&GetJREPath, &selfInfo); + dladdr(&GetJDKInstallRoot, &selfInfo); if (JLI_IsStaticallyLinked()) { char jvm_cfg[MAXPATHLEN]; @@ -488,8 +488,8 @@ static void MacOSXStartup(int argc, char *argv[]) { return JNI_TRUE; } - // If libjli.dylib is loaded from a macos bundle MacOS dir, find the JRE dir - // in ../Home. + // If libjli.dylib is loaded from a macos bundle MacOS dir, find the JDK + // install root at ../Home. const char altLastPathComponent[] = "/MacOS/libjli.dylib"; size_t sizeOfAltLastPathComponent = sizeof(altLastPathComponent) - 1; if (pathLen < sizeOfLastPathComponent) { @@ -505,7 +505,7 @@ static void MacOSXStartup(int argc, char *argv[]) { } if (!speculative) - JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); + JLI_ReportErrorMessage(LAUNCHER_ERROR2 JAVA_DLL); return JNI_FALSE; } @@ -642,27 +642,27 @@ static void MacOSXStartup(int argc, char *argv[]) { void* SplashProcAddress(const char* name) { if (!hSplashLib) { - char jrePath[PATH_MAX]; - if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) { - JLI_ReportErrorMessage(JRE_ERROR1); + char jdkRoot[PATH_MAX]; + if (!GetJDKInstallRoot(jdkRoot, sizeof(jdkRoot), JNI_FALSE)) { + JLI_ReportErrorMessage(LAUNCHER_ERROR1); return NULL; } char splashPath[PATH_MAX]; const int ret = JLI_Snprintf(splashPath, sizeof(splashPath), - "%s/lib/%s", jrePath, SPLASHSCREEN_SO); + "%s/lib/%s", jdkRoot, SPLASHSCREEN_SO); if (ret >= (int)sizeof(splashPath)) { - JLI_ReportErrorMessage(JRE_ERROR11); + JLI_ReportErrorMessage(LAUNCHER_ERROR3); return NULL; } if (ret < 0) { - JLI_ReportErrorMessage(JRE_ERROR13); + JLI_ReportErrorMessage(LAUNCHER_ERROR5); return NULL; } hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL); // It's OK if dlopen() fails. The splash screen library binary file - // might have been stripped out from the JRE image to reduce its size + // might have been stripped out from the JDK image to reduce its size // (e.g. on embedded platforms). if (hSplashLib) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java index 7fad0b84d0715..7ba4420f97348 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java @@ -37,6 +37,9 @@ * * "Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping" * and represents AES cipher in KW mode. + * + * @spec https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf + * Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping */ class AESKeyWrap extends FeedbackCipher { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java index 1e4e7236c8cae..4f25849d8501b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java @@ -39,6 +39,9 @@ * * "Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping" * and represents AES cipher in KWP mode. + * + * @spec https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf + * Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping */ class AESKeyWrapPadded extends FeedbackCipher { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java index 0d5363e866a95..fcdc3fbea49e6 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ final class DHPrivateKey implements PrivateKey, private final BigInteger x; // the key bytes, without the algorithm information + // cannot be final as it's re-assigned for deserialization private byte[] key; // the encoded key @@ -70,115 +71,85 @@ final class DHPrivateKey implements PrivateKey, // the private-value length (optional) private final int l; - /** - * Make a DH private key out of a private value x, a prime - * modulus p, and a base generator g. - * - * @param x the private value - * @param p the prime modulus - * @param g the base generator - */ - DHPrivateKey(BigInteger x, BigInteger p, BigInteger g) - throws InvalidKeyException { - this(x, p, g, 0); - } - - /** - * Make a DH private key out of a private value x, a prime - * modulus p, a base generator g, and a - * private-value length l. - * - * @param x the private value - * @param p the prime modulus - * @param g the base generator - * @param l the private-value length - */ - DHPrivateKey(BigInteger x, BigInteger p, BigInteger g, int l) { - this.x = x; - this.p = p; - this.g = g; - this.l = l; - byte[] xbytes = x.toByteArray(); - DerValue val = new DerValue(DerValue.tag_Integer, xbytes); - this.key = val.toByteArray(); - val.clear(); - Arrays.fill(xbytes, (byte) 0); - encode(); + private static class DHComponents { + final BigInteger x; + final BigInteger p; + final BigInteger g; + final int l; + final byte[] key; + + DHComponents(BigInteger x, BigInteger p, BigInteger g, int l, + byte[] key) { + this.x = x; + this.p = p; + this.g = g; + this.l = l; + this.key = key; + } } - /** - * Make a DH private key from its DER encoding (PKCS #8). - * - * @param encodedKey the encoded key - * - * @throws InvalidKeyException if the encoded key does not represent - * a Diffie-Hellman private key - */ - DHPrivateKey(byte[] encodedKey) throws InvalidKeyException { + // parses the specified encoding into a DHComponents object + private static DHComponents decode(byte[] encodedKey) + throws IOException { DerValue val = null; + try { val = new DerValue(encodedKey); if (val.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException ("Key not a SEQUENCE"); + throw new IOException("Key not a SEQUENCE"); } - // // version - // BigInteger parsedVersion = val.data.getBigInteger(); if (!parsedVersion.equals(PKCS8_VERSION)) { throw new IOException("version mismatch: (supported: " + - PKCS8_VERSION + ", parsed: " + - parsedVersion); + PKCS8_VERSION + ", parsed: " + parsedVersion); } - // // privateKeyAlgorithm - // DerValue algid = val.data.getDerValue(); if (algid.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException("AlgId is not a SEQUENCE"); + throw new IOException("AlgId is not a SEQUENCE"); } DerInputStream derInStream = algid.toDerInputStream(); ObjectIdentifier oid = derInStream.getOID(); if (oid == null) { - throw new InvalidKeyException("Null OID"); + throw new IOException("Null OID"); } if (derInStream.available() == 0) { - throw new InvalidKeyException("Parameters missing"); + throw new IOException("Parameters missing"); } // parse the parameters DerValue params = derInStream.getDerValue(); if (params.tag == DerValue.tag_Null) { - throw new InvalidKeyException("Null parameters"); + throw new IOException("Null parameters"); } if (params.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException("Parameters not a SEQUENCE"); + throw new IOException("Parameters not a SEQUENCE"); } params.data.reset(); - this.p = params.data.getBigInteger(); - this.g = params.data.getBigInteger(); + BigInteger p = params.data.getBigInteger(); + BigInteger g = params.data.getBigInteger(); // Private-value length is OPTIONAL + int l = (params.data.available() != 0 ? + params.data.getInteger() : 0); + // should have no trailing data if (params.data.available() != 0) { - this.l = params.data.getInteger(); - } else { - this.l = 0; - } - if (params.data.available() != 0) { - throw new InvalidKeyException("Extra parameter data"); + throw new IOException("Extra parameter data"); } - // // privateKey - // - this.key = val.data.getOctetString(); - - DerInputStream in = new DerInputStream(this.key); - this.x = in.getBigInteger(); + byte[] key = val.data.getOctetString(); + DerInputStream in = new DerInputStream(key); + BigInteger x = in.getBigInteger(); - this.encodedKey = encodedKey.clone(); - } catch (IOException | NumberFormatException e) { - throw new InvalidKeyException("Error parsing key encoding", e); + // should have no trailing data + if (val.data.available() != 0) { + throw new IOException("Excess trailing data"); + } + return new DHComponents(x, p, g, l, key); + } catch (NumberFormatException e) { + throw new IOException("Error parsing key encoding", e); } finally { if (val != null) { val.clear(); @@ -186,6 +157,108 @@ final class DHPrivateKey implements PrivateKey, } } + // Generates the ASN.1 encoding + private static byte[] encode(BigInteger p, BigInteger g, int l, + byte[] key) { + DerOutputStream tmp = new DerOutputStream(); + + // version + tmp.putInteger(PKCS8_VERSION); + + // privateKeyAlgorithm + DerOutputStream algid = new DerOutputStream(); + + // store OID + algid.putOID(DHPublicKey.DH_OID); + // encode parameters + DerOutputStream params = new DerOutputStream(); + params.putInteger(p); + params.putInteger(g); + if (l != 0) { + params.putInteger(l); + } + // wrap parameters into SEQUENCE + DerValue paramSequence = new DerValue(DerValue.tag_Sequence, + params.toByteArray()); + // store parameter SEQUENCE in algid + algid.putDerValue(paramSequence); + // wrap algid into SEQUENCE + tmp.write(DerValue.tag_Sequence, algid); + + // privateKey + tmp.putOctetString(key); + + // make it a SEQUENCE + DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp); + byte[] encoded = val.toByteArray(); + val.clear(); + + return encoded; + } + + /** + * Make a DH private key out of a private value x, a prime + * modulus p, and a base generator g. + * + * @param x the private value + * @param p the prime modulus + * @param g the base generator + */ + DHPrivateKey(BigInteger x, BigInteger p, BigInteger g) + throws InvalidKeyException { + this(x, p, g, 0); + } + + /** + * Make a DH private key out of a private value x, a prime + * modulus p, a base generator g, and a + * private-value length l. + * + * @param x the private value + * @param p the prime modulus + * @param g the base generator + * @param l the private-value length + */ + DHPrivateKey(BigInteger x, BigInteger p, BigInteger g, int l) { + this.x = x; + this.p = p; + this.g = g; + this.l = l; + + byte[] xbytes = x.toByteArray(); + DerValue val = new DerValue(DerValue.tag_Integer, xbytes); + try { + this.key = val.toByteArray(); + } finally { + val.clear(); + Arrays.fill(xbytes, (byte) 0); + } + this.encodedKey = encode(p, g, l, key); + } + + /** + * Make a DH private key from its DER encoding (PKCS #8). + * + * @param encodedKey the encoded key + * + * @throws InvalidKeyException if the encoded key does not represent + * a Diffie-Hellman private key + */ + DHPrivateKey(byte[] encodedKey) throws InvalidKeyException { + this.encodedKey = encodedKey.clone(); + DHComponents dc; + try { + dc = decode(this.encodedKey); + } catch (IOException e) { + throw new InvalidKeyException("Invalid encoding", e); + } + this.x = dc.x; + this.p = dc.p; + this.g = dc.g; + this.l = dc.l; + this.key = dc.key; + } + /** * Returns the encoding format of this key: "PKCS#8" */ @@ -204,55 +277,9 @@ public String getAlgorithm() { * Get the encoding of the key. */ public synchronized byte[] getEncoded() { - encode(); return encodedKey.clone(); } - /** - * Generate the encodedKey field if it has not been calculated. - * Could generate null. - */ - private void encode() { - if (this.encodedKey == null) { - DerOutputStream tmp = new DerOutputStream(); - - // - // version - // - tmp.putInteger(PKCS8_VERSION); - - // - // privateKeyAlgorithm - // - DerOutputStream algid = new DerOutputStream(); - - // store OID - algid.putOID(DHPublicKey.DH_OID); - // encode parameters - DerOutputStream params = new DerOutputStream(); - params.putInteger(this.p); - params.putInteger(this.g); - if (this.l != 0) { - params.putInteger(this.l); - } - // wrap parameters into SEQUENCE - DerValue paramSequence = new DerValue(DerValue.tag_Sequence, - params.toByteArray()); - // store parameter SEQUENCE in algid - algid.putDerValue(paramSequence); - // wrap algid into SEQUENCE - tmp.write(DerValue.tag_Sequence, algid); - - // privateKey - tmp.putOctetString(this.key); - - // make it a SEQUENCE - DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp); - this.encodedKey = val.toByteArray(); - val.clear(); - } - } - /** * Returns the private value, x. * @@ -307,10 +334,7 @@ public boolean equals(Object obj) { */ @java.io.Serial private Object writeReplace() throws java.io.ObjectStreamException { - encode(); - return new KeyRep(KeyRep.Type.PRIVATE, - getAlgorithm(), - getFormat(), + return new KeyRep(KeyRep.Type.PRIVATE, getAlgorithm(), getFormat(), encodedKey); } @@ -330,11 +354,28 @@ private void readObject(ObjectInputStream stream) if ((key == null) || (key.length == 0)) { throw new InvalidObjectException("key not deserializable"); } - this.key = key.clone(); if ((encodedKey == null) || (encodedKey.length == 0)) { throw new InvalidObjectException( "encoded key not deserializable"); } - this.encodedKey = encodedKey.clone(); + // check if the "encodedKey" value matches the deserialized fields + DHComponents c; + byte[] encodedKeyIntern = encodedKey.clone(); + try { + c = decode(encodedKeyIntern); + } catch (IOException e) { + throw new InvalidObjectException("Invalid encoding", e); + } + if (!Arrays.equals(c.key, key) || !c.x.equals(x) || !c.p.equals(p) + || !c.g.equals(g) || c.l != l) { + throw new InvalidObjectException( + "encoded key not matching internal fields"); + } + // zero out external arrays + Arrays.fill(key, (byte)0x00); + Arrays.fill(encodedKey, (byte)0x00); + // use self-created internal copies + this.key = c.key; + this.encodedKey = encodedKeyIntern; } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java index 47727c432a672..c95b40482d5bd 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package com.sun.crypto.provider; import java.io.*; +import java.util.Arrays; import java.util.Objects; import java.math.BigInteger; import java.security.KeyRep; @@ -70,6 +71,116 @@ final class DHPublicKey implements PublicKey, static final ObjectIdentifier DH_OID = ObjectIdentifier.of(KnownOIDs.DiffieHellman); + private static class DHComponents { + final BigInteger y; + final BigInteger p; + final BigInteger g; + final int l; + final byte[] key; + + DHComponents(BigInteger y, BigInteger p, BigInteger g, int l, + byte[] key) { + this.y = y; + this.p = p; + this.g = g; + this.l = l; + this.key = key; + } + } + + // parses the specified encoding into a DHComponents object + private static DHComponents decode(byte[] encodedKey) + throws IOException { + DerValue val = null; + + try { + val = new DerValue(encodedKey); + if (val.tag != DerValue.tag_Sequence) { + throw new IOException("Invalid key format"); + } + + // algorithm identifier + DerValue algid = val.data.getDerValue(); + if (algid.tag != DerValue.tag_Sequence) { + throw new IOException("AlgId is not a SEQUENCE"); + } + DerInputStream derInStream = algid.toDerInputStream(); + ObjectIdentifier oid = derInStream.getOID(); + if (oid == null) { + throw new IOException("Null OID"); + } + if (derInStream.available() == 0) { + throw new IOException("Parameters missing"); + } + + // parse the parameters + DerValue params = derInStream.getDerValue(); + if (params.tag == DerValue.tag_Null) { + throw new IOException("Null parameters"); + } + if (params.tag != DerValue.tag_Sequence) { + throw new IOException("Parameters not a SEQUENCE"); + } + params.data.reset(); + + BigInteger p = params.data.getBigInteger(); + BigInteger g = params.data.getBigInteger(); + // Private-value length is OPTIONAL + int l = (params.data.available() != 0 ? params.data.getInteger() : + 0); + if (params.data.available() != 0) { + throw new IOException("Extra parameter data"); + } + + // publickey + byte[] key = val.data.getBitString(); + DerInputStream in = new DerInputStream(key); + BigInteger y = in.getBigInteger(); + + if (val.data.available() != 0) { + throw new IOException("Excess key data"); + } + return new DHComponents(y, p, g, l, key); + } catch (NumberFormatException e) { + throw new IOException("Error parsing key encoding", e); + } + } + + // generates the ASN.1 encoding + private static byte[] encode(BigInteger p, BigInteger g, int l, + byte[] key) { + DerOutputStream algid = new DerOutputStream(); + + // store oid in algid + algid.putOID(DH_OID); + + // encode parameters + DerOutputStream params = new DerOutputStream(); + params.putInteger(p); + params.putInteger(g); + if (l != 0) { + params.putInteger(l); + } + + // wrap parameters into SEQUENCE + DerValue paramSequence = new DerValue(DerValue.tag_Sequence, + params.toByteArray()); + // store parameter SEQUENCE in algid + algid.putDerValue(paramSequence); + + // wrap algid into SEQUENCE, and store it in key encoding + DerOutputStream tmpDerKey = new DerOutputStream(); + tmpDerKey.write(DerValue.tag_Sequence, algid); + + // store key data + tmpDerKey.putBitString(key); + + // wrap algid and key into SEQUENCE + DerOutputStream derKey = new DerOutputStream(); + derKey.write(DerValue.tag_Sequence, tmpDerKey); + return derKey.toByteArray(); + } + /** * Make a DH public key out of a public value y, a prime * modulus p, and a base generator g. @@ -102,7 +213,7 @@ final class DHPublicKey implements PublicKey, this.l = l; this.key = new DerValue(DerValue.tag_Integer, this.y.toByteArray()).toByteArray(); - this.encodedKey = getEncoded(); + this.encodedKey = encode(p, g, l, key); } /** @@ -114,68 +225,19 @@ final class DHPublicKey implements PublicKey, * a Diffie-Hellman public key */ DHPublicKey(byte[] encodedKey) throws InvalidKeyException { - InputStream inStream = new ByteArrayInputStream(encodedKey); - try { - DerValue derKeyVal = new DerValue(inStream); - if (derKeyVal.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException ("Invalid key format"); - } - - /* - * Parse the algorithm identifier - */ - DerValue algid = derKeyVal.data.getDerValue(); - if (algid.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException("AlgId is not a SEQUENCE"); - } - DerInputStream derInStream = algid.toDerInputStream(); - ObjectIdentifier oid = derInStream.getOID(); - if (oid == null) { - throw new InvalidKeyException("Null OID"); - } - if (derInStream.available() == 0) { - throw new InvalidKeyException("Parameters missing"); - } - - /* - * Parse the parameters - */ - DerValue params = derInStream.getDerValue(); - if (params.tag == DerValue.tag_Null) { - throw new InvalidKeyException("Null parameters"); - } - if (params.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException("Parameters not a SEQUENCE"); - } - params.data.reset(); - this.p = params.data.getBigInteger(); - this.g = params.data.getBigInteger(); - // Private-value length is OPTIONAL - if (params.data.available() != 0) { - this.l = params.data.getInteger(); - } else { - this.l = 0; - } - if (params.data.available() != 0) { - throw new InvalidKeyException("Extra parameter data"); - } - - /* - * Parse the key - */ - this.key = derKeyVal.data.getBitString(); - - DerInputStream in = new DerInputStream(this.key); - this.y = in.getBigInteger(); - - if (derKeyVal.data.available() != 0) { - throw new InvalidKeyException("Excess key data"); - } + this.encodedKey = encodedKey.clone(); - this.encodedKey = encodedKey.clone(); - } catch (IOException | NumberFormatException e) { - throw new InvalidKeyException("Error parsing key encoding", e); + DHComponents dc; + try { + dc = decode(this.encodedKey); + } catch (IOException e) { + throw new InvalidKeyException("Invalid encoding", e); } + this.y = dc.y; + this.p = dc.p; + this.g = dc.g; + this.l = dc.l; + this.key = dc.key; } /** @@ -196,37 +258,6 @@ public String getAlgorithm() { * Get the encoding of the key. */ public synchronized byte[] getEncoded() { - if (this.encodedKey == null) { - DerOutputStream algid = new DerOutputStream(); - - // store oid in algid - algid.putOID(DH_OID); - - // encode parameters - DerOutputStream params = new DerOutputStream(); - params.putInteger(this.p); - params.putInteger(this.g); - if (this.l != 0) { - params.putInteger(this.l); - } - // wrap parameters into SEQUENCE - DerValue paramSequence = new DerValue(DerValue.tag_Sequence, - params.toByteArray()); - // store parameter SEQUENCE in algid - algid.putDerValue(paramSequence); - - // wrap algid into SEQUENCE, and store it in key encoding - DerOutputStream tmpDerKey = new DerOutputStream(); - tmpDerKey.write(DerValue.tag_Sequence, algid); - - // store key data - tmpDerKey.putBitString(this.key); - - // wrap algid and key into SEQUENCE - DerOutputStream derKey = new DerOutputStream(); - derKey.write(DerValue.tag_Sequence, tmpDerKey); - this.encodedKey = derKey.toByteArray(); - } return this.encodedKey.clone(); } @@ -263,8 +294,9 @@ public String toString() { + Debug.toHexString(this.p) + LINE_SEP + "g:" + LINE_SEP + Debug.toHexString(this.g)); - if (this.l != 0) + if (this.l != 0) { sb.append(LINE_SEP + "l:" + LINE_SEP + " " + this.l); + } return sb.toString(); } @@ -304,7 +336,7 @@ private Object writeReplace() throws java.io.ObjectStreamException { return new KeyRep(KeyRep.Type.PUBLIC, getAlgorithm(), getFormat(), - getEncoded()); + encodedKey); } /** @@ -323,11 +355,28 @@ private void readObject(ObjectInputStream stream) if ((key == null) || (key.length == 0)) { throw new InvalidObjectException("key not deserializable"); } - this.key = key.clone(); if ((encodedKey == null) || (encodedKey.length == 0)) { throw new InvalidObjectException( "encoded key not deserializable"); } - this.encodedKey = encodedKey.clone(); + // check if the "encodedKey" value matches the deserialized fields + DHComponents c; + byte[] encodedKeyIntern = encodedKey.clone(); + try { + c = decode(encodedKeyIntern); + } catch (IOException e) { + throw new InvalidObjectException("Invalid encoding", e); + } + if (!Arrays.equals(c.key, key) || !c.y.equals(y) || !c.p.equals(p) + || !c.g.equals(g) || c.l != l) { + throw new InvalidObjectException( + "encoded key not matching internal fields"); + } + // zero out external arrays + Arrays.fill(key, (byte)0x00); + Arrays.fill(encodedKey, (byte)0x00); + // use self-created internal copies + this.key = c.key; + this.encodedKey = encodedKeyIntern; } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java b/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java index e5dc892032694..5dda6379d0361 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java @@ -31,6 +31,9 @@ * This class acts as the base class for AES KeyWrap algorithms as defined * in * "Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping" + * + * @spec https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf + * Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping */ class KWUtil { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java index fb69a27c62d51..ba2825fa36c2a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java @@ -36,6 +36,9 @@ * This class is the impl class for AES KeyWrap algorithms as defined in * * "Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping" + * + * @spec https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf + * Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping */ abstract class KeyWrapCipher extends CipherSpi { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java index 14ada1699c18c..2762fb3751c1b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.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 @@ -194,22 +194,24 @@ public byte[] getEncoded() { return key.clone(); } - /** - * Restores the state of this object from the stream. - * - * @param stream the {@code ObjectInputStream} from which data is read - * @throws IOException if an I/O error occurs - * @throws ClassNotFoundException if a serialized class cannot be loaded - */ - @java.io.Serial - private void readObject(ObjectInputStream stream) - throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - if ((key == null) || (key.length == 0)) { - throw new InvalidObjectException("TlsMasterSecretKey is null"); - } - key = key.clone(); - } - } + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + if (key == null || key.length == 0) { + throw new InvalidObjectException("TlsMasterSecretKey is null"); + } + byte[] temp = key; + this.key = temp.clone(); + Arrays.fill(temp, (byte)0); + } + } } diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index 0aa12bdf4c8b5..8ae4fc00773da 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -34,7 +34,7 @@ import jdk.internal.io.JdkConsoleImpl; import jdk.internal.io.JdkConsoleProvider; import jdk.internal.javac.PreviewFeature; -import jdk.internal.util.StaticProperty; +import sun.nio.cs.UTF_8; import sun.security.action.GetPropertyAction; /** @@ -580,7 +580,8 @@ public void flush() { * the {@code Console}. *

    * The returned charset corresponds to the input and output source - * (e.g., keyboard and/or display) specified by the host environment or user. + * (e.g., keyboard and/or display) specified by the host environment or user, + * which defaults to the one based on {@link System##stdout.encoding stdout.encoding}. * It may not necessarily be the same as the default charset returned from * {@link java.nio.charset.Charset#defaultCharset() Charset.defaultCharset()}. * @@ -614,30 +615,11 @@ private static UnsupportedOperationException newUnsupportedOperationException() "Console class itself does not provide implementation"); } - private static native String encoding(); private static final boolean istty = istty(); - static final Charset CHARSET; + static final Charset CHARSET = + Charset.forName(GetPropertyAction.privilegedGetProperty("stdout.encoding"), UTF_8.INSTANCE); + private static final Console cons = instantiateConsole(); static { - Charset cs = null; - - if (istty) { - String csname = encoding(); - if (csname == null) { - csname = GetPropertyAction.privilegedGetProperty("stdout.encoding"); - } - if (csname != null) { - cs = Charset.forName(csname, null); - } - } - if (cs == null) { - cs = Charset.forName(StaticProperty.nativeEncoding(), - Charset.defaultCharset()); - } - - CHARSET = cs; - - cons = instantiateConsole(); - // Set up JavaIOAccess in SharedSecrets SharedSecrets.setJavaIOAccess(new JavaIOAccess() { public Console console() { @@ -689,6 +671,5 @@ public Console run() { return c; } - private static final Console cons; private static native boolean istty(); } diff --git a/src/java.base/share/classes/java/io/DataOutputStream.java b/src/java.base/share/classes/java/io/DataOutputStream.java index d16ae73f913bf..4b22d65bd39fa 100644 --- a/src/java.base/share/classes/java/io/DataOutputStream.java +++ b/src/java.base/share/classes/java/io/DataOutputStream.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding 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 @@ -25,8 +26,13 @@ package java.io; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.util.ByteArray; +import static jdk.internal.util.ModifiedUtf.putChar; +import static jdk.internal.util.ModifiedUtf.utfLen; + /** * A data output stream lets an application write primitive Java data * types to an output stream in a portable way. An application can @@ -44,6 +50,8 @@ * @since 1.0 */ public class DataOutputStream extends FilterOutputStream implements DataOutput { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + /** * The number of bytes written to the data output stream so far. * If this counter overflows, it will be wrapped to Integer.MAX_VALUE. @@ -352,15 +360,11 @@ public final void writeUTF(String str) throws IOException { * {@code str} would exceed 65535 bytes in length * @throws IOException if some other I/O error occurs. */ + @SuppressWarnings("deprecation") static int writeUTF(String str, DataOutput out) throws IOException { final int strlen = str.length(); - int utflen = strlen; // optimized for ASCII - - for (int i = 0; i < strlen; i++) { - int c = str.charAt(i); - if (c >= 0x80 || c == 0) - utflen += (c >= 0x800) ? 2 : 1; - } + int countNonZeroAscii = JLA.countNonZeroAscii(str); + int utflen = utfLen(str, countNonZeroAscii); if (utflen > 65535 || /* overflow */ utflen < strlen) throw new UTFDataFormatException(tooLongMsg(str, utflen)); @@ -377,25 +381,11 @@ static int writeUTF(String str, DataOutput out) throws IOException { int count = 0; ByteArray.setUnsignedShort(bytearr, count, utflen); count += 2; - int i = 0; - for (i = 0; i < strlen; i++) { // optimized for initial run of ASCII - int c = str.charAt(i); - if (c >= 0x80 || c == 0) break; - bytearr[count++] = (byte) c; - } + str.getBytes(0, countNonZeroAscii, bytearr, count); + count += countNonZeroAscii; - for (; i < strlen; i++) { - int c = str.charAt(i); - if (c < 0x80 && c != 0) { - bytearr[count++] = (byte) c; - } else if (c >= 0x800) { - bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F)); - bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F)); - bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F)); - } else { - bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F)); - bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F)); - } + for (int i = countNonZeroAscii; i < strlen;) { + count = putChar(bytearr, count, str.charAt(i++)); } out.write(bytearr, 0, utflen + 2); return utflen + 2; diff --git a/src/java.base/share/classes/java/io/FileInputStream.java b/src/java.base/share/classes/java/io/FileInputStream.java index 60b289637fdfc..4210a0f56b6b6 100644 --- a/src/java.base/share/classes/java/io/FileInputStream.java +++ b/src/java.base/share/classes/java/io/FileInputStream.java @@ -29,6 +29,7 @@ import java.util.Arrays; import jdk.internal.util.ArraysSupport; import jdk.internal.event.FileReadEvent; +import jdk.internal.vm.annotation.Stable; import sun.nio.ch.FileChannelImpl; /** @@ -81,11 +82,14 @@ public class FileInputStream extends InputStream private volatile boolean closed; + // This field indicates whether the file is a regular file as some + // operations need the current position which requires seeking + private @Stable Boolean isRegularFile; + /** - * Creates a {@code FileInputStream} by - * opening a connection to an actual file, - * the file named by the path name {@code name} - * in the file system. {@linkplain java.nio.file##links Symbolic links} + * Creates a {@code FileInputStream} to read from an existing file + * named by the path name {@code name}. + * {@linkplain java.nio.file##links Symbolic links} * are automatically redirected to the target of the link. * A new {@code FileDescriptor} * object is created to represent this file @@ -115,10 +119,8 @@ public FileInputStream(String name) throws FileNotFoundException { } /** - * Creates a {@code FileInputStream} by - * opening a connection to an actual file, - * the file named by the {@code File} - * object {@code file} in the file system. + * Creates a {@code FileInputStream} to read from an existing file + * represented by the {@code File} object {@code file}. * {@linkplain java.nio.file##links Symbolic links} * are automatically redirected to the target of the link. * A new {@code FileDescriptor} object @@ -334,6 +336,9 @@ public int read(byte[] b, int off, int len) throws IOException { @Override public byte[] readAllBytes() throws IOException { + if (!isRegularFile()) + return super.readAllBytes(); + long length = length(); long position = position(); long size = length - position; @@ -385,6 +390,9 @@ public byte[] readNBytes(int len) throws IOException { if (len == 0) return new byte[0]; + if (!isRegularFile()) + return super.readNBytes(len); + long length = length(); long position = position(); long size = length - position; @@ -421,7 +429,7 @@ public byte[] readNBytes(int len) throws IOException { @Override public long transferTo(OutputStream out) throws IOException { long transferred = 0L; - if (out instanceof FileOutputStream fos) { + if (out instanceof FileOutputStream fos && isRegularFile()) { FileChannel fc = getChannel(); long pos = fc.position(); transferred = fc.transferTo(pos, Long.MAX_VALUE, fos.getChannel()); @@ -474,7 +482,10 @@ private long position() throws IOException { */ @Override public long skip(long n) throws IOException { - return skip0(n); + if (isRegularFile()) + return skip0(n); + + return super.skip(n); } private native long skip0(long n) throws IOException; @@ -606,6 +617,18 @@ public FileChannel getChannel() { return fc; } + /** + * Determine whether the file is a regular file. + */ + private boolean isRegularFile() { + Boolean isRegularFile = this.isRegularFile; + if (isRegularFile == null) { + this.isRegularFile = isRegularFile = isRegularFile0(fd); + } + return isRegularFile; + } + private native boolean isRegularFile0(FileDescriptor fd); + private static native void initIDs(); static { diff --git a/src/java.base/share/classes/java/io/ObjectOutputStream.java b/src/java.base/share/classes/java/io/ObjectOutputStream.java index 3650b10135356..bde069a1774d1 100644 --- a/src/java.base/share/classes/java/io/ObjectOutputStream.java +++ b/src/java.base/share/classes/java/io/ObjectOutputStream.java @@ -1,5 +1,6 @@ /* * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding 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 @@ -34,8 +35,13 @@ import java.util.StringJoiner; import jdk.internal.util.ByteArray; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import sun.reflect.misc.ReflectUtil; +import static jdk.internal.util.ModifiedUtf.putChar; +import static jdk.internal.util.ModifiedUtf.utfLen; + /** * An ObjectOutputStream writes primitive data types and graphs of Java objects * to an OutputStream. The objects can be read (reconstituted) using an @@ -169,6 +175,7 @@ public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private static class Caches { /** cache of subclass security audit results */ @@ -885,7 +892,7 @@ public void writeChars(String str) throws IOException { * stream */ public void writeUTF(String str) throws IOException { - bout.writeUTF(str); + bout.writeUTFInternal(str, false); } /** @@ -1317,14 +1324,7 @@ private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared) */ private void writeString(String str, boolean unshared) throws IOException { handles.assign(unshared ? null : str); - long utflen = bout.getUTFLength(str); - if (utflen <= 0xFFFF) { - bout.writeByte(TC_STRING); - bout.writeUTF(str, utflen); - } else { - bout.writeByte(TC_LONGSTRING); - bout.writeLongUTF(str, utflen); - } + bout.writeUTFInternal(str, true); } /** @@ -1994,26 +1994,27 @@ public void writeDouble(double v) throws IOException { } } - public void writeBytes(String s) throws IOException { - int endoff = s.length(); - int cpos = 0; - int csize = 0; - for (int off = 0; off < endoff; ) { - if (cpos >= csize) { - cpos = 0; - csize = Math.min(endoff - off, CHAR_BUF_SIZE); - s.getChars(off, off + csize, cbuf, 0); - } - if (pos >= MAX_BLOCK_SIZE) { + @SuppressWarnings("deprecation") + void writeBytes(String s, int len) throws IOException { + int pos = this.pos; + for (int strpos = 0; strpos < len;) { + int rem = MAX_BLOCK_SIZE - pos; + int csize = Math.min(len - strpos, rem); + s.getBytes(strpos, strpos + csize, buf, pos); + pos += csize; + strpos += csize; + + if (pos == MAX_BLOCK_SIZE) { + this.pos = pos; drain(); + pos = 0; } - int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos); - int stop = pos + n; - while (pos < stop) { - buf[pos++] = (byte) cbuf[cpos++]; - } - off += n; } + this.pos = pos; + } + + public void writeBytes(String s) throws IOException { + writeBytes(s, s.length()); } public void writeChars(String s) throws IOException { @@ -2026,8 +2027,47 @@ public void writeChars(String s) throws IOException { } } - public void writeUTF(String s) throws IOException { - writeUTF(s, getUTFLength(s)); + public void writeUTF(String str) throws IOException { + writeUTFInternal(str, false); + } + + private void writeUTFInternal(String str, boolean writeHeader) throws IOException { + int strlen = str.length(); + int countNonZeroAscii = JLA.countNonZeroAscii(str); + int utflen = utfLen(str, countNonZeroAscii); + if (utflen <= 0xFFFF) { + if(writeHeader) { + writeByte(TC_STRING); + } + writeShort(utflen); + } else { + if(writeHeader) { + writeByte(TC_LONGSTRING); + } + writeLong(utflen); + } + + if (countNonZeroAscii != 0) { + writeBytes(str, countNonZeroAscii); + } + if (countNonZeroAscii != strlen) { + writeMoreUTF(str, countNonZeroAscii); + } + } + + private void writeMoreUTF(String str, int stroff) throws IOException { + int pos = this.pos; + for (int strlen = str.length(); stroff < strlen;) { + char c = str.charAt(stroff++); + int csize = c != 0 && c < 0x80 ? 1 : c >= 0x800 ? 3 : 2; + if (pos + csize >= MAX_BLOCK_SIZE) { + this.pos = pos; + drain(); + pos = 0; + } + pos = putChar(buf, pos, c); + } + this.pos = pos; } @@ -2153,112 +2193,6 @@ void writeDoubles(double[] v, int off, int len) throws IOException { } } } - - /** - * Returns the length in bytes of the UTF encoding of the given string. - */ - long getUTFLength(String s) { - int len = s.length(); - long utflen = 0; - for (int off = 0; off < len; ) { - int csize = Math.min(len - off, CHAR_BUF_SIZE); - s.getChars(off, off + csize, cbuf, 0); - for (int cpos = 0; cpos < csize; cpos++) { - char c = cbuf[cpos]; - if (c >= 0x0001 && c <= 0x007F) { - utflen++; - } else if (c > 0x07FF) { - utflen += 3; - } else { - utflen += 2; - } - } - off += csize; - } - return utflen; - } - - /** - * Writes the given string in UTF format. This method is used in - * situations where the UTF encoding length of the string is already - * known; specifying it explicitly avoids a prescan of the string to - * determine its UTF length. - */ - void writeUTF(String s, long utflen) throws IOException { - if (utflen > 0xFFFFL) { - throw new UTFDataFormatException(); - } - writeShort((int) utflen); - if (utflen == (long) s.length()) { - writeBytes(s); - } else { - writeUTFBody(s); - } - } - - /** - * Writes given string in "long" UTF format. "Long" UTF format is - * identical to standard UTF, except that it uses an 8 byte header - * (instead of the standard 2 bytes) to convey the UTF encoding length. - */ - void writeLongUTF(String s) throws IOException { - writeLongUTF(s, getUTFLength(s)); - } - - /** - * Writes given string in "long" UTF format, where the UTF encoding - * length of the string is already known. - */ - void writeLongUTF(String s, long utflen) throws IOException { - writeLong(utflen); - if (utflen == (long) s.length()) { - writeBytes(s); - } else { - writeUTFBody(s); - } - } - - /** - * Writes the "body" (i.e., the UTF representation minus the 2-byte or - * 8-byte length header) of the UTF encoding for the given string. - */ - private void writeUTFBody(String s) throws IOException { - int limit = MAX_BLOCK_SIZE - 3; - int len = s.length(); - for (int off = 0; off < len; ) { - int csize = Math.min(len - off, CHAR_BUF_SIZE); - s.getChars(off, off + csize, cbuf, 0); - for (int cpos = 0; cpos < csize; cpos++) { - char c = cbuf[cpos]; - if (pos <= limit) { - if (c <= 0x007F && c != 0) { - buf[pos++] = (byte) c; - } else if (c > 0x07FF) { - buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F)); - buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F)); - buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F)); - pos += 3; - } else { - buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F)); - buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F)); - pos += 2; - } - } else { // write one byte at a time to normalize block - if (c <= 0x007F && c != 0) { - write(c); - } else if (c > 0x07FF) { - write(0xE0 | ((c >> 12) & 0x0F)); - write(0x80 | ((c >> 6) & 0x3F)); - write(0x80 | ((c >> 0) & 0x3F)); - } else { - write(0xC0 | ((c >> 6) & 0x1F)); - write(0x80 | ((c >> 0) & 0x3F)); - } - } - } - off += csize; - } - } } /** diff --git a/src/java.base/share/classes/java/io/Reader.java b/src/java.base/share/classes/java/io/Reader.java index 5dbe4ab5fae77..9fca28a3a96cf 100644 --- a/src/java.base/share/classes/java/io/Reader.java +++ b/src/java.base/share/classes/java/io/Reader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,6 +140,119 @@ public void close() { }; } + /** + * Returns a {@code Reader} that reads characters from a + * {@code CharSequence}. The reader is initially open and reading starts at + * the first character in the sequence. + * + *

    The returned reader supports the {@link #mark mark()} and + * {@link #reset reset()} operations. + * + *

    The resulting reader is not safe for use by multiple + * concurrent threads. If the reader is to be used by more than one + * thread it should be controlled by appropriate synchronization. + * + *

    If the sequence changes while the reader is open, e.g. the length + * changes, the behavior is undefined. + * + * @param cs {@code CharSequence} providing the character stream. + * @return a {@code Reader} which reads characters from {@code cs} + * @throws NullPointerException if {@code cs} is {@code null} + * + * @since 24 + */ + public static Reader of(final CharSequence cs) { + Objects.requireNonNull(cs); + + return new Reader() { + private boolean isClosed; + private int next = 0; + private int mark = 0; + + /** Check to make sure that the stream has not been closed */ + private void ensureOpen() throws IOException { + if (isClosed) + throw new IOException("Stream closed"); + } + + @Override + public int read() throws IOException { + ensureOpen(); + if (next >= cs.length()) + return -1; + return cs.charAt(next++); + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + ensureOpen(); + Objects.checkFromIndexSize(off, len, cbuf.length); + if (len == 0) { + return 0; + } + int length = cs.length(); + if (next >= length) + return -1; + int n = Math.min(length - next, len); + switch (cs) { + case String s -> s.getChars(next, next + n, cbuf, off); + case StringBuilder sb -> sb.getChars(next, next + n, cbuf, off); + case StringBuffer sb -> sb.getChars(next, next + n, cbuf, off); + case CharBuffer cb -> cb.get(next, cbuf, off, n); + default -> { + for (int i = 0; i < n; i++) + cbuf[off + i] = cs.charAt(next + i); + } + } + next += n; + return n; + } + + @Override + public long skip(long n) throws IOException { + ensureOpen(); + if (next >= cs.length()) + return 0; + // Bound skip by beginning and end of the source + long r = Math.min(cs.length() - next, n); + r = Math.max(-next, r); + next += (int)r; + return r; + } + + @Override + public boolean ready() throws IOException { + ensureOpen(); + return true; + } + + @Override + public boolean markSupported() { + return true; + } + + @Override + public void mark(int readAheadLimit) throws IOException { + if (readAheadLimit < 0){ + throw new IllegalArgumentException("Read-ahead limit < 0"); + } + ensureOpen(); + mark = next; + } + + @Override + public void reset() throws IOException { + ensureOpen(); + next = mark; + } + + @Override + public void close() { + isClosed = true; + } + }; + } + /** * The object used to synchronize operations on this stream. For * efficiency, a character-stream object may use an object other than diff --git a/src/java.base/share/classes/java/io/StringReader.java b/src/java.base/share/classes/java/io/StringReader.java index 2023aadf6c8db..719e3246adf70 100644 --- a/src/java.base/share/classes/java/io/StringReader.java +++ b/src/java.base/share/classes/java/io/StringReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,16 +30,17 @@ /** * A character stream whose source is a string. * + * @apiNote + * {@link Reader#of(CharSequence)} provides a method to read from any + * {@link CharSequence} that may be more efficient than {@code StringReader}. + * * @author Mark Reinhold * @since 1.1 */ public class StringReader extends Reader { - private final int length; - private String str; - private int next = 0; - private int mark = 0; + private final Reader r; /** * Creates a new string reader. @@ -47,14 +48,7 @@ public class StringReader extends Reader { * @param s String providing the character stream. */ public StringReader(String s) { - this.length = s.length(); - this.str = s; - } - - /** Check to make sure that the stream has not been closed */ - private void ensureOpen() throws IOException { - if (str == null) - throw new IOException("Stream closed"); + r = Reader.of(s); } /** @@ -67,10 +61,7 @@ private void ensureOpen() throws IOException { */ public int read() throws IOException { synchronized (lock) { - ensureOpen(); - if (next >= length) - return -1; - return str.charAt(next++); + return r.read(); } } @@ -94,17 +85,7 @@ public int read() throws IOException { */ public int read(char[] cbuf, int off, int len) throws IOException { synchronized (lock) { - ensureOpen(); - Objects.checkFromIndexSize(off, len, cbuf.length); - if (len == 0) { - return 0; - } - if (next >= length) - return -1; - int n = Math.min(length - next, len); - str.getChars(next, next + n, cbuf, off); - next += n; - return n; + return r.read(cbuf, off, len); } } @@ -130,14 +111,7 @@ public int read(char[] cbuf, int off, int len) throws IOException { */ public long skip(long n) throws IOException { synchronized (lock) { - ensureOpen(); - if (next >= length) - return 0; - // Bound skip by beginning and end of the source - long r = Math.min(length - next, n); - r = Math.max(-next, r); - next += (int)r; - return r; + return r.skip(n); } } @@ -150,8 +124,7 @@ public long skip(long n) throws IOException { */ public boolean ready() throws IOException { synchronized (lock) { - ensureOpen(); - return true; + return r.ready(); } } @@ -176,12 +149,8 @@ public boolean markSupported() { * @throws IOException If an I/O error occurs */ public void mark(int readAheadLimit) throws IOException { - if (readAheadLimit < 0){ - throw new IllegalArgumentException("Read-ahead limit < 0"); - } synchronized (lock) { - ensureOpen(); - mark = next; + r.mark(readAheadLimit); } } @@ -193,8 +162,7 @@ public void mark(int readAheadLimit) throws IOException { */ public void reset() throws IOException { synchronized (lock) { - ensureOpen(); - next = mark; + r.reset(); } } @@ -207,7 +175,11 @@ public void reset() throws IOException { */ public void close() { synchronized (lock) { - str = null; + try { + r.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } } } diff --git a/src/java.base/share/classes/java/lang/Boolean.java b/src/java.base/share/classes/java/lang/Boolean.java index 2c0925a979016..31507f60e3782 100644 --- a/src/java.base/share/classes/java/lang/Boolean.java +++ b/src/java.base/share/classes/java/lang/Boolean.java @@ -78,8 +78,7 @@ public final class Boolean implements java.io.Serializable, * * @since 1.1 */ - @SuppressWarnings("unchecked") - public static final Class TYPE = (Class) Class.getPrimitiveClass("boolean"); + public static final Class TYPE = Class.getPrimitiveClass("boolean"); /** * The value of the Boolean. @@ -255,8 +254,8 @@ public static int hashCode(boolean value) { * same value; {@code false} otherwise. */ public boolean equals(Object obj) { - if (obj instanceof Boolean) { - return value == ((Boolean)obj).booleanValue(); + if (obj instanceof Boolean b) { + return value == b.booleanValue(); } return false; } diff --git a/src/java.base/share/classes/java/lang/Byte.java b/src/java.base/share/classes/java/lang/Byte.java index ade75a7a99eeb..5835f65366fb7 100644 --- a/src/java.base/share/classes/java/lang/Byte.java +++ b/src/java.base/share/classes/java/lang/Byte.java @@ -79,8 +79,7 @@ public final class Byte extends Number implements Comparable, Constable { * The {@code Class} instance representing the primitive type * {@code byte}. */ - @SuppressWarnings("unchecked") - public static final Class TYPE = (Class) Class.getPrimitiveClass("byte"); + public static final Class TYPE = Class.getPrimitiveClass("byte"); /** * Returns a new {@code String} object representing the @@ -118,7 +117,7 @@ private ByteCache() {} // Load and use the archived cache if it exists CDS.initializeFromArchive(ByteCache.class); - if (archivedCache == null || archivedCache.length != size) { + if (archivedCache == null) { Byte[] c = new Byte[size]; byte value = (byte)-128; for(int i = 0; i < size; i++) { @@ -127,6 +126,7 @@ private ByteCache() {} archivedCache = c; } cache = archivedCache; + assert cache.length == size; } } @@ -477,8 +477,8 @@ public static int hashCode(byte value) { * {@code false} otherwise. */ public boolean equals(Object obj) { - if (obj instanceof Byte) { - return value == ((Byte)obj).byteValue(); + if (obj instanceof Byte b) { + return value == b.byteValue(); } return false; } diff --git a/src/java.base/share/classes/java/lang/Character.java b/src/java.base/share/classes/java/lang/Character.java index 84db550d7cc4d..8368adf540330 100644 --- a/src/java.base/share/classes/java/lang/Character.java +++ b/src/java.base/share/classes/java/lang/Character.java @@ -232,8 +232,7 @@ class Character implements java.io.Serializable, Comparable, Constabl * * @since 1.1 */ - @SuppressWarnings("unchecked") - public static final Class TYPE = (Class) Class.getPrimitiveClass("char"); + public static final Class TYPE = Class.getPrimitiveClass("char"); /* * Normative general types @@ -8985,7 +8984,7 @@ private CharacterCache(){} // Load and use the archived cache if it exists CDS.initializeFromArchive(CharacterCache.class); - if (archivedCache == null || archivedCache.length != size) { + if (archivedCache == null) { Character[] c = new Character[size]; for (int i = 0; i < size; i++) { c[i] = new Character((char) i); @@ -8993,6 +8992,7 @@ private CharacterCache(){} archivedCache = c; } cache = archivedCache; + assert cache.length == size; } } @@ -9066,8 +9066,8 @@ public static int hashCode(char value) { * {@code false} otherwise. */ public boolean equals(Object obj) { - if (obj instanceof Character) { - return value == ((Character)obj).charValue(); + if (obj instanceof Character c) { + return value == c.charValue(); } return false; } diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 79cd57011b0ed..93a675c83a4ea 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -3278,10 +3278,10 @@ ProtectionDomain protectionDomain() { private native ProtectionDomain getProtectionDomain0(); /* - * Return the Virtual Machine's Class object for the named - * primitive type. + * Returns the Class object for the named primitive type. Type parameter T + * avoids redundant casts for trusted code. */ - static native Class getPrimitiveClass(String name); + static native Class getPrimitiveClass(String name); /* * Check if client is allowed to access members. If access is denied, diff --git a/src/java.base/share/classes/java/lang/Double.java b/src/java.base/share/classes/java/lang/Double.java index 68fff6a2fbdd2..ed23f7d39c9fc 100644 --- a/src/java.base/share/classes/java/lang/Double.java +++ b/src/java.base/share/classes/java/lang/Double.java @@ -459,8 +459,7 @@ public final class Double extends Number * * @since 1.1 */ - @SuppressWarnings("unchecked") - public static final Class TYPE = (Class) Class.getPrimitiveClass("double"); + public static final Class TYPE = Class.getPrimitiveClass("double"); /** * Returns a string representation of the {@code double} @@ -1257,9 +1256,8 @@ public static int hashCode(double value) { * @jls 15.21.1 Numerical Equality Operators == and != */ public boolean equals(Object obj) { - return (obj instanceof Double) - && (doubleToLongBits(((Double)obj).value) == - doubleToLongBits(value)); + return (obj instanceof Double d) && + (doubleToLongBits(d.value) == doubleToLongBits(value)); } /** diff --git a/src/java.base/share/classes/java/lang/Float.java b/src/java.base/share/classes/java/lang/Float.java index 470eb71cf701f..821a05fa00abd 100644 --- a/src/java.base/share/classes/java/lang/Float.java +++ b/src/java.base/share/classes/java/lang/Float.java @@ -175,8 +175,7 @@ public final class Float extends Number * * @since 1.1 */ - @SuppressWarnings("unchecked") - public static final Class TYPE = (Class) Class.getPrimitiveClass("float"); + public static final Class TYPE = Class.getPrimitiveClass("float"); /** * Returns a string representation of the {@code float} @@ -889,8 +888,8 @@ public static int hashCode(float value) { * @jls 15.21.1 Numerical Equality Operators == and != */ public boolean equals(Object obj) { - return (obj instanceof Float) - && (floatToIntBits(((Float)obj).value) == floatToIntBits(value)); + return (obj instanceof Float f) && + (floatToIntBits(f.value) == floatToIntBits(value)); } /** diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index eab0a942d9a9a..e666e977c61a5 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -95,8 +95,7 @@ public final class Integer extends Number * * @since 1.1 */ - @SuppressWarnings("unchecked") - public static final Class TYPE = (Class) Class.getPrimitiveClass("int"); + public static final Class TYPE = Class.getPrimitiveClass("int"); /** * All possible chars for representing a number as a String @@ -961,7 +960,17 @@ private static final class IntegerCache { if (archivedCache == null || size > archivedCache.length) { Integer[] c = new Integer[size]; int j = low; - for(int i = 0; i < c.length; i++) { + // If archive has Integer cache, we must use all instances from it. + // Otherwise, the identity checks between archived Integers and + // runtime-cached Integers would fail. + int archivedSize = (archivedCache == null) ? 0 : archivedCache.length; + for (int i = 0; i < archivedSize; i++) { + c[i] = archivedCache[i]; + assert j == archivedCache[i]; + j++; + } + // Fill the rest of the cache. + for (int i = archivedSize; i < size; i++) { c[i] = new Integer(j++); } archivedCache = c; @@ -1147,8 +1156,8 @@ public static int hashCode(int value) { * {@code false} otherwise. */ public boolean equals(Object obj) { - if (obj instanceof Integer) { - return value == ((Integer)obj).intValue(); + if (obj instanceof Integer i) { + return value == i.intValue(); } return false; } diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index f86e1622b3836..8c083b3ec8431 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -95,8 +95,7 @@ public final class Long extends Number * * @since 1.1 */ - @SuppressWarnings("unchecked") - public static final Class TYPE = (Class) Class.getPrimitiveClass("long"); + public static final Class TYPE = Class.getPrimitiveClass("long"); /** * Returns a string representation of the first argument in the @@ -963,7 +962,7 @@ private LongCache() {} // Load and use the archived cache if it exists CDS.initializeFromArchive(LongCache.class); - if (archivedCache == null || archivedCache.length != size) { + if (archivedCache == null) { Long[] c = new Long[size]; long value = -128; for(int i = 0; i < size; i++) { @@ -972,6 +971,7 @@ private LongCache() {} archivedCache = c; } cache = archivedCache; + assert cache.length == size; } } @@ -1245,8 +1245,8 @@ public static int hashCode(long value) { * {@code false} otherwise. */ public boolean equals(Object obj) { - if (obj instanceof Long) { - return value == ((Long)obj).longValue(); + if (obj instanceof Long ell) { + return value == ell.longValue(); } return false; } diff --git a/src/java.base/share/classes/java/lang/Short.java b/src/java.base/share/classes/java/lang/Short.java index ec792de47e2ac..57e88442b2783 100644 --- a/src/java.base/share/classes/java/lang/Short.java +++ b/src/java.base/share/classes/java/lang/Short.java @@ -79,8 +79,7 @@ public final class Short extends Number implements Comparable, Constable * The {@code Class} instance representing the primitive type * {@code short}. */ - @SuppressWarnings("unchecked") - public static final Class TYPE = (Class) Class.getPrimitiveClass("short"); + public static final Class TYPE = Class.getPrimitiveClass("short"); /** * Returns a new {@code String} object representing the @@ -245,7 +244,7 @@ private ShortCache() {} // Load and use the archived cache if it exists CDS.initializeFromArchive(ShortCache.class); - if (archivedCache == null || archivedCache.length != size) { + if (archivedCache == null) { Short[] c = new Short[size]; short value = -128; for(int i = 0; i < size; i++) { @@ -254,6 +253,7 @@ private ShortCache() {} archivedCache = c; } cache = archivedCache; + assert cache.length == size; } } @@ -483,8 +483,8 @@ public static int hashCode(short value) { * {@code false} otherwise. */ public boolean equals(Object obj) { - if (obj instanceof Short) { - return value == ((Short)obj).shortValue(); + if (obj instanceof Short s) { + return value == s.shortValue(); } return false; } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 930b6b7f611b5..5b04bca4f44af 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -147,8 +147,7 @@ private System() { * corresponds to display output or another output destination * specified by the host environment or user. The encoding used * in the conversion from characters to bytes is equivalent to - * {@link Console#charset()} if the {@code Console} exists, - * stdout.encoding otherwise. + * {@link ##stdout.encoding stdout.encoding}. *

    * For simple stand-alone Java applications, a typical way to write * a line of output data is: @@ -168,8 +167,7 @@ private System() { * @see java.io.PrintStream#println(long) * @see java.io.PrintStream#println(java.lang.Object) * @see java.io.PrintStream#println(java.lang.String) - * @see Console#charset() - * @see stdout.encoding + * @see ##stdout.encoding stdout.encoding */ public static final PrintStream out = null; @@ -185,11 +183,9 @@ private System() { * variable {@code out}, has been redirected to a file or other * destination that is typically not continuously monitored. * The encoding used in the conversion from characters to bytes is - * equivalent to {@link Console#charset()} if the {@code Console} - * exists, stderr.encoding otherwise. + * equivalent to {@link ##stderr.encoding stderr.encoding}. * - * @see Console#charset() - * @see stderr.encoding + * @see ##stderr.encoding stderr.encoding */ public static final PrintStream err = null; @@ -788,7 +784,8 @@ public static native void arraycopy(Object src, int srcPos, * Character encoding name derived from the host environment and/or * the user's settings. Setting this system property has no effect. * {@systemProperty stdout.encoding} - * Character encoding name for {@link System#out System.out}. + * Character encoding name for {@link System#out System.out} and + * {@link System#console() System.console()}. * The Java runtime can be started with the system property set to {@code UTF-8}, * starting it with the property set to another value leads to undefined behavior. * {@systemProperty stderr.encoding} diff --git a/src/java.base/share/classes/java/lang/ThreadLocal.java b/src/java.base/share/classes/java/lang/ThreadLocal.java index 4c2eb08c125c5..8a9aa7998fd44 100644 --- a/src/java.base/share/classes/java/lang/ThreadLocal.java +++ b/src/java.base/share/classes/java/lang/ThreadLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -232,8 +232,8 @@ private T setInitialValue(Thread t) { if (this instanceof TerminatingThreadLocal ttl) { TerminatingThreadLocal.register(ttl); } - if (TRACE_VTHREAD_LOCALS) { - dumpStackIfVirtualThread(); + if (TRACE_VTHREAD_LOCALS && t == Thread.currentThread() && t.isVirtual()) { + printStackTrace(); } return value; } @@ -249,8 +249,8 @@ private T setInitialValue(Thread t) { */ public void set(T value) { set(Thread.currentThread(), value); - if (TRACE_VTHREAD_LOCALS) { - dumpStackIfVirtualThread(); + if (TRACE_VTHREAD_LOCALS && Thread.currentThread().isVirtual()) { + printStackTrace(); } } @@ -799,7 +799,6 @@ private void expungeStaleEntries() { } } - /** * Reads the value of the jdk.traceVirtualThreadLocals property to determine if * a stack trace should be printed when a virtual thread sets a thread local. @@ -811,30 +810,28 @@ private static boolean traceVirtualThreadLocals() { } /** - * Print a stack trace if the current thread is a virtual thread. + * Print the stack trace of the current thread, skipping the printStackTrace frame. + * A thread local is used to detect reentrancy as the printing may itself use + * thread locals. */ - static void dumpStackIfVirtualThread() { - if (Thread.currentThread() instanceof VirtualThread vthread) { + private void printStackTrace() { + Thread t = Thread.currentThread(); + ThreadLocalMap map = getMap(t); + if (map.getEntry(DUMPING_STACK) == null) { + map.set(DUMPING_STACK, true); try { - var stack = StackWalkerHolder.STACK_WALKER.walk(s -> + var stack = StackWalker.getInstance().walk(s -> s.skip(1) // skip caller .collect(Collectors.toList())); - - // switch to carrier thread to avoid recursive use of thread-locals - vthread.executeOnCarrierThread(() -> { - System.out.println(vthread); - for (StackWalker.StackFrame frame : stack) { - System.out.format(" %s%n", frame.toStackTraceElement()); - } - return null; - }); - } catch (Exception e) { - throw new InternalError(e); + System.out.println(t); + for (StackWalker.StackFrame frame : stack) { + System.out.format(" %s%n", frame.toStackTraceElement()); + } + } finally { + map.remove(DUMPING_STACK); } } } - private static class StackWalkerHolder { - static final StackWalker STACK_WALKER = StackWalker.getInstance(); - } + private static final ThreadLocal DUMPING_STACK = new ThreadLocal<>(); } diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 6eb20fa9e2e12..f76a6eec9140e 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -28,7 +28,6 @@ import java.security.PrivilegedAction; import java.util.Locale; import java.util.Objects; -import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -56,6 +55,7 @@ import jdk.internal.vm.annotation.ChangesCurrentThread; import jdk.internal.vm.annotation.Hidden; import jdk.internal.vm.annotation.IntrinsicCandidate; +import jdk.internal.vm.annotation.JvmtiHideEvents; import jdk.internal.vm.annotation.JvmtiMountTransition; import jdk.internal.vm.annotation.ReservedStackAccess; import sun.nio.ch.Interruptible; @@ -136,13 +136,18 @@ final class VirtualThread extends BaseVirtualThread { // parking permit private volatile boolean parkPermit; + // timeout for timed-park, in nanoseconds, only accessed on current/carrier thread + private long parkTimeout; + + // timer task for timed-park, only accessed on current/carrier thread + private Future timeoutTask; + // carrier thread when mounted, accessed by VM private volatile Thread carrierThread; // termination object when joining, created lazily if needed private volatile CountDownLatch termination; - /** * Returns the default scheduler. */ @@ -213,8 +218,14 @@ protected void onPinned(Continuation.Pinned reason) { private static Runnable wrap(VirtualThread vthread, Runnable task) { return new Runnable() { @Hidden + @JvmtiHideEvents public void run() { - vthread.run(task); + vthread.notifyJvmtiStart(); // notify JVMTI + try { + vthread.run(task); + } finally { + vthread.notifyJvmtiEnd(); // notify JVMTI + } } }; } @@ -239,8 +250,10 @@ private void runContinuation() { if (!compareAndSetState(initialState, RUNNING)) { return; } - // consume parking permit when continuing after parking + // consume permit when continuing after parking. If continuing after a + // timed-park then the timeout task is cancelled. if (initialState == UNPARKED) { + cancelTimeoutTask(); setParkPermit(false); } } else { @@ -261,6 +274,17 @@ private void runContinuation() { } } + /** + * Cancel timeout task when continuing after a timed-park. The + * timeout task may be executing, or may have already completed. + */ + private void cancelTimeoutTask() { + if (timeoutTask != null) { + timeoutTask.cancel(false); + timeoutTask = null; + } + } + /** * Submits the runContinuation task to the scheduler. For the default scheduler, * and calling it on a worker thread, the task will be pushed to the local queue, @@ -269,23 +293,21 @@ private void runContinuation() { * @param retryOnOOME true to retry indefinitely if OutOfMemoryError is thrown * @throws RejectedExecutionException */ - @ChangesCurrentThread private void submitRunContinuation(Executor scheduler, boolean retryOnOOME) { boolean done = false; while (!done) { try { - // The scheduler's execute method is invoked in the context of the - // carrier thread. For the default scheduler this ensures that the - // current thread is a ForkJoinWorkerThread so the task will be pushed - // to the local queue. For other schedulers, it avoids deadlock that - // would arise due to platform and virtual threads contending for a - // lock on the scheduler's submission queue. - if (currentThread() instanceof VirtualThread vthread) { - vthread.switchToCarrierThread(); + // Pin the continuation to prevent the virtual thread from unmounting + // when submitting a task. For the default scheduler this ensures that + // the carrier doesn't change when pushing a task. For other schedulers + // it avoids deadlock that could arise due to carriers and virtual + // threads contending for a lock. + if (currentThread().isVirtual()) { + Continuation.pin(); try { scheduler.execute(runContinuation); } finally { - switchToVirtualThread(vthread); + Continuation.unpin(); } } else { scheduler.execute(runContinuation); @@ -304,24 +326,6 @@ private void submitRunContinuation(Executor scheduler, boolean retryOnOOME) { } } - /** - * Submits the runContinuation task to given scheduler with a lazy submit. - * If OutOfMemoryError is thrown then the submit will be retried until it succeeds. - * @throws RejectedExecutionException - * @see ForkJoinPool#lazySubmit(ForkJoinTask) - */ - private void lazySubmitRunContinuation(ForkJoinPool pool) { - assert Thread.currentThread() instanceof CarrierThread; - try { - pool.lazySubmit(ForkJoinTask.adapt(runContinuation)); - } catch (RejectedExecutionException ree) { - submitFailed(ree); - throw ree; - } catch (OutOfMemoryError e) { - submitRunContinuation(pool, true); - } - } - /** * Submits the runContinuation task to the given scheduler as an external submit. * If OutOfMemoryError is thrown then the submit will be retried until it succeeds. @@ -351,6 +355,30 @@ private void submitRunContinuation() { submitRunContinuation(scheduler, true); } + /** + * Lazy submit the runContinuation task if invoked on a carrier thread and its local + * queue is empty. If not empty, or invoked by another thread, then this method works + * like submitRunContinuation and just submits the task to the scheduler. + * If OutOfMemoryError is thrown then the submit will be retried until it succeeds. + * @throws RejectedExecutionException + * @see ForkJoinPool#lazySubmit(ForkJoinTask) + */ + private void lazySubmitRunContinuation() { + if (currentThread() instanceof CarrierThread ct && ct.getQueuedTaskCount() == 0) { + ForkJoinPool pool = ct.getPool(); + try { + pool.lazySubmit(ForkJoinTask.adapt(runContinuation)); + } catch (RejectedExecutionException ree) { + submitFailed(ree); + throw ree; + } catch (OutOfMemoryError e) { + submitRunContinuation(); + } + } else { + submitRunContinuation(); + } + } + /** * Submits the runContinuation task to the scheduler. For the default scheduler, and * calling it a virtual thread that uses the default scheduler, the task will be @@ -389,9 +417,6 @@ private void submitFailed(RejectedExecutionException ree) { private void run(Runnable task) { assert Thread.currentThread() == this && state == RUNNING; - // notify JVMTI, may post VirtualThreadStart event - notifyJvmtiStart(); - // emit JFR event if enabled if (VirtualThreadStartEvent.isTurnedOn()) { var event = new VirtualThreadStartEvent(); @@ -405,20 +430,14 @@ private void run(Runnable task) { } catch (Throwable exc) { dispatchUncaughtException(exc); } finally { - try { - // pop any remaining scopes from the stack, this may block - StackableScope.popAll(); - - // emit JFR event if enabled - if (VirtualThreadEndEvent.isTurnedOn()) { - var event = new VirtualThreadEndEvent(); - event.javaThreadId = threadId(); - event.commit(); - } + // pop any remaining scopes from the stack, this may block + StackableScope.popAll(); - } finally { - // notify JVMTI, may post VirtualThreadEnd event - notifyJvmtiEnd(); + // emit JFR event if enabled + if (VirtualThreadEndEvent.isTurnedOn()) { + var event = new VirtualThreadEndEvent(); + event.javaThreadId = threadId(); + event.commit(); } } } @@ -476,45 +495,6 @@ private void unmount() { notifyJvmtiUnmount(/*hide*/false); } - /** - * Sets the current thread to the current carrier thread. - */ - @ChangesCurrentThread - @JvmtiMountTransition - private void switchToCarrierThread() { - notifyJvmtiHideFrames(true); - Thread carrier = this.carrierThread; - assert Thread.currentThread() == this - && carrier == Thread.currentCarrierThread(); - carrier.setCurrentThread(carrier); - } - - /** - * Sets the current thread to the given virtual thread. - */ - @ChangesCurrentThread - @JvmtiMountTransition - private static void switchToVirtualThread(VirtualThread vthread) { - Thread carrier = vthread.carrierThread; - assert carrier == Thread.currentCarrierThread(); - carrier.setCurrentThread(vthread); - notifyJvmtiHideFrames(false); - } - - /** - * Executes the given value returning task on the current carrier thread. - */ - @ChangesCurrentThread - V executeOnCarrierThread(Callable task) throws Exception { - assert Thread.currentThread() == this; - switchToCarrierThread(); - try { - return task.call(); - } finally { - switchToVirtualThread(this); - } - } - /** * Invokes Continuation.yield, notifying JVMTI (if enabled) to hide frames until * the continuation continues. @@ -530,9 +510,8 @@ private boolean yieldContinuation() { } /** - * Invoked after the continuation yields. If parking then it sets the state - * and also re-submits the task to continue if unparked while parking. - * If yielding due to Thread.yield then it just submits the task to continue. + * Invoked in the context of the carrier thread after the Continuation yields when + * parking or Thread.yield. */ private void afterYield() { assert carrierThread == null; @@ -546,17 +525,20 @@ private void afterYield() { // LockSupport.park/parkNanos if (s == PARKING || s == TIMED_PARKING) { - int newState = (s == PARKING) ? PARKED : TIMED_PARKED; - setState(newState); + int newState; + if (s == PARKING) { + setState(newState = PARKED); + } else { + // schedule unpark + assert parkTimeout > 0; + timeoutTask = schedule(this::unpark, parkTimeout, NANOSECONDS); + setState(newState = TIMED_PARKED); + } // may have been unparked while parking if (parkPermit && compareAndSetState(newState, UNPARKED)) { - // lazy submit to continue on the current carrier if possible - if (currentThread() instanceof CarrierThread ct && ct.getQueuedTaskCount() == 0) { - lazySubmitRunContinuation(ct.getPool()); - } else { - submitRunContinuation(); - } + // lazy submit if local queue is empty + lazySubmitRunContinuation(); } return; } @@ -674,7 +656,9 @@ void park() { boolean yielded = false; setState(PARKING); try { - yielded = yieldContinuation(); // may throw + yielded = yieldContinuation(); + } catch (OutOfMemoryError e) { + // park on carrier } finally { assert (Thread.currentThread() == this) && (yielded == (state() == RUNNING)); if (!yielded) { @@ -709,21 +693,23 @@ void parkNanos(long nanos) { if (nanos > 0) { long startTime = System.nanoTime(); + // park the thread, afterYield will schedule the thread to unpark boolean yielded = false; - Future unparker = scheduleUnpark(nanos); // may throw OOME + setParkTimeout(nanos); setState(TIMED_PARKING); try { - yielded = yieldContinuation(); // may throw + yielded = yieldContinuation(); + } catch (OutOfMemoryError e) { + // park on carrier } finally { assert (Thread.currentThread() == this) && (yielded == (state() == RUNNING)); if (!yielded) { assert state() == TIMED_PARKING; setState(RUNNING); } - cancel(unparker); } - // park on carrier thread for remaining time when pinned + // park on carrier thread for remaining time when pinned (or OOME) if (!yielded) { long remainingNanos = nanos - (System.nanoTime() - startTime); parkOnCarrierThread(true, remainingNanos); @@ -774,38 +760,6 @@ private void parkOnCarrierThread(boolean timed, long nanos) { } } - /** - * Schedule this virtual thread to be unparked after a given delay. - */ - @ChangesCurrentThread - private Future scheduleUnpark(long nanos) { - assert Thread.currentThread() == this; - // need to switch to current carrier thread to avoid nested parking - switchToCarrierThread(); - try { - return schedule(this::unpark, nanos, NANOSECONDS); - } finally { - switchToVirtualThread(this); - } - } - - /** - * Cancels a task if it has not completed. - */ - @ChangesCurrentThread - private void cancel(Future future) { - assert Thread.currentThread() == this; - if (!future.isDone()) { - // need to switch to current carrier thread to avoid nested parking - switchToCarrierThread(); - try { - future.cancel(false); - } finally { - switchToVirtualThread(this); - } - } - } - /** * Re-enables this virtual thread for scheduling. If this virtual thread is parked * then its task is scheduled to continue, otherwise its next call to {@code park} or @@ -1043,10 +997,10 @@ Thread.State threadState() { return Thread.State.RUNNABLE; case PARKED: case PINNED: - return State.WAITING; + return Thread.State.WAITING; case TIMED_PARKED: case TIMED_PINNED: - return State.TIMED_WAITING; + return Thread.State.TIMED_WAITING; case TERMINATED: return Thread.State.TERMINATED; default: @@ -1265,6 +1219,10 @@ private boolean getAndSetParkPermit(boolean newValue) { } } + private void setParkTimeout(long timeout) { + parkTimeout = timeout; + } + private void setCarrierThread(Thread carrier) { // U.putReferenceRelease(this, CARRIER_THREAD, carrier); this.carrierThread = carrier; @@ -1288,10 +1246,6 @@ private void setCarrierThread(Thread carrier) { @JvmtiMountTransition private native void notifyJvmtiUnmount(boolean hide); - @IntrinsicCandidate - @JvmtiMountTransition - private static native void notifyJvmtiHideFrames(boolean hide); - @IntrinsicCandidate private static native void notifyJvmtiDisableSuspend(boolean enter); diff --git a/src/java.base/share/classes/java/lang/Void.java b/src/java.base/share/classes/java/lang/Void.java index 3ea0e79e61c5b..9a3adafec33e2 100644 --- a/src/java.base/share/classes/java/lang/Void.java +++ b/src/java.base/share/classes/java/lang/Void.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,7 @@ class Void { * The {@code Class} object representing the pseudo-type corresponding to * the keyword {@code void}. */ - @SuppressWarnings("unchecked") - public static final Class TYPE = (Class) Class.getPrimitiveClass("void"); + public static final Class TYPE = Class.getPrimitiveClass("void"); /* * The Void class cannot be instantiated. diff --git a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java index 6c6ac75e64896..4abe17c1cf59e 100644 --- a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java +++ b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java @@ -24,9 +24,10 @@ */ package java.lang.classfile; +import java.lang.reflect.AccessFlag; import java.util.Set; + import jdk.internal.classfile.impl.AccessFlagsImpl; -import java.lang.reflect.AccessFlag; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/Annotation.java b/src/java.base/share/classes/java/lang/classfile/Annotation.java index 009248ffd7856..4f222084cb7ab 100644 --- a/src/java.base/share/classes/java/lang/classfile/Annotation.java +++ b/src/java.base/share/classes/java/lang/classfile/Annotation.java @@ -29,12 +29,11 @@ import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; import java.lang.classfile.constantpool.Utf8Entry; -import jdk.internal.classfile.impl.AnnotationImpl; -import jdk.internal.classfile.impl.TemporaryConstantPool; - import java.lang.constant.ClassDesc; import java.util.List; +import jdk.internal.classfile.impl.AnnotationImpl; +import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java index 33bd410e78dce..7c4283c49bf4d 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java @@ -24,9 +24,9 @@ */ package java.lang.classfile; +import java.lang.classfile.constantpool.Utf8Entry; import java.lang.constant.ClassDesc; -import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.AnnotationImpl; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index 50bfa0b7aa6fb..e1e91f2c9edb1 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -24,24 +24,19 @@ */ package java.lang.classfile; -import java.lang.classfile.constantpool.AnnotationConstantValueEntry; -import java.lang.classfile.constantpool.DoubleEntry; -import java.lang.classfile.constantpool.DynamicConstantPoolEntry; -import java.lang.classfile.constantpool.FloatEntry; -import java.lang.classfile.constantpool.IntegerEntry; -import java.lang.classfile.constantpool.LongEntry; -import java.lang.classfile.constantpool.Utf8Entry; -import jdk.internal.classfile.impl.AnnotationImpl; -import jdk.internal.classfile.impl.TemporaryConstantPool; - +import java.lang.classfile.constantpool.*; import java.lang.constant.ClassDesc; import java.lang.constant.Constable; import java.util.ArrayList; import java.util.List; +import jdk.internal.classfile.impl.AnnotationImpl; +import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * Models an {@code element_value} structure, or a value of an element-value * pair of an annotation, as defined in JVMS {@jvms 4.7.16.1}. @@ -488,6 +483,8 @@ default ClassDesc classSymbol() { */ static OfEnum ofEnum(Utf8Entry className, Utf8Entry constantName) { + requireNonNull(className); + requireNonNull(constantName); return new AnnotationImpl.OfEnumImpl(className, constantName); } @@ -506,6 +503,7 @@ static OfEnum ofEnum(ClassDesc className, String constantName) { * @param className the descriptor string of the class */ static OfClass ofClass(Utf8Entry className) { + requireNonNull(className); return new AnnotationImpl.OfClassImpl(className); } @@ -522,6 +520,7 @@ static OfClass ofClass(ClassDesc className) { * @param value the string */ static OfString ofString(Utf8Entry value) { + requireNonNull(value); return new AnnotationImpl.OfStringImpl(value); } @@ -538,6 +537,7 @@ static OfString ofString(String value) { * @param value the double value */ static OfDouble ofDouble(DoubleEntry value) { + requireNonNull(value); return new AnnotationImpl.OfDoubleImpl(value); } @@ -554,6 +554,7 @@ static OfDouble ofDouble(double value) { * @param value the float value */ static OfFloat ofFloat(FloatEntry value) { + requireNonNull(value); return new AnnotationImpl.OfFloatImpl(value); } @@ -570,6 +571,7 @@ static OfFloat ofFloat(float value) { * @param value the long value */ static OfLong ofLong(LongEntry value) { + requireNonNull(value); return new AnnotationImpl.OfLongImpl(value); } @@ -586,6 +588,7 @@ static OfLong ofLong(long value) { * @param value the int value */ static OfInt ofInt(IntegerEntry value) { + requireNonNull(value); return new AnnotationImpl.OfIntImpl(value); } @@ -602,6 +605,7 @@ static OfInt ofInt(int value) { * @param value the short value */ static OfShort ofShort(IntegerEntry value) { + requireNonNull(value); return new AnnotationImpl.OfShortImpl(value); } @@ -618,6 +622,7 @@ static OfShort ofShort(short value) { * @param value the char value */ static OfChar ofChar(IntegerEntry value) { + requireNonNull(value); return new AnnotationImpl.OfCharImpl(value); } @@ -634,6 +639,7 @@ static OfChar ofChar(char value) { * @param value the byte value */ static OfByte ofByte(IntegerEntry value) { + requireNonNull(value); return new AnnotationImpl.OfByteImpl(value); } @@ -650,6 +656,7 @@ static OfByte ofByte(byte value) { * @param value the boolean value */ static OfBoolean ofBoolean(IntegerEntry value) { + requireNonNull(value); return new AnnotationImpl.OfBooleanImpl(value); } @@ -667,6 +674,7 @@ static OfBoolean ofBoolean(boolean value) { * @param value the annotation */ static OfAnnotation ofAnnotation(Annotation value) { + requireNonNull(value); return new AnnotationImpl.OfAnnotationImpl(value); } @@ -784,6 +792,6 @@ static AnnotationValue of(Object value) { } else if (value instanceof Enum e) { return ofEnum(ClassDesc.ofDescriptor(e.getDeclaringClass().descriptorString()), e.name()); } - throw new IllegalArgumentException("Illegal annotation constant value type " + (value == null ? null : value.getClass())); + throw new IllegalArgumentException("Illegal annotation constant value type " + requireNonNull(value).getClass()); } } diff --git a/src/java.base/share/classes/java/lang/classfile/Attribute.java b/src/java.base/share/classes/java/lang/classfile/Attribute.java index b9e3df8d2a2d3..e2f0072d3967f 100644 --- a/src/java.base/share/classes/java/lang/classfile/Attribute.java +++ b/src/java.base/share/classes/java/lang/classfile/Attribute.java @@ -24,43 +24,8 @@ */ package java.lang.classfile; -import java.lang.classfile.attribute.AnnotationDefaultAttribute; -import java.lang.classfile.attribute.BootstrapMethodsAttribute; -import java.lang.classfile.attribute.CharacterRangeTableAttribute; -import java.lang.classfile.attribute.CodeAttribute; -import java.lang.classfile.attribute.CompilationIDAttribute; -import java.lang.classfile.attribute.ConstantValueAttribute; -import java.lang.classfile.attribute.DeprecatedAttribute; -import java.lang.classfile.attribute.EnclosingMethodAttribute; -import java.lang.classfile.attribute.ExceptionsAttribute; -import java.lang.classfile.attribute.InnerClassesAttribute; -import java.lang.classfile.attribute.LineNumberTableAttribute; -import java.lang.classfile.attribute.LocalVariableTableAttribute; -import java.lang.classfile.attribute.LocalVariableTypeTableAttribute; -import java.lang.classfile.attribute.MethodParametersAttribute; -import java.lang.classfile.attribute.ModuleAttribute; -import java.lang.classfile.attribute.ModuleHashesAttribute; -import java.lang.classfile.attribute.ModuleMainClassAttribute; -import java.lang.classfile.attribute.ModulePackagesAttribute; -import java.lang.classfile.attribute.ModuleResolutionAttribute; -import java.lang.classfile.attribute.ModuleTargetAttribute; -import java.lang.classfile.attribute.NestHostAttribute; -import java.lang.classfile.attribute.NestMembersAttribute; -import java.lang.classfile.attribute.PermittedSubclassesAttribute; -import java.lang.classfile.attribute.RecordAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.SignatureAttribute; -import java.lang.classfile.attribute.SourceDebugExtensionAttribute; -import java.lang.classfile.attribute.SourceFileAttribute; -import java.lang.classfile.attribute.SourceIDAttribute; -import java.lang.classfile.attribute.StackMapTableAttribute; -import java.lang.classfile.attribute.SyntheticAttribute; -import java.lang.classfile.attribute.UnknownAttribute; +import java.lang.classfile.attribute.*; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/AttributedElement.java b/src/java.base/share/classes/java/lang/classfile/AttributedElement.java index d66806ca93b43..fb1bf817480e0 100644 --- a/src/java.base/share/classes/java/lang/classfile/AttributedElement.java +++ b/src/java.base/share/classes/java/lang/classfile/AttributedElement.java @@ -24,15 +24,17 @@ */ package java.lang.classfile; +import java.lang.classfile.attribute.RecordComponentInfo; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; -import java.lang.classfile.attribute.RecordComponentInfo; import jdk.internal.classfile.impl.AbstractUnboundModel; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A {@link ClassFileElement} describing an entity that has attributes, such * as a class, field, method, code attribute, or record component. @@ -58,6 +60,7 @@ public sealed interface AttributedElement extends ClassFileElement * is not present */ default > Optional findAttribute(AttributeMapper attr) { + requireNonNull(attr); for (Attribute la : attributes()) { if (la.attributeMapper() == attr) { @SuppressWarnings("unchecked") @@ -76,6 +79,7 @@ default > Optional findAttribute(AttributeMapper at * is not present */ default > List findAttributes(AttributeMapper attr) { + requireNonNull(attr); var list = new ArrayList(); for (var a : attributes()) { if (a.attributeMapper() == attr) { diff --git a/src/java.base/share/classes/java/lang/classfile/Attributes.java b/src/java.base/share/classes/java/lang/classfile/Attributes.java index 1e91090f8afda..ad63eec75de39 100644 --- a/src/java.base/share/classes/java/lang/classfile/Attributes.java +++ b/src/java.base/share/classes/java/lang/classfile/Attributes.java @@ -26,6 +26,7 @@ import java.lang.classfile.AttributeMapper.AttributeStability; import java.lang.classfile.attribute.*; + import jdk.internal.classfile.impl.AbstractAttributeMapper.*; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java b/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java index 5ff3c449fe9ae..964976e0fd5ad 100644 --- a/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java @@ -25,11 +25,11 @@ package java.lang.classfile; -import java.util.List; - import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.LoadableConstantEntry; import java.lang.classfile.constantpool.MethodHandleEntry; +import java.util.List; + import jdk.internal.classfile.impl.BootstrapMethodEntryImpl; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/BufWriter.java b/src/java.base/share/classes/java/lang/classfile/BufWriter.java index c71b44e7c0286..d60447c138843 100644 --- a/src/java.base/share/classes/java/lang/classfile/BufWriter.java +++ b/src/java.base/share/classes/java/lang/classfile/BufWriter.java @@ -27,6 +27,7 @@ import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.PoolEntry; + import jdk.internal.classfile.impl.BufWriterImpl; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java index 905c7355c3406..71f1cc5319458 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java @@ -25,22 +25,20 @@ package java.lang.classfile; - +import java.lang.classfile.attribute.CodeAttribute; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.Utf8Entry; import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.constantpool.Utf8Entry; - import jdk.internal.classfile.impl.AccessFlagsImpl; import jdk.internal.classfile.impl.ChainedClassBuilder; import jdk.internal.classfile.impl.DirectClassBuilder; import jdk.internal.classfile.impl.Util; -import java.lang.reflect.AccessFlag; -import java.lang.classfile.attribute.CodeAttribute; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/ClassElement.java b/src/java.base/share/classes/java/lang/classfile/ClassElement.java index 3852f7d12933a..6c918b7de4aab 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassElement.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassElement.java @@ -24,30 +24,8 @@ */ package java.lang.classfile; -import java.lang.classfile.attribute.CompilationIDAttribute; -import java.lang.classfile.attribute.DeprecatedAttribute; -import java.lang.classfile.attribute.EnclosingMethodAttribute; -import java.lang.classfile.attribute.InnerClassesAttribute; -import java.lang.classfile.attribute.ModuleAttribute; -import java.lang.classfile.attribute.ModuleHashesAttribute; -import java.lang.classfile.attribute.ModuleMainClassAttribute; -import java.lang.classfile.attribute.ModulePackagesAttribute; -import java.lang.classfile.attribute.ModuleResolutionAttribute; -import java.lang.classfile.attribute.ModuleTargetAttribute; -import java.lang.classfile.attribute.NestHostAttribute; -import java.lang.classfile.attribute.NestMembersAttribute; -import java.lang.classfile.attribute.PermittedSubclassesAttribute; -import java.lang.classfile.attribute.RecordAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.SignatureAttribute; -import java.lang.classfile.attribute.SourceDebugExtensionAttribute; -import java.lang.classfile.attribute.SourceFileAttribute; -import java.lang.classfile.attribute.SourceIDAttribute; -import java.lang.classfile.attribute.SyntheticAttribute; -import java.lang.classfile.attribute.UnknownAttribute; +import java.lang.classfile.attribute.*; + import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFile.java b/src/java.base/share/classes/java/lang/classfile/ClassFile.java index 284503ee62714..7051228c827b0 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -25,27 +25,28 @@ package java.lang.classfile; import java.io.IOException; +import java.lang.classfile.attribute.CharacterRangeInfo; +import java.lang.classfile.attribute.LocalVariableInfo; +import java.lang.classfile.attribute.LocalVariableTypeInfo; +import java.lang.classfile.attribute.ModuleAttribute; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.classfile.instruction.ExceptionCatch; import java.lang.constant.ClassDesc; +import java.lang.reflect.AccessFlag; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.function.Consumer; import java.util.function.Function; -import java.lang.classfile.attribute.ModuleAttribute; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.ClassFileImpl; import jdk.internal.classfile.impl.TemporaryConstantPool; -import java.lang.reflect.AccessFlag; -import java.lang.classfile.attribute.CharacterRangeInfo; -import java.lang.classfile.attribute.LocalVariableInfo; -import java.lang.classfile.attribute.LocalVariableTypeInfo; -import java.lang.classfile.instruction.ExceptionCatch; -import java.util.List; +import jdk.internal.javac.PreviewFeature; + import static java.util.Objects.requireNonNull; import static jdk.internal.constant.ConstantUtils.CD_module_info; -import jdk.internal.javac.PreviewFeature; /** * Represents a context for parsing, transforming, and generating classfiles. diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java index 56a2088370c6b..8b3f6544fff16 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java @@ -24,11 +24,10 @@ */ package java.lang.classfile; +import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.constant.ClassDesc; import java.util.function.Consumer; -import java.lang.classfile.constantpool.ConstantPoolBuilder; - import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java b/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java index 851f4deb03e92..b9c5210881cb9 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java @@ -24,9 +24,9 @@ */ package java.lang.classfile; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.util.function.Supplier; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java b/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java index 589713c8e95c8..c2719e7aae062 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.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 @@ -37,9 +37,10 @@ import jdk.internal.classfile.impl.ClassHierarchyImpl.ClassLoadingClassHierarchyResolver; import jdk.internal.classfile.impl.ClassHierarchyImpl.StaticClassHierarchyResolver; import jdk.internal.classfile.impl.Util; +import jdk.internal.javac.PreviewFeature; import static java.lang.constant.ConstantDescs.CD_Object; -import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; /** * Provides class hierarchy information for generating correct stack maps @@ -106,6 +107,7 @@ static ClassHierarchyInfo ofInterface() { * other resolver in cases where this resolver returns {@code null}. */ default ClassHierarchyResolver orElse(ClassHierarchyResolver other) { + requireNonNull(other); return new ClassHierarchyResolver() { @Override public ClassHierarchyInfo getClassInfo(ClassDesc classDesc) { @@ -170,7 +172,7 @@ public Map get() { * @return the {@linkplain ClassHierarchyResolver} */ static ClassHierarchyResolver ofResourceParsing(Function classStreamResolver) { - return new ClassHierarchyImpl.ResourceParsingClassHierarchyResolver(classStreamResolver); + return new ClassHierarchyImpl.ResourceParsingClassHierarchyResolver(requireNonNull(classStreamResolver)); } /** @@ -181,6 +183,7 @@ static ClassHierarchyResolver ofResourceParsing(Function * @return the {@linkplain ClassHierarchyResolver} */ static ClassHierarchyResolver ofResourceParsing(ClassLoader loader) { + requireNonNull(loader); return ofResourceParsing(new Function<>() { @Override public InputStream apply(ClassDesc classDesc) { @@ -210,6 +213,7 @@ static ClassHierarchyResolver of(Collection interfaces, * @return the class hierarchy resolver */ static ClassHierarchyResolver ofClassLoading(ClassLoader loader) { + requireNonNull(loader); return new ClassLoadingClassHierarchyResolver(new Function<>() { @Override public Class apply(ClassDesc cd) { @@ -232,6 +236,7 @@ public Class apply(ClassDesc cd) { * @return the class hierarchy resolver */ static ClassHierarchyResolver ofClassLoading(MethodHandles.Lookup lookup) { + requireNonNull(lookup); return new ClassLoadingClassHierarchyResolver(new Function<>() { @Override public Class apply(ClassDesc cd) { diff --git a/src/java.base/share/classes/java/lang/classfile/ClassModel.java b/src/java.base/share/classes/java/lang/classfile/ClassModel.java index c289f72f560f0..915b662b48838 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassModel.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassModel.java @@ -25,14 +25,12 @@ package java.lang.classfile; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPool; import java.util.List; import java.util.Optional; -import java.util.function.Consumer; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.constantpool.ConstantPool; import jdk.internal.classfile.impl.ClassImpl; -import jdk.internal.classfile.impl.verifier.VerifierImpl; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/ClassReader.java b/src/java.base/share/classes/java/lang/classfile/ClassReader.java index 735aae444fc0c..58ee2aae5e58e 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassReader.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassReader.java @@ -29,10 +29,10 @@ import java.lang.classfile.constantpool.ConstantPoolException; import java.lang.classfile.constantpool.PoolEntry; import java.lang.classfile.constantpool.Utf8Entry; -import jdk.internal.classfile.impl.ClassReaderImpl; - import java.util.Optional; import java.util.function.Function; + +import jdk.internal.classfile.impl.ClassReaderImpl; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java index 3b6b15f59f839..5a57144c4abce 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java @@ -25,10 +25,12 @@ package java.lang.classfile; import java.util.List; + import jdk.internal.classfile.impl.SignaturesImpl; -import static java.util.Objects.requireNonNull; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * Models the generic signature of a class file, as defined by JVMS {@jvms 4.7.9}. * diff --git a/src/java.base/share/classes/java/lang/classfile/ClassTransform.java b/src/java.base/share/classes/java/lang/classfile/ClassTransform.java index 743a39851148a..f512683a9b652 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassTransform.java @@ -24,14 +24,16 @@ */ package java.lang.classfile; +import java.lang.classfile.attribute.CodeAttribute; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; -import java.lang.classfile.attribute.CodeAttribute; import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A transformation on streams of {@link ClassElement}. * @@ -63,7 +65,7 @@ public void accept(ClassBuilder builder, ClassElement element) { * @return the stateful class transform */ static ClassTransform ofStateful(Supplier supplier) { - return new TransformImpl.SupplierClassTransform(supplier); + return new TransformImpl.SupplierClassTransform(requireNonNull(supplier)); } /** @@ -74,6 +76,7 @@ static ClassTransform ofStateful(Supplier supplier) { * @return the class transform */ static ClassTransform endHandler(Consumer finisher) { + requireNonNull(finisher); return new ClassTransform() { @Override public void accept(ClassBuilder builder, ClassElement element) { @@ -95,6 +98,7 @@ public void atEnd(ClassBuilder builder) { * @return the class transform */ static ClassTransform dropping(Predicate filter) { + requireNonNull(filter); return (b, e) -> { if (!filter.test(e)) b.with(e); @@ -111,7 +115,7 @@ static ClassTransform dropping(Predicate filter) { */ static ClassTransform transformingMethods(Predicate filter, MethodTransform xform) { - return new TransformImpl.ClassMethodTransform(xform, filter); + return new TransformImpl.ClassMethodTransform(requireNonNull(xform), requireNonNull(filter)); } /** @@ -122,7 +126,7 @@ static ClassTransform transformingMethods(Predicate filter, * @return the class transform */ static ClassTransform transformingMethods(MethodTransform xform) { - return transformingMethods(mm -> true, xform); + return transformingMethods(_ -> true, xform); } /** @@ -157,7 +161,7 @@ static ClassTransform transformingMethodBodies(CodeTransform xform) { * @return the class transform */ static ClassTransform transformingFields(FieldTransform xform) { - return new TransformImpl.ClassFieldTransform(xform, f -> true); + return new TransformImpl.ClassFieldTransform(requireNonNull(xform), _ -> true); } /** @@ -169,6 +173,6 @@ static ClassTransform transformingFields(FieldTransform xform) { */ @Override default ClassTransform andThen(ClassTransform t) { - return new TransformImpl.ChainedClassTransform(this, t); + return new TransformImpl.ChainedClassTransform(this, requireNonNull(t)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index 7b27238bbdfae..11e83550d233d 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -25,6 +25,8 @@ package java.lang.classfile; +import java.lang.classfile.constantpool.*; +import java.lang.classfile.instruction.*; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; import java.lang.constant.ConstantDescs; @@ -36,60 +38,12 @@ import java.util.Optional; import java.util.function.Consumer; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.constantpool.FieldRefEntry; -import java.lang.classfile.constantpool.InterfaceMethodRefEntry; -import java.lang.classfile.constantpool.InvokeDynamicEntry; -import java.lang.classfile.constantpool.LoadableConstantEntry; -import java.lang.classfile.constantpool.MemberRefEntry; -import java.lang.classfile.constantpool.MethodRefEntry; -import java.lang.classfile.constantpool.MethodHandleEntry; -import java.lang.classfile.constantpool.NameAndTypeEntry; -import java.lang.classfile.constantpool.Utf8Entry; -import jdk.internal.classfile.impl.BlockCodeBuilderImpl; -import jdk.internal.classfile.impl.BytecodeHelpers; -import jdk.internal.classfile.impl.CatchBuilderImpl; -import jdk.internal.classfile.impl.ChainedCodeBuilder; -import jdk.internal.classfile.impl.LabelImpl; -import jdk.internal.classfile.impl.NonterminalCodeBuilder; -import jdk.internal.classfile.impl.TerminalCodeBuilder; -import java.lang.classfile.instruction.ArrayLoadInstruction; -import java.lang.classfile.instruction.ArrayStoreInstruction; -import java.lang.classfile.instruction.BranchInstruction; -import java.lang.classfile.instruction.CharacterRange; -import java.lang.classfile.instruction.ConstantInstruction; -import java.lang.classfile.instruction.ConvertInstruction; -import java.lang.classfile.instruction.ExceptionCatch; -import java.lang.classfile.instruction.FieldInstruction; -import java.lang.classfile.instruction.IncrementInstruction; -import java.lang.classfile.instruction.InvokeDynamicInstruction; -import java.lang.classfile.instruction.InvokeInstruction; -import java.lang.classfile.instruction.LineNumber; -import java.lang.classfile.instruction.LoadInstruction; -import java.lang.classfile.instruction.LocalVariable; -import java.lang.classfile.instruction.LocalVariableType; -import java.lang.classfile.instruction.LookupSwitchInstruction; -import java.lang.classfile.instruction.MonitorInstruction; -import java.lang.classfile.instruction.NewMultiArrayInstruction; -import java.lang.classfile.instruction.NewObjectInstruction; -import java.lang.classfile.instruction.NewPrimitiveArrayInstruction; -import java.lang.classfile.instruction.NewReferenceArrayInstruction; -import java.lang.classfile.instruction.NopInstruction; -import java.lang.classfile.instruction.OperatorInstruction; -import java.lang.classfile.instruction.ReturnInstruction; -import java.lang.classfile.instruction.StackInstruction; -import java.lang.classfile.instruction.StoreInstruction; -import java.lang.classfile.instruction.SwitchCase; -import java.lang.classfile.instruction.TableSwitchInstruction; -import java.lang.classfile.instruction.ThrowInstruction; -import java.lang.classfile.instruction.TypeCheckInstruction; +import jdk.internal.classfile.impl.*; +import jdk.internal.javac.PreviewFeature; import static java.util.Objects.requireNonNull; import static jdk.internal.classfile.impl.BytecodeHelpers.handleDescToHandleInfo; -import jdk.internal.classfile.impl.TransformImpl; -import jdk.internal.javac.PreviewFeature; - /** * A builder for code attributes (method bodies). Builders are not created * directly; they are passed to handlers by methods such as {@link diff --git a/src/java.base/share/classes/java/lang/classfile/CodeElement.java b/src/java.base/share/classes/java/lang/classfile/CodeElement.java index cd4fafdd5bb9c..1cec4b8e6045f 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeElement.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeElement.java @@ -27,6 +27,7 @@ import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; import java.lang.classfile.attribute.StackMapTableAttribute; + import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/CodeModel.java b/src/java.base/share/classes/java/lang/classfile/CodeModel.java index ba816f2080581..759aacc18c94e 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeModel.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeModel.java @@ -25,13 +25,12 @@ package java.lang.classfile; +import java.lang.classfile.attribute.CodeAttribute; +import java.lang.classfile.instruction.ExceptionCatch; import java.util.List; import java.util.Optional; -import java.lang.classfile.attribute.CodeAttribute; import jdk.internal.classfile.impl.BufferedCodeBuilder; -import jdk.internal.classfile.impl.CodeImpl; -import java.lang.classfile.instruction.ExceptionCatch; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/CodeTransform.java b/src/java.base/share/classes/java/lang/classfile/CodeTransform.java index cdc7a3b1434d7..0474e0c9c67f7 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeTransform.java @@ -30,6 +30,8 @@ import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A transformation on streams of {@link CodeElement}. * @@ -61,7 +63,7 @@ public void accept(CodeBuilder builder, CodeElement element) { * @return the stateful code transform */ static CodeTransform ofStateful(Supplier supplier) { - return new TransformImpl.SupplierCodeTransform(supplier); + return new TransformImpl.SupplierCodeTransform(requireNonNull(supplier)); } /** @@ -72,6 +74,7 @@ static CodeTransform ofStateful(Supplier supplier) { * @return the code transform */ static CodeTransform endHandler(Consumer finisher) { + requireNonNull(finisher); return new CodeTransform() { @Override public void accept(CodeBuilder builder, CodeElement element) { @@ -94,6 +97,6 @@ public void atEnd(CodeBuilder builder) { */ @Override default CodeTransform andThen(CodeTransform t) { - return new TransformImpl.ChainedCodeTransform(this, t); + return new TransformImpl.ChainedCodeTransform(this, requireNonNull(t)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/CompoundElement.java b/src/java.base/share/classes/java/lang/classfile/CompoundElement.java index 9fcf02204cb13..5dfeac6f00d33 100644 --- a/src/java.base/share/classes/java/lang/classfile/CompoundElement.java +++ b/src/java.base/share/classes/java/lang/classfile/CompoundElement.java @@ -33,6 +33,7 @@ import java.util.function.Consumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; + import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java index d9a8f6b2fc325..d318364465748 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java @@ -26,13 +26,12 @@ package java.lang.classfile; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.reflect.AccessFlag; +import java.util.function.Consumer; import jdk.internal.classfile.impl.AccessFlagsImpl; import jdk.internal.classfile.impl.ChainedFieldBuilder; import jdk.internal.classfile.impl.TerminalFieldBuilder; -import java.lang.reflect.AccessFlag; - -import java.util.function.Consumer; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/FieldElement.java b/src/java.base/share/classes/java/lang/classfile/FieldElement.java index c41c9224bd39b..b4af99719818c 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldElement.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldElement.java @@ -24,15 +24,8 @@ */ package java.lang.classfile; -import java.lang.classfile.attribute.ConstantValueAttribute; -import java.lang.classfile.attribute.DeprecatedAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.SignatureAttribute; -import java.lang.classfile.attribute.SyntheticAttribute; -import java.lang.classfile.attribute.UnknownAttribute; +import java.lang.classfile.attribute.*; + import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/FieldModel.java b/src/java.base/share/classes/java/lang/classfile/FieldModel.java index 006103d5f9cbc..c45f3e88d5dcb 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldModel.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldModel.java @@ -25,10 +25,10 @@ package java.lang.classfile; +import java.lang.classfile.constantpool.Utf8Entry; import java.lang.constant.ClassDesc; import java.util.Optional; -import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.BufferedFieldBuilder; import jdk.internal.classfile.impl.FieldImpl; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/FieldTransform.java b/src/java.base/share/classes/java/lang/classfile/FieldTransform.java index 4e39f1e9c7fec..78a6f5ead2f79 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldTransform.java @@ -31,6 +31,8 @@ import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A transformation on streams of {@link FieldElement}. * @@ -62,7 +64,7 @@ public void accept(FieldBuilder builder, FieldElement element) { * @return the stateful field transform */ static FieldTransform ofStateful(Supplier supplier) { - return new TransformImpl.SupplierFieldTransform(supplier); + return new TransformImpl.SupplierFieldTransform(requireNonNull(supplier)); } /** @@ -73,6 +75,7 @@ static FieldTransform ofStateful(Supplier supplier) { * @return the field transform */ static FieldTransform endHandler(Consumer finisher) { + requireNonNull(finisher); return new FieldTransform() { @Override public void accept(FieldBuilder builder, FieldElement element) { @@ -94,6 +97,7 @@ public void atEnd(FieldBuilder builder) { * @return the field transform */ static FieldTransform dropping(Predicate filter) { + requireNonNull(filter); return (b, e) -> { if (!filter.test(e)) b.with(e); @@ -109,6 +113,6 @@ static FieldTransform dropping(Predicate filter) { */ @Override default FieldTransform andThen(FieldTransform t) { - return new TransformImpl.ChainedFieldTransform(this, t); + return new TransformImpl.ChainedFieldTransform(this, requireNonNull(t)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/Instruction.java b/src/java.base/share/classes/java/lang/classfile/Instruction.java index 08255d8a5b106..210c1e1b0da7b 100644 --- a/src/java.base/share/classes/java/lang/classfile/Instruction.java +++ b/src/java.base/share/classes/java/lang/classfile/Instruction.java @@ -25,32 +25,9 @@ package java.lang.classfile; +import java.lang.classfile.instruction.*; + import jdk.internal.classfile.impl.AbstractInstruction; -import java.lang.classfile.instruction.ArrayLoadInstruction; -import java.lang.classfile.instruction.ArrayStoreInstruction; -import java.lang.classfile.instruction.BranchInstruction; -import java.lang.classfile.instruction.ConstantInstruction; -import java.lang.classfile.instruction.ConvertInstruction; -import java.lang.classfile.instruction.DiscontinuedInstruction; -import java.lang.classfile.instruction.FieldInstruction; -import java.lang.classfile.instruction.IncrementInstruction; -import java.lang.classfile.instruction.InvokeDynamicInstruction; -import java.lang.classfile.instruction.InvokeInstruction; -import java.lang.classfile.instruction.LoadInstruction; -import java.lang.classfile.instruction.LookupSwitchInstruction; -import java.lang.classfile.instruction.MonitorInstruction; -import java.lang.classfile.instruction.NewMultiArrayInstruction; -import java.lang.classfile.instruction.NewObjectInstruction; -import java.lang.classfile.instruction.NewPrimitiveArrayInstruction; -import java.lang.classfile.instruction.NewReferenceArrayInstruction; -import java.lang.classfile.instruction.NopInstruction; -import java.lang.classfile.instruction.OperatorInstruction; -import java.lang.classfile.instruction.ReturnInstruction; -import java.lang.classfile.instruction.StackInstruction; -import java.lang.classfile.instruction.StoreInstruction; -import java.lang.classfile.instruction.TableSwitchInstruction; -import java.lang.classfile.instruction.ThrowInstruction; -import java.lang.classfile.instruction.TypeCheckInstruction; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/Interfaces.java b/src/java.base/share/classes/java/lang/classfile/Interfaces.java index 9092334bfb483..ff1dda17de8cd 100644 --- a/src/java.base/share/classes/java/lang/classfile/Interfaces.java +++ b/src/java.base/share/classes/java/lang/classfile/Interfaces.java @@ -24,11 +24,11 @@ */ package java.lang.classfile; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; import java.util.Arrays; import java.util.List; -import java.lang.classfile.constantpool.ClassEntry; import jdk.internal.classfile.impl.InterfacesImpl; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java index 7c230760f6934..6607d19b0acbe 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java @@ -25,14 +25,13 @@ package java.lang.classfile; -import java.util.function.Consumer; - import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.reflect.AccessFlag; +import java.util.function.Consumer; import jdk.internal.classfile.impl.AccessFlagsImpl; import jdk.internal.classfile.impl.ChainedMethodBuilder; import jdk.internal.classfile.impl.TerminalMethodBuilder; -import java.lang.reflect.AccessFlag; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/MethodElement.java b/src/java.base/share/classes/java/lang/classfile/MethodElement.java index a744952de7a99..dd23548c36022 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodElement.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodElement.java @@ -24,19 +24,8 @@ */ package java.lang.classfile; -import java.lang.classfile.attribute.AnnotationDefaultAttribute; -import java.lang.classfile.attribute.DeprecatedAttribute; -import java.lang.classfile.attribute.ExceptionsAttribute; -import java.lang.classfile.attribute.MethodParametersAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.SignatureAttribute; -import java.lang.classfile.attribute.SyntheticAttribute; -import java.lang.classfile.attribute.UnknownAttribute; +import java.lang.classfile.attribute.*; + import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/MethodModel.java b/src/java.base/share/classes/java/lang/classfile/MethodModel.java index bd51f3c97d72e..568036e464d8b 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodModel.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodModel.java @@ -25,10 +25,10 @@ package java.lang.classfile; +import java.lang.classfile.constantpool.Utf8Entry; import java.lang.constant.MethodTypeDesc; import java.util.Optional; -import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.BufferedMethodBuilder; import jdk.internal.classfile.impl.MethodImpl; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/MethodSignature.java b/src/java.base/share/classes/java/lang/classfile/MethodSignature.java index 5e758b64be3f8..7235c368a4591 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodSignature.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodSignature.java @@ -26,11 +26,13 @@ import java.lang.constant.MethodTypeDesc; import java.util.List; + import jdk.internal.classfile.impl.SignaturesImpl; -import static java.util.Objects.requireNonNull; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * Models the generic signature of a method, as defined by JVMS {@jvms 4.7.9}. * diff --git a/src/java.base/share/classes/java/lang/classfile/MethodTransform.java b/src/java.base/share/classes/java/lang/classfile/MethodTransform.java index e7e024ebc3467..bf5786f3dc74b 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodTransform.java @@ -31,6 +31,8 @@ import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A transformation on streams of {@link MethodElement}. * @@ -62,6 +64,7 @@ public void accept(MethodBuilder builder, MethodElement element) { * @return the stateful method transform */ static MethodTransform ofStateful(Supplier supplier) { + requireNonNull(supplier); return new TransformImpl.SupplierMethodTransform(supplier); } @@ -73,6 +76,7 @@ static MethodTransform ofStateful(Supplier supplier) { * @return the method transform */ static MethodTransform endHandler(Consumer finisher) { + requireNonNull(finisher); return new MethodTransform() { @Override public void accept(MethodBuilder builder, MethodElement element) { @@ -94,6 +98,7 @@ public void atEnd(MethodBuilder builder) { * @return the method transform */ static MethodTransform dropping(Predicate filter) { + requireNonNull(filter); return (b, e) -> { if (!filter.test(e)) b.with(e); @@ -108,7 +113,7 @@ static MethodTransform dropping(Predicate filter) { * @return the class transform */ static MethodTransform transformingCode(CodeTransform xform) { - return new TransformImpl.MethodCodeTransform(xform); + return new TransformImpl.MethodCodeTransform(requireNonNull(xform)); } /** @@ -120,6 +125,6 @@ static MethodTransform transformingCode(CodeTransform xform) { */ @Override default MethodTransform andThen(MethodTransform t) { - return new TransformImpl.ChainedMethodTransform(this, t); + return new TransformImpl.ChainedMethodTransform(this, requireNonNull(t)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/PseudoInstruction.java b/src/java.base/share/classes/java/lang/classfile/PseudoInstruction.java index 8a2db569ba0c3..b152756acfd8d 100644 --- a/src/java.base/share/classes/java/lang/classfile/PseudoInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/PseudoInstruction.java @@ -31,6 +31,7 @@ import java.lang.classfile.instruction.LineNumber; import java.lang.classfile.instruction.LocalVariable; import java.lang.classfile.instruction.LocalVariableType; + import jdk.internal.classfile.impl.AbstractPseudoInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/Signature.java b/src/java.base/share/classes/java/lang/classfile/Signature.java index 739c3f1f3f397..7255a41528c01 100644 --- a/src/java.base/share/classes/java/lang/classfile/Signature.java +++ b/src/java.base/share/classes/java/lang/classfile/Signature.java @@ -25,14 +25,15 @@ package java.lang.classfile; import java.lang.constant.ClassDesc; -import jdk.internal.classfile.impl.SignaturesImpl; - import java.util.List; -import static java.util.Objects.requireNonNull; import java.util.Optional; + +import jdk.internal.classfile.impl.SignaturesImpl; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * Models generic Java type signatures, as defined in JVMS {@jvms 4.7.9.1}. * diff --git a/src/java.base/share/classes/java/lang/classfile/Superclass.java b/src/java.base/share/classes/java/lang/classfile/Superclass.java index 70b18bb14d0e2..a69fac6341a11 100644 --- a/src/java.base/share/classes/java/lang/classfile/Superclass.java +++ b/src/java.base/share/classes/java/lang/classfile/Superclass.java @@ -25,6 +25,7 @@ package java.lang.classfile; import java.lang.classfile.constantpool.ClassEntry; + import jdk.internal.classfile.impl.SuperclassImpl; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index 139c8eef835dc..38e5ea09a9328 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -25,10 +25,10 @@ package java.lang.classfile; -import java.util.List; - import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; +import java.util.List; + import jdk.internal.classfile.impl.TargetInfoImpl; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/TypeKind.java b/src/java.base/share/classes/java/lang/classfile/TypeKind.java index fdd8826f4eafd..bdbea7c8c54a3 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeKind.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeKind.java @@ -29,6 +29,7 @@ import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.invoke.TypeDescriptor; + import jdk.internal.javac.PreviewFeature; import jdk.internal.vm.annotation.Stable; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java index 018fcd65a34a9..4f147b0d63a47 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java @@ -29,6 +29,7 @@ import java.lang.classfile.Attribute; import java.lang.classfile.MethodElement; import java.lang.classfile.MethodModel; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; @@ -66,5 +67,4 @@ public sealed interface AnnotationDefaultAttribute static AnnotationDefaultAttribute of(AnnotationValue annotationDefault) { return new UnboundAttribute.UnboundAnnotationDefaultAttribute(annotationDefault); } - } diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java index 7cc784af1f413..26ef1d3ddafc8 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java @@ -25,11 +25,11 @@ package java.lang.classfile.attribute; -import java.util.List; - import java.lang.classfile.Attribute; import java.lang.classfile.BootstrapMethodEntry; import java.lang.classfile.constantpool.ConstantPool; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java index 7a8aac6b91e1a..a4b79be62f057 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java @@ -25,9 +25,9 @@ package java.lang.classfile.attribute; +import java.lang.classfile.Attribute; import java.util.List; -import java.lang.classfile.Attribute; import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java index f0bab0fde110f..3342c2648ed93 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java @@ -28,6 +28,7 @@ import java.lang.classfile.Attribute; import java.lang.classfile.CodeModel; import java.lang.classfile.Label; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CompilationIDAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CompilationIDAttribute.java index ab6ab43c5aed4..292b449c628f1 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CompilationIDAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CompilationIDAttribute.java @@ -28,6 +28,7 @@ import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; import java.lang.classfile.constantpool.Utf8Entry; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java index 390320c679c8a..cd87464855191 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java @@ -24,10 +24,11 @@ */ package java.lang.classfile.attribute; -import java.lang.constant.ConstantDesc; import java.lang.classfile.Attribute; import java.lang.classfile.FieldElement; import java.lang.classfile.constantpool.ConstantValueEntry; +import java.lang.constant.ConstantDesc; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java index f65f01f4e2a88..47c85c4b6c1d6 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java @@ -28,6 +28,7 @@ import java.lang.classfile.ClassElement; import java.lang.classfile.FieldElement; import java.lang.classfile.MethodElement; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java index 768019fa1d301..c760fdee04bbe 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java @@ -24,15 +24,15 @@ */ package java.lang.classfile.attribute; -import java.lang.constant.ClassDesc; -import java.lang.constant.MethodTypeDesc; -import java.util.Optional; - import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.NameAndTypeEntry; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.util.Optional; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; @@ -92,7 +92,7 @@ default Optional enclosingMethodType() { * immediately enclosed by a method or constructor} */ default Optional enclosingMethodTypeSymbol() { - return enclosingMethod().map(Util::methodTypeSymbol); + return enclosingMethodType().map(Util::methodTypeSymbol); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java index e12b9eb9fc3c7..91f07d94de90e 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java @@ -24,13 +24,13 @@ */ package java.lang.classfile.attribute; +import java.lang.classfile.Attribute; +import java.lang.classfile.MethodElement; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; import java.util.Arrays; import java.util.List; -import java.lang.classfile.Attribute; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.MethodElement; import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java index d6eaee796bae2..fca8cce7faae2 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java @@ -24,13 +24,12 @@ */ package java.lang.classfile.attribute; -import java.lang.constant.ClassDesc; -import java.util.Optional; -import java.util.Set; - import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.ClassDesc; import java.lang.reflect.AccessFlag; +import java.util.Optional; +import java.util.Set; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java index 0746d20b5b823..3b5d63822c498 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java @@ -25,10 +25,10 @@ package java.lang.classfile.attribute; -import java.util.List; - import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java index a31f4919688b7..bb636a8113f73 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java @@ -24,9 +24,9 @@ */ package java.lang.classfile.attribute; +import java.lang.classfile.Attribute; import java.util.List; -import java.lang.classfile.Attribute; import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableInfo.java index 0ef8542e05c55..177fc84248316 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableInfo.java @@ -24,8 +24,9 @@ */ package java.lang.classfile.attribute; -import java.lang.constant.ClassDesc; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.ClassDesc; + import jdk.internal.classfile.impl.BoundLocalVariable; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java index 745b6d8e8e23f..ad4e732073e35 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java @@ -25,10 +25,10 @@ package java.lang.classfile.attribute; import java.lang.classfile.Attribute; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; - -import java.util.List; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeInfo.java index e72c5984a370c..6ba5b409b5b72 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeInfo.java @@ -25,6 +25,7 @@ package java.lang.classfile.attribute; import java.lang.classfile.constantpool.Utf8Entry; + import jdk.internal.classfile.impl.BoundLocalVariableType; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java index c2475530e6c53..084b72d68381a 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java @@ -26,10 +26,10 @@ package java.lang.classfile.attribute; import java.lang.classfile.Attribute; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; - -import java.util.List; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java index e42caa74be356..b0961bf147691 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java @@ -24,12 +24,12 @@ */ package java.lang.classfile.attribute; +import java.lang.classfile.ClassFile; +import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.reflect.AccessFlag; import java.util.Optional; import java.util.Set; -import java.lang.classfile.constantpool.Utf8Entry; -import java.lang.reflect.AccessFlag; -import java.lang.classfile.ClassFile; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java index 81530086cdf3b..43a43d25bb733 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java @@ -25,10 +25,10 @@ package java.lang.classfile.attribute; -import java.util.List; - import java.lang.classfile.Attribute; import java.lang.classfile.MethodElement; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java index ec258611c70a1..7091bbd5c4276 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java @@ -24,24 +24,24 @@ */ package java.lang.classfile.attribute; -import java.lang.constant.ClassDesc; -import java.util.Collection; import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ModuleEntry; import java.lang.classfile.constantpool.Utf8Entry; -import jdk.internal.classfile.impl.BoundAttribute; -import jdk.internal.classfile.impl.UnboundAttribute; - +import java.lang.constant.ClassDesc; +import java.lang.constant.ModuleDesc; +import java.lang.constant.PackageDesc; +import java.lang.reflect.AccessFlag; +import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; -import java.lang.reflect.AccessFlag; -import java.lang.constant.ModuleDesc; -import java.lang.constant.PackageDesc; + +import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.ModuleAttributeBuilderImpl; +import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java index 88b446ab200ba..4a534894e9e16 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java @@ -24,17 +24,16 @@ */ package java.lang.classfile.attribute; -import java.util.Collection; -import java.util.List; -import java.util.Set; - +import java.lang.classfile.ClassFile; import java.lang.classfile.constantpool.ModuleEntry; import java.lang.classfile.constantpool.PackageEntry; import java.lang.constant.ModuleDesc; import java.lang.constant.PackageDesc; import java.lang.reflect.AccessFlag; +import java.util.Collection; +import java.util.List; +import java.util.Set; -import java.lang.classfile.ClassFile; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashInfo.java index 88bb849db6fc2..0c85dd14125f9 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashInfo.java @@ -26,6 +26,7 @@ import java.lang.classfile.constantpool.ModuleEntry; import java.lang.constant.ModuleDesc; + import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java index d0ff0f8a1076b..0d2eb7014841c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java @@ -27,10 +27,9 @@ import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; - +import java.lang.classfile.constantpool.Utf8Entry; import java.util.List; -import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java index 91fe3c8f2d79c..67d6e5cc15c71 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java @@ -25,10 +25,11 @@ package java.lang.classfile.attribute; -import java.lang.constant.ClassDesc; import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; import java.lang.classfile.constantpool.ClassEntry; +import java.lang.constant.ClassDesc; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java index 0fac2def865f6..7c5fe948d7807 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java @@ -24,15 +24,14 @@ */ package java.lang.classfile.attribute; -import java.util.Collection; -import java.util.List; -import java.util.Set; - import java.lang.classfile.constantpool.ModuleEntry; import java.lang.classfile.constantpool.PackageEntry; import java.lang.constant.ModuleDesc; import java.lang.constant.PackageDesc; import java.lang.reflect.AccessFlag; +import java.util.Collection; +import java.util.List; +import java.util.Set; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java index 30bc0e9827b5f..f2b34ad107dbe 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java @@ -26,13 +26,12 @@ import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; -import jdk.internal.classfile.impl.BoundAttribute; - +import java.lang.classfile.constantpool.PackageEntry; +import java.lang.constant.PackageDesc; import java.util.Arrays; import java.util.List; -import java.lang.classfile.constantpool.PackageEntry; -import java.lang.constant.PackageDesc; +import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java index eabdd735073e7..266c73de04f2b 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java @@ -24,11 +24,11 @@ */ package java.lang.classfile.attribute; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; import java.util.Arrays; import java.util.List; -import java.lang.classfile.constantpool.ClassEntry; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java index 9220c9a6ce967..d072d0fead885 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java @@ -24,14 +24,14 @@ */ package java.lang.classfile.attribute; +import java.lang.classfile.constantpool.ModuleEntry; +import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.ModuleDesc; +import java.lang.reflect.AccessFlag; import java.util.Collection; import java.util.Optional; import java.util.Set; -import java.lang.classfile.constantpool.ModuleEntry; -import java.lang.classfile.constantpool.Utf8Entry; -import java.lang.reflect.AccessFlag; -import java.lang.constant.ModuleDesc; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java index fcae1e8aac76c..a6b17fa404152 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java @@ -27,6 +27,7 @@ import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleTargetAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleTargetAttribute.java index 7086336547787..226412eccf34c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleTargetAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleTargetAttribute.java @@ -28,6 +28,7 @@ import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; import java.lang.classfile.constantpool.Utf8Entry; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java index 0961601e5d46d..6b69f9cbe080c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java @@ -25,10 +25,11 @@ package java.lang.classfile.attribute; -import java.lang.constant.ClassDesc; import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; import java.lang.classfile.constantpool.ClassEntry; +import java.lang.constant.ClassDesc; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java index f184df7fff509..8826b4953a598 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java @@ -24,13 +24,13 @@ */ package java.lang.classfile.attribute; +import java.lang.classfile.Attribute; +import java.lang.classfile.ClassElement; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; import java.util.Arrays; import java.util.List; -import java.lang.classfile.Attribute; -import java.lang.classfile.ClassElement; -import java.lang.classfile.constantpool.ClassEntry; import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java index 2d86d4d26e0a0..1242bc6e04543 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java @@ -24,13 +24,13 @@ */ package java.lang.classfile.attribute; +import java.lang.classfile.Attribute; +import java.lang.classfile.ClassElement; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; import java.util.Arrays; import java.util.List; -import java.lang.classfile.Attribute; -import java.lang.classfile.ClassElement; -import java.lang.classfile.constantpool.ClassEntry; import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java index f79538a135cf9..7ef3b6f41b665 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java @@ -25,10 +25,10 @@ package java.lang.classfile.attribute; -import java.util.List; - import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java index 5a4c0d87b839a..ef6385653ed53 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java @@ -24,12 +24,12 @@ */ package java.lang.classfile.attribute; -import java.lang.constant.ClassDesc; -import java.util.List; - import java.lang.classfile.Attribute; import java.lang.classfile.AttributedElement; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.ClassDesc; +import java.util.List; + import jdk.internal.classfile.impl.BoundRecordComponentInfo; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java index b467e8504fe06..05635af4beb4f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java @@ -25,11 +25,15 @@ package java.lang.classfile.attribute; -import java.lang.classfile.*; +import java.lang.classfile.Annotation; +import java.lang.classfile.Attribute; +import java.lang.classfile.ClassElement; +import java.lang.classfile.FieldElement; +import java.lang.classfile.MethodElement; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; - -import java.util.List; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java index af495788afa45..edb82c49900ff 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java @@ -25,12 +25,12 @@ package java.lang.classfile.attribute; -import java.util.List; - import java.lang.classfile.Annotation; import java.lang.classfile.Attribute; import java.lang.classfile.MethodElement; import java.lang.classfile.MethodModel; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java index 46dd2167541d9..df3a035d62099 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java @@ -25,14 +25,14 @@ package java.lang.classfile.attribute; -import java.util.List; - import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; import java.lang.classfile.CodeElement; import java.lang.classfile.FieldElement; import java.lang.classfile.MethodElement; import java.lang.classfile.TypeAnnotation; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java index 4454dac62a95f..6909518881807 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java @@ -25,11 +25,15 @@ package java.lang.classfile.attribute; -import java.lang.classfile.*; +import java.lang.classfile.Annotation; +import java.lang.classfile.Attribute; +import java.lang.classfile.ClassElement; +import java.lang.classfile.FieldElement; +import java.lang.classfile.MethodElement; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; - -import java.util.List; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java index 59f648199ca49..ef58d21f14ac4 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java @@ -25,12 +25,12 @@ package java.lang.classfile.attribute; -import java.util.List; - import java.lang.classfile.Annotation; import java.lang.classfile.Attribute; import java.lang.classfile.MethodElement; import java.lang.classfile.MethodModel; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java index 8bdf322803d83..20dc89d700cdd 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java @@ -25,14 +25,14 @@ package java.lang.classfile.attribute; -import java.util.List; - import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; import java.lang.classfile.CodeElement; import java.lang.classfile.FieldElement; import java.lang.classfile.MethodElement; import java.lang.classfile.TypeAnnotation; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java index 783b068c4e64c..ca4cc62852a5f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java @@ -25,15 +25,10 @@ package java.lang.classfile.attribute; -import java.lang.classfile.Attribute; -import java.lang.classfile.ClassElement; -import java.lang.classfile.ClassSignature; -import java.lang.classfile.FieldElement; -import java.lang.classfile.MethodElement; +import java.lang.classfile.*; import java.lang.classfile.constantpool.Utf8Entry; + import jdk.internal.classfile.impl.BoundAttribute; -import java.lang.classfile.MethodSignature; -import java.lang.classfile.Signature; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SourceDebugExtensionAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SourceDebugExtensionAttribute.java index 719fb2d1171c1..e181b7fb14a2e 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SourceDebugExtensionAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SourceDebugExtensionAttribute.java @@ -27,6 +27,7 @@ import java.lang.classfile.Attribute; import java.lang.classfile.ClassElement; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java index abfa4eb05ffc9..d6c40058e7b74 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java @@ -29,6 +29,7 @@ import java.lang.classfile.ClassElement; import java.lang.classfile.ClassModel; import java.lang.classfile.constantpool.Utf8Entry; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SourceIDAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SourceIDAttribute.java index a99a0bf49678c..69ff3bf57fd44 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SourceIDAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SourceIDAttribute.java @@ -29,6 +29,7 @@ import java.lang.classfile.ClassElement; import java.lang.classfile.ClassModel; import java.lang.classfile.constantpool.Utf8Entry; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.UnboundAttribute; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java index 3415c89174ae9..d041a73c58a1c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java @@ -25,11 +25,11 @@ package java.lang.classfile.attribute; +import java.lang.classfile.Label; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; import java.util.List; -import java.lang.classfile.Label; -import java.lang.classfile.constantpool.ClassEntry; import jdk.internal.classfile.impl.StackMapDecoder; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java index 74dd567060eab..a8aef4795d78d 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java @@ -25,10 +25,10 @@ package java.lang.classfile.attribute; -import java.util.List; - import java.lang.classfile.Attribute; import java.lang.classfile.CodeElement; +import java.util.List; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java index d1b7b8f0384dc..e5b5da7fbfe2e 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java @@ -29,6 +29,7 @@ import java.lang.classfile.ClassElement; import java.lang.classfile.FieldElement; import java.lang.classfile.MethodElement; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/UnknownAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/UnknownAttribute.java index 4e66836fbdce1..5c1369e13080f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/UnknownAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/UnknownAttribute.java @@ -29,6 +29,7 @@ import java.lang.classfile.ClassElement; import java.lang.classfile.FieldElement; import java.lang.classfile.MethodElement; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/components/ClassPrinter.java b/src/java.base/share/classes/java/lang/classfile/components/ClassPrinter.java index c2e93a955ed45..85768cbe6a457 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/ClassPrinter.java +++ b/src/java.base/share/classes/java/lang/classfile/components/ClassPrinter.java @@ -24,16 +24,16 @@ */ package java.lang.classfile.components; +import java.lang.classfile.ClassModel; +import java.lang.classfile.CodeModel; +import java.lang.classfile.CompoundElement; +import java.lang.classfile.FieldModel; +import java.lang.classfile.MethodModel; import java.lang.constant.ConstantDesc; import java.util.List; import java.util.Map; import java.util.function.Consumer; import java.util.stream.Stream; -import java.lang.classfile.ClassModel; -import java.lang.classfile.FieldModel; -import java.lang.classfile.MethodModel; -import java.lang.classfile.CodeModel; -import java.lang.classfile.CompoundElement; import jdk.internal.classfile.impl.ClassPrinterImpl; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java b/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java index d3ae180dde573..4f7bd3199d59d 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java +++ b/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.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 @@ -24,18 +24,21 @@ */ package java.lang.classfile.components; -import java.lang.constant.ClassDesc; -import java.util.Map; -import java.util.function.Function; +import java.lang.classfile.ClassFile; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassTransform; -import java.lang.classfile.ClassFile; import java.lang.classfile.CodeTransform; import java.lang.classfile.FieldTransform; import java.lang.classfile.MethodTransform; +import java.lang.constant.ClassDesc; +import java.util.Map; +import java.util.function.Function; + import jdk.internal.classfile.impl.ClassRemapperImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * {@code ClassRemapper} is a {@link ClassTransform}, {@link FieldTransform}, * {@link MethodTransform} and {@link CodeTransform} @@ -64,6 +67,7 @@ public sealed interface ClassRemapper extends ClassTransform permits ClassRemapp * @return new instance of {@code ClassRemapper} */ static ClassRemapper of(Map classMap) { + requireNonNull(classMap); return of(desc -> classMap.getOrDefault(desc, desc)); } @@ -75,7 +79,7 @@ static ClassRemapper of(Map classMap) { * @return new instance of {@code ClassRemapper} */ static ClassRemapper of(Function mapFunction) { - return new ClassRemapperImpl(mapFunction); + return new ClassRemapperImpl(requireNonNull(mapFunction)); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/components/CodeLocalsShifter.java b/src/java.base/share/classes/java/lang/classfile/components/CodeLocalsShifter.java index fa75e9f002b5e..4983872246102 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/CodeLocalsShifter.java +++ b/src/java.base/share/classes/java/lang/classfile/components/CodeLocalsShifter.java @@ -24,11 +24,12 @@ */ package java.lang.classfile.components; -import java.lang.constant.MethodTypeDesc; -import java.lang.reflect.AccessFlag; import java.lang.classfile.AccessFlags; import java.lang.classfile.CodeTransform; import java.lang.classfile.TypeKind; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; + import jdk.internal.classfile.impl.CodeLocalsShifterImpl; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java b/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java index ca5ad90389c5c..247d712e4f382 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java +++ b/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java @@ -24,15 +24,18 @@ */ package java.lang.classfile.components; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.function.BiFunction; import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeTransform; import java.lang.classfile.Label; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.function.BiFunction; + import jdk.internal.classfile.impl.CodeRelabelerImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A code relabeler is a {@link CodeTransform} replacing all occurrences * of {@link java.lang.classfile.Label} in the transformed code with new instances. @@ -62,6 +65,7 @@ static CodeRelabeler of() { * @return a new instance of CodeRelabeler */ static CodeRelabeler of(Map map) { + requireNonNull(map); return of((l, cob) -> map.computeIfAbsent(l, ll -> cob.newLabel())); } @@ -72,6 +76,6 @@ static CodeRelabeler of(Map map) { * @return a new instance of CodeRelabeler */ static CodeRelabeler of(BiFunction mapFunction) { - return new CodeRelabelerImpl(mapFunction); + return new CodeRelabelerImpl(requireNonNull(mapFunction)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/components/CodeStackTracker.java b/src/java.base/share/classes/java/lang/classfile/components/CodeStackTracker.java index 1b711cfad0ec3..1ee0b0948e112 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/CodeStackTracker.java +++ b/src/java.base/share/classes/java/lang/classfile/components/CodeStackTracker.java @@ -24,11 +24,12 @@ */ package java.lang.classfile.components; -import java.util.Collection; -import java.util.Optional; import java.lang.classfile.CodeTransform; import java.lang.classfile.Label; import java.lang.classfile.TypeKind; +import java.util.Collection; +import java.util.Optional; + import jdk.internal.classfile.impl.CodeStackTrackerImpl; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java b/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java index 2e7fb121a373b..87c2146a7acae 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java +++ b/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java @@ -24,32 +24,22 @@ */ package java.lang.classfile.components.snippets; +import java.lang.classfile.*; +import java.lang.classfile.components.ClassPrinter; +import java.lang.classfile.components.ClassRemapper; +import java.lang.classfile.components.CodeLocalsShifter; +import java.lang.classfile.components.CodeRelabeler; +import java.lang.classfile.instruction.InvokeInstruction; +import java.lang.classfile.instruction.ReturnInstruction; +import java.lang.classfile.instruction.StoreInstruction; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; - import java.lang.constant.ConstantDescs; import java.lang.reflect.AccessFlag; import java.util.ArrayDeque; import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.lang.classfile.ClassFile; -import java.lang.classfile.ClassModel; -import java.lang.classfile.ClassTransform; -import java.lang.classfile.CodeModel; -import java.lang.classfile.CodeTransform; -import java.lang.classfile.FieldModel; -import java.lang.classfile.MethodModel; -import java.lang.classfile.TypeKind; -import java.lang.classfile.instruction.InvokeInstruction; - -import java.lang.classfile.MethodTransform; -import java.lang.classfile.components.ClassPrinter; -import java.lang.classfile.components.ClassRemapper; -import java.lang.classfile.components.CodeLocalsShifter; -import java.lang.classfile.components.CodeRelabeler; -import java.lang.classfile.instruction.ReturnInstruction; -import java.lang.classfile.instruction.StoreInstruction; class PackageSnippets { diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java index d405f68570ebe..6365fc3636a40 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java @@ -26,6 +26,7 @@ import java.lang.classfile.AnnotationValue; import java.lang.constant.ConstantDesc; + import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ClassEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ClassEntry.java index db2135c84f5d9..9e5f1f5204927 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ClassEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ClassEntry.java @@ -26,6 +26,7 @@ import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; + import jdk.internal.classfile.impl.AbstractPoolEntry; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java index 144c8a539d72c..7c55a09f3f4c8 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java @@ -25,13 +25,12 @@ package java.lang.classfile.constantpool; import java.lang.classfile.TypeKind; -import jdk.internal.classfile.impl.Util; - import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; import java.lang.constant.DynamicConstantDesc; import jdk.internal.classfile.impl.AbstractPoolEntry; +import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; /** @@ -50,7 +49,7 @@ public sealed interface ConstantDynamicEntry * {@return a symbolic descriptor for the dynamic constant's type} */ default ClassDesc typeSymbol() { - return Util.fieldTypeSymbol(nameAndType()); + return Util.fieldTypeSymbol(type()); } @Override diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPool.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPool.java index ef6f75955b29e..0225f6ec77d8c 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPool.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPool.java @@ -25,10 +25,11 @@ package java.lang.classfile.constantpool; -import java.util.Iterator; -import java.util.NoSuchElementException; import java.lang.classfile.BootstrapMethodEntry; import java.lang.classfile.ClassReader; +import java.util.Iterator; +import java.util.NoSuchElementException; + import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index 1c0d6e55e3143..0ce4a6868c86a 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -24,26 +24,19 @@ */ package java.lang.classfile.constantpool; -import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDesc; -import java.lang.constant.DirectMethodHandleDesc; -import java.lang.constant.DynamicCallSiteDesc; -import java.lang.constant.DynamicConstantDesc; -import java.lang.constant.MethodTypeDesc; -import java.util.List; - import java.lang.classfile.BootstrapMethodEntry; import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassModel; -import jdk.internal.classfile.impl.ClassReaderImpl; -import java.lang.constant.ModuleDesc; -import java.lang.constant.PackageDesc; +import java.lang.constant.*; +import java.util.List; + import jdk.internal.classfile.impl.AbstractPoolEntry.ClassEntryImpl; -import jdk.internal.classfile.impl.AbstractPoolEntry.NameAndTypeEntryImpl; +import jdk.internal.classfile.impl.ClassReaderImpl; import jdk.internal.classfile.impl.SplitConstantPool; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; + import static java.util.Objects.requireNonNull; /** @@ -470,10 +463,11 @@ default StringEntry stringEntry(String value) { } /** - * {@return A {@link ConstantValueEntry} descripbing the provided + * {@return A {@link ConstantValueEntry} describing the provided * Integer, Long, Float, Double, or String constant} * * @param c the constant + * @see ConstantValueEntry#constantValue() */ default ConstantValueEntry constantValueEntry(ConstantDesc c) { if (c instanceof Integer i) return intEntry(i); diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java index 340baeb905fd6..924d0aca71080 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.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 @@ -24,13 +24,15 @@ */ package java.lang.classfile.constantpool; +import java.lang.classfile.Attributes; import java.lang.constant.ConstantDesc; + import jdk.internal.javac.PreviewFeature; /** * Models a constant pool entry that can be used as the constant in a - * {@code ConstantValue} attribute; this includes the four primitive constant - * types and {@linkplain String} constants. + * {@link Attributes#constantValue() ConstantValue} attribute; this includes the four + * primitive constant types and {@linkplain String} constants. * * @sealedGraph * @since 22 @@ -42,6 +44,8 @@ public sealed interface ConstantValueEntry extends LoadableConstantEntry /** * {@return the constant value} The constant value will be an {@link Integer}, * {@link Long}, {@link Float}, {@link Double}, or {@link String}. + * + * @see ConstantPoolBuilder#constantValueEntry(ConstantDesc) */ @Override ConstantDesc constantValue(); diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/DoubleEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/DoubleEntry.java index 391dcf021eb4b..8dd4ba1ffd934 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/DoubleEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/DoubleEntry.java @@ -25,6 +25,7 @@ package java.lang.classfile.constantpool; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractPoolEntry; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/DynamicConstantPoolEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/DynamicConstantPoolEntry.java index 41ed4b298047f..ac7630494100c 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/DynamicConstantPoolEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/DynamicConstantPoolEntry.java @@ -25,6 +25,7 @@ package java.lang.classfile.constantpool; import java.lang.classfile.BootstrapMethodEntry; + import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java index 628abdac6fe43..ab122f410b699 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java @@ -24,10 +24,11 @@ */ package java.lang.classfile.constantpool; +import java.lang.constant.ClassDesc; + import jdk.internal.classfile.impl.AbstractPoolEntry; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; -import java.lang.constant.ClassDesc; /** * Models a {@code CONSTANT_Fieldref_info} constant in the constant pool of a @@ -44,6 +45,6 @@ public sealed interface FieldRefEntry extends MemberRefEntry * {@return a symbolic descriptor for the field's type} */ default ClassDesc typeSymbol() { - return Util.fieldTypeSymbol(nameAndType()); + return Util.fieldTypeSymbol(type()); } } diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/FloatEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/FloatEntry.java index d84cc903ea5ea..7a91dd111530f 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/FloatEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/FloatEntry.java @@ -25,6 +25,7 @@ package java.lang.classfile.constantpool; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractPoolEntry; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/IntegerEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/IntegerEntry.java index 807ce188a6acb..7cd21e37db824 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/IntegerEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/IntegerEntry.java @@ -25,6 +25,7 @@ package java.lang.classfile.constantpool; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractPoolEntry; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java index 43faa488bb915..8f15053e5b705 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java @@ -24,10 +24,11 @@ */ package java.lang.classfile.constantpool; +import java.lang.constant.MethodTypeDesc; + import jdk.internal.classfile.impl.AbstractPoolEntry; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; -import java.lang.constant.MethodTypeDesc; /** * Models a {@code CONSTANT_InterfaceMethodRef_info} constant in the constant pool of a @@ -45,6 +46,6 @@ public sealed interface InterfaceMethodRefEntry * {@return a symbolic descriptor for the interface method's type} */ default MethodTypeDesc typeSymbol() { - return Util.methodTypeSymbol(nameAndType()); + return Util.methodTypeSymbol(type()); } } diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/InvokeDynamicEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/InvokeDynamicEntry.java index d9a1c29997299..f06c3d4c7828c 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/InvokeDynamicEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/InvokeDynamicEntry.java @@ -47,7 +47,7 @@ public sealed interface InvokeDynamicEntry * {@return a symbolic descriptor for the call site's invocation type} */ default MethodTypeDesc typeSymbol() { - return Util.methodTypeSymbol(nameAndType()); + return Util.methodTypeSymbol(type()); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/LoadableConstantEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/LoadableConstantEntry.java index 6ae8e68787eaf..c963e2425eac4 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/LoadableConstantEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/LoadableConstantEntry.java @@ -24,8 +24,9 @@ */ package java.lang.classfile.constantpool; -import java.lang.constant.ConstantDesc; import java.lang.classfile.TypeKind; +import java.lang.constant.ConstantDesc; + import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/LongEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/LongEntry.java index 975df03f04343..75e02b1944192 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/LongEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/LongEntry.java @@ -25,6 +25,7 @@ package java.lang.classfile.constantpool; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractPoolEntry; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java index 39684db462134..ff3f5e5220ccd 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java @@ -24,10 +24,11 @@ */ package java.lang.classfile.constantpool; +import java.lang.constant.MethodTypeDesc; + import jdk.internal.classfile.impl.AbstractPoolEntry; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; -import java.lang.constant.MethodTypeDesc; /** * Models a {@code CONSTANT_MethodRef_info} constant in the constant pool of a @@ -44,6 +45,6 @@ public sealed interface MethodRefEntry extends MemberRefEntry * {@return a symbolic descriptor for the method's type} */ default MethodTypeDesc typeSymbol() { - return Util.methodTypeSymbol(nameAndType()); + return Util.methodTypeSymbol(type()); } } diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ModuleEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ModuleEntry.java index cbddf6b90e3a4..db7aa1f76fe1a 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ModuleEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ModuleEntry.java @@ -24,8 +24,9 @@ */ package java.lang.classfile.constantpool; -import jdk.internal.classfile.impl.AbstractPoolEntry; import java.lang.constant.ModuleDesc; + +import jdk.internal.classfile.impl.AbstractPoolEntry; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/PackageEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/PackageEntry.java index 1817aa647d4aa..5725d411028c1 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/PackageEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/PackageEntry.java @@ -24,8 +24,9 @@ */ package java.lang.classfile.constantpool; -import jdk.internal.classfile.impl.AbstractPoolEntry; import java.lang.constant.PackageDesc; + +import jdk.internal.classfile.impl.AbstractPoolEntry; import jdk.internal.javac.PreviewFeature; /** diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ArrayLoadInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ArrayLoadInstruction.java index e773d2da2ccae..b66627ef212a6 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ArrayLoadInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ArrayLoadInstruction.java @@ -29,6 +29,7 @@ import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ArrayStoreInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ArrayStoreInstruction.java index 9b9ec6018d1f2..f009cfca36129 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ArrayStoreInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ArrayStoreInstruction.java @@ -29,6 +29,7 @@ import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/BranchInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/BranchInstruction.java index 6ee47b7fbc2c1..6b2142fa0e101 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/BranchInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/BranchInstruction.java @@ -29,6 +29,7 @@ import java.lang.classfile.Instruction; import java.lang.classfile.Label; import java.lang.classfile.Opcode; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java index fca3279cd2228..3d04473ab3750 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java @@ -31,6 +31,7 @@ import java.lang.classfile.PseudoInstruction; import java.lang.classfile.attribute.CharacterRangeInfo; import java.lang.classfile.attribute.CharacterRangeTableAttribute; + import jdk.internal.classfile.impl.AbstractPseudoInstruction; import jdk.internal.classfile.impl.BoundCharacterRange; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java index 6f07805a1e81c..c41793c614e7f 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java @@ -24,14 +24,14 @@ */ package java.lang.classfile.instruction; -import java.lang.constant.ConstantDesc; - import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; import java.lang.classfile.constantpool.LoadableConstantEntry; +import java.lang.constant.ConstantDesc; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.BytecodeHelpers; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java index daa7e60248470..ec48c2f46639f 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java @@ -29,6 +29,7 @@ import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.BytecodeHelpers; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java index 84bead6d8ccb4..0e4718a1c77c8 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.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.lang.classfile.Instruction; import java.lang.classfile.Label; import java.lang.classfile.Opcode; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.BytecodeHelpers; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java index 9ed851fff88ed..22b6f632abcf3 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java @@ -24,13 +24,13 @@ */ package java.lang.classfile.instruction; -import java.util.Optional; - import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; -import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.Label; import java.lang.classfile.PseudoInstruction; +import java.lang.classfile.constantpool.ClassEntry; +import java.util.Optional; + import jdk.internal.classfile.impl.AbstractPseudoInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java index 43dbcccf75eaa..c8a82fe7dfa89 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java @@ -24,16 +24,16 @@ */ package java.lang.classfile.instruction; -import java.lang.constant.ClassDesc; - import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; -import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.FieldRefEntry; import java.lang.classfile.constantpool.NameAndTypeEntry; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.ClassDesc; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java index bebb101d7f326..74fd6a4465a1f 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java @@ -28,6 +28,7 @@ import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java index 708b284c0bf57..6df960b88fab8 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java @@ -24,18 +24,18 @@ */ package java.lang.classfile.instruction; -import java.lang.constant.ConstantDesc; -import java.lang.constant.DirectMethodHandleDesc; -import java.lang.constant.MethodTypeDesc; -import java.util.List; -import java.util.function.Function; - import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.constantpool.InvokeDynamicEntry; import java.lang.classfile.constantpool.LoadableConstantEntry; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.ConstantDesc; +import java.lang.constant.DirectMethodHandleDesc; +import java.lang.constant.MethodTypeDesc; +import java.util.List; +import java.util.function.Function; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java index ff68abce3d21e..41ca5fd1519ef 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java @@ -24,18 +24,18 @@ */ package java.lang.classfile.instruction; -import java.lang.constant.MethodTypeDesc; - import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; -import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.InterfaceMethodRefEntry; import java.lang.classfile.constantpool.MemberRefEntry; import java.lang.classfile.constantpool.MethodRefEntry; import java.lang.classfile.constantpool.NameAndTypeEntry; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.MethodTypeDesc; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.Util; @@ -94,7 +94,7 @@ default Utf8Entry type() { * {@return a symbolic descriptor for the method type} */ default MethodTypeDesc typeSymbol() { - return Util.methodTypeSymbol(method().nameAndType()); + return Util.methodTypeSymbol(method().type()); } diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java b/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java index 80b3ea4785d90..8682d0ee508e6 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java @@ -28,6 +28,7 @@ import java.lang.classfile.CodeModel; import java.lang.classfile.Label; import java.lang.classfile.PseudoInstruction; + import jdk.internal.classfile.impl.LabelImpl; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java b/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java index 3990fe1f5e286..a06e7cfcebac2 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java @@ -29,6 +29,7 @@ import java.lang.classfile.CodeModel; import java.lang.classfile.PseudoInstruction; import java.lang.classfile.attribute.LineNumberTableAttribute; + import jdk.internal.classfile.impl.LineNumberImpl; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java index ea10ba6a0d0fb..ce6463ef92478 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java @@ -29,6 +29,7 @@ import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.BytecodeHelpers; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java index 6ddbbde8cea86..ce6c0cce10999 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java @@ -24,12 +24,12 @@ */ package java.lang.classfile.instruction; -import java.util.List; - import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.Label; +import java.util.List; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java index d0148b34aee65..9bec7805339d2 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java @@ -28,6 +28,7 @@ import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java index 2c572c607b4f4..f5e0129205cfb 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java @@ -26,8 +26,9 @@ import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; -import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.Instruction; +import java.lang.classfile.constantpool.ClassEntry; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.BytecodeHelpers; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java index fbfbb0da47b31..e6e8fc64d1763 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java @@ -26,8 +26,9 @@ import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; -import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.Instruction; +import java.lang.classfile.constantpool.ClassEntry; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java index cbc8f2068a8ad..4adc7536c2cfd 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java @@ -28,6 +28,7 @@ import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java index 7226850cc34cf..b622f915c464e 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java @@ -26,8 +26,9 @@ import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; -import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.Instruction; +import java.lang.classfile.constantpool.ClassEntry; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java index e47d2eb5f2b51..3183ad888161e 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java @@ -27,6 +27,7 @@ import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java index aeaa4109d7bd6..602f34ec03e0b 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java @@ -29,6 +29,7 @@ import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java index fbfd22210d3dd..6596404a58282 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java @@ -29,6 +29,7 @@ import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.BytecodeHelpers; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java index 9b2e0b6904387..17e9496652b90 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java @@ -28,6 +28,7 @@ import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java index 5bfe13421da35..68bf54e61c28b 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java @@ -29,6 +29,7 @@ import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.BytecodeHelpers; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java b/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java index 0db88fa4b6338..6149945532bf1 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java @@ -25,6 +25,7 @@ package java.lang.classfile.instruction; import java.lang.classfile.Label; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java index bdcc2326f4a28..a8bce119db2f8 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java @@ -24,12 +24,12 @@ */ package java.lang.classfile.instruction; -import java.util.List; - import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.Label; +import java.util.List; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java index 86c964cb61e12..68d861ba06dbe 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java @@ -27,6 +27,7 @@ import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.javac.PreviewFeature; diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java index d93f5244ca962..a4b9818a4bebd 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java @@ -24,13 +24,13 @@ */ package java.lang.classfile.instruction; -import java.lang.constant.ClassDesc; - import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; -import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.constant.ClassDesc; + import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java b/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java index 46e057210ac74..c6956d6d23a7f 100644 --- a/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java +++ b/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java @@ -24,43 +24,25 @@ */ package java.lang.classfile.snippets; -import java.lang.classfile.ClassBuilder; +import java.lang.classfile.*; +import java.lang.classfile.components.ClassRemapper; +import java.lang.classfile.components.CodeLocalsShifter; +import java.lang.classfile.components.CodeRelabeler; +import java.lang.classfile.instruction.*; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandles; +import java.lang.reflect.AccessFlag; import java.util.ArrayDeque; import java.util.HashSet; -import java.util.Set; - -import java.lang.reflect.AccessFlag; import java.util.Map; +import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; -import java.lang.classfile.ClassElement; -import java.lang.classfile.ClassHierarchyResolver; -import java.lang.classfile.ClassModel; -import java.lang.classfile.ClassTransform; -import java.lang.classfile.ClassFile; -import java.lang.classfile.ClassFileVersion; -import java.lang.classfile.CodeBuilder; -import java.lang.classfile.CodeElement; -import java.lang.classfile.CodeModel; -import java.lang.classfile.CodeTransform; -import java.lang.classfile.FieldModel; -import java.lang.classfile.MethodElement; -import java.lang.classfile.MethodModel; -import java.lang.classfile.Opcode; -import java.lang.classfile.PseudoInstruction; -import java.lang.classfile.TypeKind; -import java.lang.classfile.instruction.*; - import static java.util.stream.Collectors.toSet; -import java.lang.classfile.components.ClassRemapper; -import java.lang.classfile.components.CodeLocalsShifter; -import java.lang.classfile.components.CodeRelabeler; class PackageSnippets { void enumerateFieldsMethods1(byte[] bytes) { diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index b93d95223529e..9f58a4f94da3b 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -26,22 +26,13 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.TypeDescriptor; -import java.util.stream.Stream; +import jdk.internal.constant.ArrayClassDescImpl; +import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.PrimitiveClassDescImpl; -import jdk.internal.constant.ReferenceClassDescImpl; -import sun.invoke.util.Wrapper; +import jdk.internal.constant.ClassOrInterfaceDescImpl; -import static java.util.stream.Collectors.joining; -import static jdk.internal.constant.ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS; -import static jdk.internal.constant.ConstantUtils.arrayDepth; -import static jdk.internal.constant.ConstantUtils.binaryToInternal; -import static jdk.internal.constant.ConstantUtils.concat; -import static jdk.internal.constant.ConstantUtils.forPrimitiveType; -import static jdk.internal.constant.ConstantUtils.internalToBinary; -import static jdk.internal.constant.ConstantUtils.validateBinaryClassName; -import static jdk.internal.constant.ConstantUtils.validateInternalClassName; -import static jdk.internal.constant.ConstantUtils.validateMemberName; +import static jdk.internal.constant.ConstantUtils.*; /** * A nominal descriptor for a @@ -64,7 +55,8 @@ public sealed interface ClassDesc extends ConstantDesc, TypeDescriptor.OfField permits PrimitiveClassDescImpl, - ReferenceClassDescImpl { + ClassOrInterfaceDescImpl, + ArrayClassDescImpl { /** * Returns a {@linkplain ClassDesc} for a class or interface type, @@ -84,7 +76,7 @@ public sealed interface ClassDesc */ static ClassDesc of(String name) { validateBinaryClassName(name); - return ClassDesc.ofDescriptor(concat("L", binaryToInternal(name), ";")); + return ConstantUtils.binaryNameToDesc(name); } /** @@ -110,7 +102,7 @@ static ClassDesc of(String name) { */ static ClassDesc ofInternalName(String name) { validateInternalClassName(name); - return ClassDesc.ofDescriptor(concat("L", name, ";")); + return ConstantUtils.internalNameToDesc(name); } /** @@ -129,11 +121,11 @@ static ClassDesc ofInternalName(String name) { */ static ClassDesc of(String packageName, String className) { validateBinaryClassName(packageName); + validateMemberName(className, false); if (packageName.isEmpty()) { - return of(className); + return internalNameToDesc(className); } - validateMemberName(className, false); - return ofDescriptor('L' + binaryToInternal(packageName) + + return ClassOrInterfaceDescImpl.ofValidated('L' + binaryToInternal(packageName) + '/' + className + ';'); } @@ -168,7 +160,7 @@ static ClassDesc ofDescriptor(String descriptor) { return (descriptor.length() == 1) ? forPrimitiveType(descriptor, 0) // will throw IAE on descriptor.length == 0 or if array dimensions too long - : ReferenceClassDescImpl.of(descriptor); + : parseReferenceTypeDesc(descriptor); } /** @@ -180,20 +172,7 @@ static ClassDesc ofDescriptor(String descriptor) { * ClassDesc} would have an array rank of greater than 255 * @jvms 4.4.1 The CONSTANT_Class_info Structure */ - default ClassDesc arrayType() { - String desc = descriptorString(); - int depth = arrayDepth(desc); - if (depth >= MAX_ARRAY_TYPE_DESC_DIMENSIONS) { - throw new IllegalStateException( - "Cannot create an array type descriptor with more than " + - MAX_ARRAY_TYPE_DESC_DIMENSIONS + " dimensions"); - } - String newDesc = "[".concat(desc); - if (desc.length() == 1 && desc.charAt(0) == 'V') { - throw new IllegalArgumentException("not a valid reference type descriptor: " + newDesc); - } - return ReferenceClassDescImpl.ofValidated(newDesc); - } + ClassDesc arrayType(); /** * Returns a {@linkplain ClassDesc} for an array type of the specified rank, @@ -206,24 +185,7 @@ default ClassDesc arrayType() { * greater than 255 * @jvms 4.4.1 The CONSTANT_Class_info Structure */ - default ClassDesc arrayType(int rank) { - if (rank <= 0) { - throw new IllegalArgumentException("rank " + rank + " is not a positive value"); - } - String desc = descriptorString(); - long currentDepth = arrayDepth(desc); - long netRank = currentDepth + rank; - if (netRank > MAX_ARRAY_TYPE_DESC_DIMENSIONS) { - throw new IllegalArgumentException("rank: " + netRank + - " exceeds maximum supported dimension of " + - MAX_ARRAY_TYPE_DESC_DIMENSIONS); - } - String newDesc = new StringBuilder(desc.length() + rank).repeat('[', rank).append(desc).toString(); - if (desc.length() == 1 && desc.charAt(0) == 'V') { - throw new IllegalArgumentException("not a valid reference type descriptor: " + newDesc); - } - return ReferenceClassDescImpl.ofValidated(newDesc); - } + ClassDesc arrayType(int rank); /** * Returns a {@linkplain ClassDesc} for a nested class of the class or @@ -243,13 +205,7 @@ default ClassDesc arrayType(int rank) { * @throws IllegalArgumentException if the nested class name is invalid */ default ClassDesc nested(String nestedName) { - validateMemberName(nestedName, false); - if (!isClassOrInterface()) - throw new IllegalStateException("Outer class is not a class or interface type"); - String desc = descriptorString(); - StringBuilder sb = new StringBuilder(desc.length() + nestedName.length() + 1); - sb.append(desc, 0, desc.length() - 1).append('$').append(nestedName).append(';'); - return ReferenceClassDescImpl.ofValidated(sb.toString()); + throw new IllegalStateException("Outer class is not a class or interface type"); } /** @@ -266,16 +222,7 @@ default ClassDesc nested(String nestedName) { * @throws IllegalArgumentException if the nested class name is invalid */ default ClassDesc nested(String firstNestedName, String... moreNestedNames) { - if (!isClassOrInterface()) - throw new IllegalStateException("Outer class is not a class or interface type"); - validateMemberName(firstNestedName, false); - // implicit null-check - for (String addNestedNames : moreNestedNames) { - validateMemberName(addNestedNames, false); - } - return moreNestedNames.length == 0 - ? nested(firstNestedName) - : nested(firstNestedName + Stream.of(moreNestedNames).collect(joining("$", "$", ""))); + throw new IllegalStateException("Outer class is not a class or interface type"); } /** @@ -284,7 +231,7 @@ default ClassDesc nested(String firstNestedName, String... moreNestedNames) { * @return whether this {@linkplain ClassDesc} describes an array type */ default boolean isArray() { - return descriptorString().charAt(0) == '['; + return false; } /** @@ -293,7 +240,7 @@ default boolean isArray() { * @return whether this {@linkplain ClassDesc} describes a primitive type */ default boolean isPrimitive() { - return descriptorString().length() == 1; + return false; } /** @@ -302,7 +249,7 @@ default boolean isPrimitive() { * @return whether this {@linkplain ClassDesc} describes a class or interface type */ default boolean isClassOrInterface() { - return descriptorString().charAt(0) == 'L'; + return false; } /** @@ -313,14 +260,6 @@ default boolean isClassOrInterface() { * if this descriptor does not describe an array type */ default ClassDesc componentType() { - if (isArray()) { - String desc = descriptorString(); - if (desc.length() == 2) { - return Wrapper.forBasicType(desc.charAt(1)).basicClassDescriptor(); - } else { - return ReferenceClassDescImpl.ofValidated(desc.substring(1)); - } - } return null; } @@ -332,41 +271,17 @@ default ClassDesc componentType() { * default package, or this {@linkplain ClassDesc} does not describe a class or interface type */ default String packageName() { - if (!isClassOrInterface()) - return ""; - String desc = descriptorString(); - int index = desc.lastIndexOf('/'); - return (index == -1) ? "" : internalToBinary(desc.substring(1, index)); + return ""; } /** - * Returns a human-readable name for the type described by this descriptor. - * - * @implSpec - *

    The default implementation returns the simple name - * (e.g., {@code int}) for primitive types, the unqualified class name - * for class or interface types, or the display name of the component type - * suffixed with the appropriate number of {@code []} pairs for array types. - * - * @return the human-readable name + * {@return a human-readable name for this {@code ClassDesc}} + * For primitive types, this method returns the simple name (such as {@code int}). + * For class or interface types, this method returns the unqualified class name. + * For array types, this method returns the human-readable name of the component + * type suffixed with the appropriate number of {@code []} pairs. */ - default String displayName() { - if (isPrimitive()) - return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveSimpleName(); - else if (isClassOrInterface()) { - String desc = descriptorString(); - return desc.substring(Math.max(1, desc.lastIndexOf('/') + 1), desc.length() - 1); - } - else if (isArray()) { - int depth = arrayDepth(descriptorString()); - ClassDesc c = this; - for (int i=0; i + + + + Restricted methods + + +

    Restricted methods

    +

    Various methods in the Java SE API allow Java code to interoperate with resources outside the Java runtime + in such a way that the runtime cannot prove correct or safe use of the resources. These methods can, + when used incorrectly, violate the integrity of the Java Virtual Machine, but are conditionally made available + to users, as they provide essential functionality. They are known as restricted methods.

    +

    Given the potential danger of restricted methods, the Java runtime issues a warning on + the standard error stream every time a restricted method is invoked. Such warnings can + be disabled by granting access to restricted methods to selected modules. This can be + done either via implementation-specific command line options or programmatically, e.g. + by calling ModuleLayer.Controller.enableNativeAccess(java.lang.Module).

    +

    When a restricted method is invoked by JNI code, + or from an upcall stub + and there is no caller class on the stack, it is as if the restricted method call occurred in an unnamed module.

    +

    In the reference implementation, access to restricted methods can be granted to + specific modules using the command line option --enable-native-access=M1,M2, ... Mn, + where M1, M2, ... Mn are module names (for the unnamed module, + the special value ALL-UNNAMED can be used). Access to restricted methods + from modules not listed by that option is deemed illegal. Clients can + control how access to restricted methods is handled, using the command line + option --illegal-native-access. If this option is not specified, + illegal access to restricted methods will result in runtime warnings.

    + + diff --git a/src/java.base/share/classes/java/lang/foreign/package-info.java b/src/java.base/share/classes/java/lang/foreign/package-info.java index 1f31301638e05..18419ba1877d8 100644 --- a/src/java.base/share/classes/java/lang/foreign/package-info.java +++ b/src/java.base/share/classes/java/lang/foreign/package-info.java @@ -128,49 +128,9 @@ * {@linkplain java.lang.foreign.SegmentAllocator#allocateFrom(java.lang.String) converting} * Java strings into zero-terminated, UTF-8 strings, as demonstrated in the above example. * - *

    Restricted methods

    - * - * Some methods in this package are considered restricted. Restricted methods - * are typically used to bind native foreign data and/or functions to first-class - * Java API elements which can then be used directly by clients. For instance the - * restricted method {@link java.lang.foreign.MemorySegment#reinterpret(long)} can be - * used to create a fresh segment with the same address and temporal bounds, but with - * the provided size. This can be useful to resize memory segments obtained when - * interacting with native functions. - *

    - * Binding foreign data and/or functions is generally unsafe and, if done incorrectly, - * can result in VM crashes, or memory corruption when the bound Java API element - * is accessed. For instance, incorrectly resizing a native memory segment using - * {@link java.lang.foreign.MemorySegment#reinterpret(long)} can lead to a JVM crash, or, - * worse, lead to silent memory corruption when attempting to access the resized segment. - * For these reasons, it is crucial for code that calls a restricted method to never pass - * arguments that might cause incorrect binding of foreign data and/or functions to - * a Java API. - *

    - * Given the potential danger of restricted methods, the Java runtime issues a warning on - * the standard error stream every time a restricted method is invoked. Such warnings can - * be disabled by granting access to restricted methods to selected modules. This can be - * done either via implementation-specific command line options or programmatically, e.g. - * by calling {@link java.lang.ModuleLayer.Controller#enableNativeAccess(java.lang.Module)}. - *

    - * For every class in this package, unless specified otherwise, any method arguments of - * reference type must not be {@code null}, and any null argument will elicit a - * {@code NullPointerException}. This fact is not individually documented for methods of - * this API. - * * @apiNote Usual memory model guarantees (see {@jls 17.4}) do not apply when accessing * native memory segments as these segments are backed by off-heap regions of memory. * - * @implNote - * In the reference implementation, access to restricted methods can be granted to - * specific modules using the command line option {@code --enable-native-access=M1,M2, ... Mn}, - * where {@code M1}, {@code M2}, {@code ... Mn} are module names (for the unnamed module, - * the special value {@code ALL-UNNAMED} can be used). Access to restricted methods - * from modules not listed by that option is deemed illegal. Clients can - * control how access to restricted methods is handled, using the command line - * option {@code --illegal-native-access}. If this option is not specified, - * illegal access to restricted methods will result in runtime warnings. - * * @spec jni/index.html Java Native Interface Specification * * @since 22 diff --git a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java index 94a271780c32e..1ed7c422c9857 100644 --- a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java +++ b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java @@ -42,8 +42,9 @@ import java.util.function.Consumer; import java.util.function.Function; +import jdk.internal.constant.ClassOrInterfaceDescImpl; +import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.MethodTypeDescImpl; -import jdk.internal.constant.ReferenceClassDescImpl; import jdk.internal.loader.BootLoader; import jdk.internal.vm.annotation.Stable; import sun.invoke.util.BytecodeName; @@ -65,8 +66,8 @@ /*non-public*/ abstract class ClassSpecializer.SpeciesData> { - private static final ClassDesc CD_LambdaForm = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;"); - private static final ClassDesc CD_BoundMethodHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/BoundMethodHandle;"); + private static final ClassDesc CD_LambdaForm = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;"); + private static final ClassDesc CD_BoundMethodHandle = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/BoundMethodHandle;"); private final Class topClass; private final Class keyType; @@ -974,7 +975,7 @@ static ClassDesc classDesc(Class cls) { : cls == MethodType.class ? CD_MethodType : cls == LambdaForm.class ? CD_LambdaForm : cls == BoundMethodHandle.class ? CD_BoundMethodHandle - : ReferenceClassDescImpl.ofValidated(cls.descriptorString()); + : ConstantUtils.referenceClassDesc(cls.descriptorString()); } static MethodTypeDesc methodDesc(MethodType mt) { diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 92c02c433c524..937840049943c 100644 --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -25,6 +25,7 @@ package java.lang.invoke; +import jdk.internal.constant.ClassOrInterfaceDescImpl; import jdk.internal.misc.CDS; import jdk.internal.util.ClassFileDumper; import sun.invoke.util.VerifyAccess; @@ -34,12 +35,10 @@ import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; -import java.lang.classfile.FieldBuilder; import java.lang.classfile.MethodBuilder; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; import java.lang.constant.ClassDesc; -import java.lang.constant.DynamicConstantDesc; import java.lang.constant.MethodTypeDesc; import java.lang.reflect.Modifier; import java.util.LinkedHashSet; @@ -51,16 +50,13 @@ import java.lang.classfile.attribute.ExceptionsAttribute; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.constantpool.MethodRefEntry; + import static java.lang.constant.ConstantDescs.*; import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS; import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK; -import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; -import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; -import static java.lang.invoke.MethodType.methodType; import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.MethodTypeDescImpl; -import jdk.internal.constant.ReferenceClassDescImpl; +import jdk.internal.vm.annotation.Stable; import sun.invoke.util.Wrapper; /** @@ -71,7 +67,7 @@ */ /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$"; - private static final String[] EMPTY_STRING_ARRAY = new String[0]; + private static final @Stable String[] ARG_NAME_CACHE = {"arg$1", "arg$2", "arg$3", "arg$4", "arg$5", "arg$6", "arg$7", "arg$8"}; private static final ClassDesc[] EMPTY_CLASSDESC_ARRAY = ConstantUtils.EMPTY_CLASSDESC; // For dumping generated classes to disk, for debugging purposes @@ -96,7 +92,6 @@ private final MethodTypeDesc implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;" private final MethodType constructorType; // Generated class constructor type "(CC)void" private final MethodTypeDesc constructorTypeDesc;// Type descriptor for the generated class constructor type "(CC)void" - private final String[] argNames; // Generated names for the constructor arguments private final ClassDesc[] argDescs; // Type descriptors for the constructor arguments private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" private final ConstantPoolBuilder pool = ConstantPoolBuilder.of(); @@ -161,7 +156,7 @@ public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, implMethodDesc = methodDesc(implInfo.getMethodType()); constructorType = factoryType.changeReturnType(Void.TYPE); lambdaClassName = lambdaClassName(targetClass); - lambdaClassEntry = pool.classEntry(ReferenceClassDescImpl.ofValidated(ConstantUtils.concat("L", lambdaClassName, ";"))); + lambdaClassEntry = pool.classEntry(ConstantUtils.internalNameToDesc(lambdaClassName)); // If the target class invokes a protected method inherited from a // superclass in a different package, or does 'invokespecial', the // lambda class has no access to the resolved method, or does @@ -174,18 +169,24 @@ public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, implKind == MethodHandleInfo.REF_invokeSpecial || implKind == MethodHandleInfo.REF_invokeStatic && implClass.isHidden(); int parameterCount = factoryType.parameterCount(); + ClassDesc[] argDescs; + MethodTypeDesc constructorTypeDesc; if (parameterCount > 0) { - argNames = new String[parameterCount]; argDescs = new ClassDesc[parameterCount]; for (int i = 0; i < parameterCount; i++) { - argNames[i] = "arg$" + (i + 1); argDescs[i] = classDesc(factoryType.parameterType(i)); } + constructorTypeDesc = MethodTypeDescImpl.ofValidated(CD_void, argDescs); } else { - argNames = EMPTY_STRING_ARRAY; argDescs = EMPTY_CLASSDESC_ARRAY; + constructorTypeDesc = MTD_void; } - constructorTypeDesc = MethodTypeDescImpl.ofValidated(CD_void, argDescs); + this.argDescs = argDescs; + this.constructorTypeDesc = constructorTypeDesc; + } + + private static String argName(int i) { + return i < ARG_NAME_CACHE.length ? ARG_NAME_CACHE[i] : "arg$" + (i + 1); } private static String lambdaClassName(Class targetClass) { @@ -313,7 +314,7 @@ public void accept(ClassBuilder clb) { .withInterfaceSymbols(interfaces); // Generate final fields to be filled in by constructor for (int i = 0; i < argDescs.length; i++) { - clb.withField(argNames[i], argDescs[i], ACC_PRIVATE | ACC_FINAL); + clb.withField(argName(i), argDescs[i], ACC_PRIVATE | ACC_FINAL); } generateConstructor(clb); @@ -394,10 +395,9 @@ public void accept(CodeBuilder cob) { .invokespecial(CD_Object, INIT_NAME, MTD_void); int parameterCount = factoryType.parameterCount(); for (int i = 0; i < parameterCount; i++) { - cob.aload(0); - Class argType = factoryType.parameterType(i); - cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i)); - cob.putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); + cob.aload(0) + .loadLocal(TypeKind.from(factoryType.parameterType(i)), cob.parameterSlot(i)) + .putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argName(i), argDescs[i]))); } cob.return_(); } @@ -406,9 +406,9 @@ public void accept(CodeBuilder cob) { private static class SerializationSupport { // Serialization support - private static final ClassDesc CD_SerializedLambda = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/SerializedLambda;"); - private static final ClassDesc CD_ObjectOutputStream = ReferenceClassDescImpl.ofValidated("Ljava/io/ObjectOutputStream;"); - private static final ClassDesc CD_ObjectInputStream = ReferenceClassDescImpl.ofValidated("Ljava/io/ObjectInputStream;"); + private static final ClassDesc CD_SerializedLambda = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/SerializedLambda;"); + private static final ClassDesc CD_ObjectOutputStream = ClassOrInterfaceDescImpl.ofValidated("Ljava/io/ObjectOutputStream;"); + private static final ClassDesc CD_ObjectInputStream = ClassOrInterfaceDescImpl.ofValidated("Ljava/io/ObjectInputStream;"); private static final MethodTypeDesc MTD_Object = MethodTypeDescImpl.ofValidated(CD_Object); private static final MethodTypeDesc MTD_void_ObjectOutputStream = MethodTypeDescImpl.ofValidated(CD_void, CD_ObjectOutputStream); private static final MethodTypeDesc MTD_void_ObjectInputStream = MethodTypeDescImpl.ofValidated(CD_void, CD_ObjectInputStream); @@ -417,10 +417,10 @@ private static class SerializationSupport { private static final String NAME_METHOD_READ_OBJECT = "readObject"; private static final String NAME_METHOD_WRITE_OBJECT = "writeObject"; - static final ClassDesc CD_NotSerializableException = ReferenceClassDescImpl.ofValidated("Ljava/io/NotSerializableException;"); + static final ClassDesc CD_NotSerializableException = ClassOrInterfaceDescImpl.ofValidated("Ljava/io/NotSerializableException;"); static final MethodTypeDesc MTD_CTOR_NOT_SERIALIZABLE_EXCEPTION = MethodTypeDescImpl.ofValidated(CD_void, CD_String); static final MethodTypeDesc MTD_CTOR_SERIALIZED_LAMBDA = MethodTypeDescImpl.ofValidated(CD_void, - CD_Class, CD_String, CD_String, CD_String, CD_int, CD_String, CD_String, CD_String, CD_String, ReferenceClassDescImpl.ofValidated("[Ljava/lang/Object;")); + CD_Class, CD_String, CD_String, CD_String, CD_int, CD_String, CD_String, CD_String, CD_String, ConstantUtils.CD_Object_array); } @@ -449,7 +449,7 @@ public void accept(CodeBuilder cob) { cob.dup() .loadConstant(i) .aload(0) - .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); + .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argName(i), argDescs[i]))); TypeConvertingMethodAdapter.boxIfTypePrimitive(cob, TypeKind.from(argDescs[i])); cob.aastore(); } @@ -506,9 +506,9 @@ public void accept(CodeBuilder cob) { cob.ldc(cp.constantDynamicEntry(cp.bsmEntry(cp.methodHandleEntry(BSM_CLASS_DATA), List.of()), cp.nameAndTypeEntry(DEFAULT_NAME, CD_MethodHandle))); } - for (int i = 0; i < argNames.length; i++) { + for (int i = 0; i < argDescs.length; i++) { cob.aload(0) - .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); + .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argName(i), argDescs[i]))); } convertArgumentTypes(cob, methodType); @@ -556,12 +556,12 @@ private Opcode invocationOpcode() throws InternalError { } static ClassDesc implClassDesc(Class cls) { - return cls.isHidden() ? null : ReferenceClassDescImpl.ofValidated(cls.descriptorString()); + return cls.isHidden() ? null : ConstantUtils.referenceClassDesc(cls.descriptorString()); } static ClassDesc classDesc(Class cls) { return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor() - : ReferenceClassDescImpl.ofValidated(cls.descriptorString()); + : ConstantUtils.referenceClassDesc(cls.descriptorString()); } static MethodTypeDesc methodDesc(MethodType mt) { diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 4a905a3030b9a..ec131d67f2b75 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -25,6 +25,8 @@ package java.lang.invoke; +import jdk.internal.constant.ClassOrInterfaceDescImpl; +import jdk.internal.constant.ConstantUtils; import sun.invoke.util.VerifyAccess; import sun.invoke.util.VerifyType; import sun.invoke.util.Wrapper; @@ -50,7 +52,6 @@ import java.util.function.Consumer; import java.util.stream.Stream; import jdk.internal.constant.MethodTypeDescImpl; -import jdk.internal.constant.ReferenceClassDescImpl; import static java.lang.classfile.ClassFile.*; import static java.lang.constant.ConstantDescs.*; @@ -59,7 +60,6 @@ import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; -import static jdk.internal.constant.ConstantUtils.concat; import static jdk.internal.constant.ConstantUtils.validateInternalClassName; /** @@ -69,16 +69,16 @@ */ class InvokerBytecodeGenerator { /** Define class names for convenience. */ - private static final ClassDesc CD_CasesHolder = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$CasesHolder;"); - private static final ClassDesc CD_DirectMethodHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/DirectMethodHandle;"); - private static final ClassDesc CD_MemberName = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MemberName;"); - private static final ClassDesc CD_MethodHandleImpl = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl;"); - private static final ClassDesc CD_LambdaForm = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;"); - private static final ClassDesc CD_LambdaForm_Name = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Name;"); - private static final ClassDesc CD_LoopClauses = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$LoopClauses;"); - private static final ClassDesc CD_Object_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/Object;"); - private static final ClassDesc CD_MethodHandle_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/invoke/MethodHandle;"); - private static final ClassDesc CD_MethodHandle_array2 = ReferenceClassDescImpl.ofValidated("[[Ljava/lang/invoke/MethodHandle;"); + private static final ClassDesc CD_CasesHolder = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$CasesHolder;"); + private static final ClassDesc CD_DirectMethodHandle = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/DirectMethodHandle;"); + private static final ClassDesc CD_MemberName = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MemberName;"); + private static final ClassDesc CD_MethodHandleImpl = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl;"); + private static final ClassDesc CD_LambdaForm = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;"); + private static final ClassDesc CD_LambdaForm_Name = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Name;"); + private static final ClassDesc CD_LoopClauses = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$LoopClauses;"); + private static final ClassDesc CD_Object_array = ConstantUtils.CD_Object_array; + private static final ClassDesc CD_MethodHandle_array = CD_MethodHandle.arrayType(); + private static final ClassDesc CD_MethodHandle_array2 = CD_MethodHandle_array.arrayType(); private static final MethodTypeDesc MTD_boolean_Object = MethodTypeDescImpl.ofValidated(CD_boolean, CD_Object); private static final MethodTypeDesc MTD_Object_int = MethodTypeDescImpl.ofValidated(CD_Object, CD_int); @@ -133,7 +133,7 @@ private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize, this.name = name; this.className = CLASS_PREFIX.concat(name); validateInternalClassName(name); - this.classEntry = pool.classEntry(ReferenceClassDescImpl.ofValidated(concat("L", className, ";"))); + this.classEntry = pool.classEntry(ConstantUtils.internalNameToDesc(className)); this.lambdaForm = lambdaForm; this.invokerName = invokerName; this.invokerType = invokerType; @@ -517,11 +517,11 @@ private boolean checkActualReceiver(CodeBuilder cob) { return true; } - static final Annotation DONTINLINE = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljdk/internal/vm/annotation/DontInline;")); - static final Annotation FORCEINLINE = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljdk/internal/vm/annotation/ForceInline;")); - static final Annotation HIDDEN = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljdk/internal/vm/annotation/Hidden;")); - static final Annotation INJECTEDPROFILE = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/InjectedProfile;")); - static final Annotation LF_COMPILED = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Compiled;")); + static final Annotation DONTINLINE = Annotation.of(ClassOrInterfaceDescImpl.ofValidated("Ljdk/internal/vm/annotation/DontInline;")); + static final Annotation FORCEINLINE = Annotation.of(ClassOrInterfaceDescImpl.ofValidated("Ljdk/internal/vm/annotation/ForceInline;")); + static final Annotation HIDDEN = Annotation.of(ClassOrInterfaceDescImpl.ofValidated("Ljdk/internal/vm/annotation/Hidden;")); + static final Annotation INJECTEDPROFILE = Annotation.of(ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/InjectedProfile;")); + static final Annotation LF_COMPILED = Annotation.of(ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Compiled;")); // Suppress method in backtraces displayed to the user, mark this method as // a compiled LambdaForm, then either force or prohibit inlining. @@ -891,10 +891,9 @@ private Name emitSelectAlternative(CodeBuilder cob, Name selectAlternativeName, emitStaticInvoke(cob, invokeBasicName); // goto L_done - cob.goto_w(L_done); - - // L_fallback: - cob.labelBinding(L_fallback); + cob.goto_w(L_done) + // L_fallback: + .labelBinding(L_fallback); // invoke selectAlternativeName.arguments[2] System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length); @@ -945,26 +944,23 @@ private Name emitGuardWithCatch(CodeBuilder cob, int pos) { .dropParameterTypes(0,1) .changeReturnType(returnType); - cob.exceptionCatch(L_startBlock, L_endBlock, L_handler, CD_Throwable); - - // Normal case - cob.labelBinding(L_startBlock); + cob.exceptionCatch(L_startBlock, L_endBlock, L_handler, CD_Throwable) + // Normal case + .labelBinding(L_startBlock); // load target emitPushArgument(cob, invoker, 0); emitPushArguments(cob, args, 1); // skip 1st argument: method handle - cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType())); - cob.labelBinding(L_endBlock); - cob.goto_w(L_done); - - // Exceptional case - cob.labelBinding(L_handler); - - // Check exception's type - cob.dup(); + cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType())) + .labelBinding(L_endBlock) + .goto_w(L_done) + // Exceptional case + .labelBinding(L_handler) + // Check exception's type + .dup(); // load exception class emitPushArgument(cob, invoker, 1); - cob.swap(); - cob.invokevirtual(CD_Class, "isInstance", MTD_boolean_Object); + cob.swap() + .invokevirtual(CD_Class, "isInstance", MTD_boolean_Object); Label L_rethrow = cob.newLabel(); cob.ifeq(L_rethrow); @@ -974,13 +970,11 @@ private Name emitGuardWithCatch(CodeBuilder cob, int pos) { cob.swap(); emitPushArguments(cob, args, 1); // skip 1st argument: method handle MethodType catcherType = type.insertParameterTypes(0, Throwable.class); - cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(catcherType.basicType())); - cob.goto_w(L_done); - - cob.labelBinding(L_rethrow); - cob.athrow(); - - cob.labelBinding(L_done); + cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(catcherType.basicType())) + .goto_w(L_done) + .labelBinding(L_rethrow) + .athrow() + .labelBinding(L_done); return result; } @@ -1075,8 +1069,8 @@ private Name emitTryFinally(CodeBuilder cob, int pos) { cob.labelBinding(lFrom); emitPushArgument(cob, invoker, 0); // load target emitPushArguments(cob, args, 1); // load args (skip 0: method handle) - cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType())); - cob.labelBinding(lTo); + cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType())) + .labelBinding(lTo); // FINALLY_NORMAL: int index = extendLocalsMap(new Class[]{ returnType }); @@ -1084,17 +1078,16 @@ private Name emitTryFinally(CodeBuilder cob, int pos) { emitStoreInsn(cob, basicReturnType.basicTypeKind(), index); } emitPushArgument(cob, invoker, 1); // load cleanup - cob.loadConstant(null); + cob.aconst_null(); if (isNonVoid) { emitLoadInsn(cob, basicReturnType.basicTypeKind(), index); } emitPushArguments(cob, args, 1); // load args (skip 0: method handle) - cob.invokevirtual(CD_MethodHandle, "invokeBasic", cleanupDesc); - cob.goto_w(lDone); - - // CATCH: - cob.labelBinding(lCatch); - cob.dup(); + cob.invokevirtual(CD_MethodHandle, "invokeBasic", cleanupDesc) + .goto_w(lDone) + // CATCH: + .labelBinding(lCatch) + .dup(); // FINALLY_EXCEPTIONAL: emitPushArgument(cob, invoker, 1); // load cleanup @@ -1107,10 +1100,9 @@ private Name emitTryFinally(CodeBuilder cob, int pos) { if (isNonVoid) { emitPopInsn(cob, basicReturnType); } - cob.athrow(); - - // DONE: - cob.labelBinding(lDone); + cob.athrow() + // DONE: + .labelBinding(lDone); return result; } @@ -1147,26 +1139,24 @@ private Name emitTableSwitch(CodeBuilder cob, int pos, int numCases) { } emitPushArgument(cob, invoker, 0); // push switch input - cob.tableswitch(0, numCases - 1, defaultLabel, cases); - - cob.labelBinding(defaultLabel); + cob.tableswitch(0, numCases - 1, defaultLabel, cases) + .labelBinding(defaultLabel); emitPushArgument(cob, invoker, 1); // push default handle emitPushArguments(cob, args, 1); // again, skip collector - cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor); - cob.goto_(endLabel); + cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor) + .goto_(endLabel); for (int i = 0; i < numCases; i++) { cob.labelBinding(cases.get(i).target()); // Load the particular case: emitLoadInsn(cob, TypeKind.REFERENCE, casesLocal); - cob.loadConstant(i); - cob.aaload(); + cob.loadConstant(i) + .aaload(); // invoke it: emitPushArguments(cob, args, 1); // again, skip collector - cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor); - - cob.goto_(endLabel); + cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor) + .goto_(endLabel); } cob.labelBinding(endLabel); @@ -1335,16 +1325,14 @@ private Name emitLoop(CodeBuilder cob, int pos) { // invoke fini emitLoopHandleInvoke(cob, invoker, finis, c, args, true, finiType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex); - cob.goto_w(lDone); - - // this is the beginning of the next loop clause - cob.labelBinding(lNext); + cob.goto_w(lDone) + // this is the beginning of the next loop clause + .labelBinding(lNext); } - cob.goto_w(lLoop); - - // DONE: - cob.labelBinding(lDone); + cob.goto_w(lLoop) + // DONE: + .labelBinding(lDone); return result; } @@ -1370,8 +1358,8 @@ private void emitLoopHandleInvoke(CodeBuilder cob, Name holder, int handles, int int firstLoopStateSlot) { // load handle for clause emitPushClauseArray(cob, clauseDataSlot, handles); - cob.loadConstant(clause); - cob.aaload(); + cob.loadConstant(clause) + .aaload(); // load loop state (preceding the other arguments) if (pushLocalState) { for (int s = 0; s < loopLocalStateTypes.length; ++s) { @@ -1385,8 +1373,8 @@ private void emitLoopHandleInvoke(CodeBuilder cob, Name holder, int handles, int private void emitPushClauseArray(CodeBuilder cob, int clauseDataSlot, int which) { emitLoadInsn(cob, TypeKind.REFERENCE, clauseDataSlot); - cob.loadConstant(which - 1); - cob.aaload(); + cob.loadConstant(which - 1) + .aaload(); } private void emitZero(CodeBuilder cob, BasicType type) { @@ -1519,14 +1507,14 @@ public void accept(MethodBuilder mb) { @Override public void accept(CodeBuilder cob) { // create parameter array - cob.loadConstant(invokerType.parameterCount()); - cob.anewarray(CD_Object); + cob.loadConstant(invokerType.parameterCount()) + .anewarray(CD_Object); // fill parameter array for (int i = 0; i < invokerType.parameterCount(); i++) { Class ptype = invokerType.parameterType(i); - cob.dup(); - cob.loadConstant(i); + cob.dup() + .loadConstant(i); emitLoadInsn(cob, basicType(ptype).basicTypeKind(), i); // box if primitive type if (ptype.isPrimitive()) { @@ -1535,10 +1523,10 @@ public void accept(CodeBuilder cob) { cob.aastore(); } // invoke - cob.aload(0); - cob.getfield(CD_MethodHandle, "form", CD_LambdaForm); - cob.swap(); // swap form and array; avoid local variable - cob.invokevirtual(CD_LambdaForm, "interpretWithArguments", MethodTypeDescImpl.ofValidated(CD_Object, CD_Object_array)); + cob.aload(0) + .getfield(CD_MethodHandle, "form", CD_LambdaForm) + .swap() // swap form and array; avoid local variable + .invokevirtual(CD_LambdaForm, "interpretWithArguments", MethodTypeDescImpl.ofValidated(CD_Object, CD_Object_array)); // maybe unbox Class rtype = invokerType.returnType(); @@ -1592,9 +1580,9 @@ public void accept(CodeBuilder cob) { // Load arguments from array for (int i = 0; i < dstType.parameterCount(); i++) { - cob.aload(1); - cob.loadConstant(i); - cob.aaload(); + cob.aload(1) + .loadConstant(i) + .aaload(); // Maybe unbox Class dptype = dstType.parameterType(i); @@ -1645,9 +1633,9 @@ private void bogusMethod(ClassBuilder clb, Object os) { clb.withMethodBody("dummy", MTD_void, ACC_STATIC, new Consumer<>() { @Override public void accept(CodeBuilder cob) { - cob.ldc(os.toString()); - cob.pop(); - cob.return_(); + cob.ldc(os.toString()) + .pop() + .return_(); } }); } @@ -1661,7 +1649,7 @@ static ClassDesc classDesc(Class cls) { : cls == MemberName.class ? CD_MemberName : cls == MethodType.class ? CD_MethodType : cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor() - : ReferenceClassDescImpl.ofValidated(cls.descriptorString()); + : ConstantUtils.referenceClassDesc(cls.descriptorString()); } static MethodTypeDesc methodDesc(MethodType mt) { diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java index 7109f35f069ce..b3983b8bd7e58 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java @@ -301,12 +301,8 @@ enum Kind { PUT_DOUBLE_VOLATILE("putDoubleVolatile"), TRY_FINALLY("tryFinally"), TABLE_SWITCH("tableSwitch"), - COLLECT("collect"), COLLECTOR("collector"), - CONVERT("convert"), - SPREAD("spread"), LOOP("loop"), - FIELD("field"), GUARD("guard"), GUARD_WITH_CATCH("guardWithCatch"), VARHANDLE_EXACT_INVOKER("VH.exactInvoker"), diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index 104248c27e61a..d327060070741 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -27,6 +27,8 @@ import jdk.internal.loader.ClassLoaders; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import java.lang.constant.ClassDesc; @@ -856,6 +858,7 @@ public Object invokeWithArguments(java.util.List arguments) throws Throwable * @throws WrongMethodTypeException if the conversion cannot be made * @see MethodHandles#explicitCastArguments */ + @ForceInline public final MethodHandle asType(MethodType newType) { // Fast path alternative to a heavyweight {@code asType} call. // Return 'this' if the conversion will be a no-op. @@ -867,7 +870,7 @@ public final MethodHandle asType(MethodType newType) { if (at != null) { return at; } - return setAsTypeCache(asTypeUncached(newType)); + return setAsTypeCache(newType); } private MethodHandle asTypeCached(MethodType newType) { @@ -885,7 +888,16 @@ private MethodHandle asTypeCached(MethodType newType) { return null; } - private MethodHandle setAsTypeCache(MethodHandle at) { + /* + * We disable inlining here to prevent complex code in the slow path + * of MethodHandle::asType from being inlined into that method. + * Excessive inlining into MethodHandle::asType can cause that method + * to become too big, which will then cause performance issues during + * var handle and method handle calls. + */ + @DontInline + private MethodHandle setAsTypeCache(MethodType newType) { + MethodHandle at = asTypeUncached(newType); // Don't introduce a strong reference in the cache if newType depends on any class loader other than // current method handle already does to avoid class loader leaks. if (isSafeToCache(at.type)) { diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index 992ef38768484..fd3e20a524e1b 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -27,8 +27,9 @@ import jdk.internal.access.JavaLangInvokeAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.constant.ClassOrInterfaceDescImpl; +import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.MethodTypeDescImpl; -import jdk.internal.constant.ReferenceClassDescImpl; import jdk.internal.foreign.abi.NativeEntryPoint; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; @@ -54,7 +55,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.stream.Stream; @@ -67,7 +67,6 @@ import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; -import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; /** * Trusted implementation code for MethodHandle. @@ -1038,7 +1037,7 @@ static MethodHandle bindCaller(MethodHandle mh, Class hostClass) { // That way we can lazily load the code and set up the constants. private static class BindCaller { - private static final ClassDesc CD_Object_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/Object;"); + private static final ClassDesc CD_Object_array = ConstantUtils.CD_Object_array; private static final MethodType INVOKER_MT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class); private static final MethodType REFLECT_INVOKER_MT = MethodType.methodType(Object.class, MethodHandle.class, Object.class, Object[].class); @@ -1267,7 +1266,7 @@ private static byte[] generateInvokerTemplate() { // } // } // } - return ClassFile.of().build(ReferenceClassDescImpl.ofValidated("LInjectedInvoker;"), clb -> clb + return ClassFile.of().build(ClassOrInterfaceDescImpl.ofValidated("LInjectedInvoker;"), clb -> clb .withFlags(ACC_PRIVATE | ACC_SUPER) .withMethodBody( "invoke_V", diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java index c6a5c2763f4a6..9709c881863ef 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java @@ -54,6 +54,7 @@ import java.lang.classfile.TypeKind; import jdk.internal.constant.ConstantUtils; +import jdk.internal.loader.ClassLoaders; import jdk.internal.module.Modules; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; @@ -371,48 +372,46 @@ private static Class getProxyClass(Class intfc) { */ private static byte[] createTemplate(ClassLoader loader, ClassDesc proxyDesc, ClassDesc ifaceDesc, String methodName, List methods) { - return ClassFile.of(ClassHierarchyResolverOption.of(ClassHierarchyResolver.ofClassLoading(loader))) + return ClassFile.of(ClassHierarchyResolverOption.of(ClassHierarchyResolver.ofClassLoading(loader == null ? + ClassLoaders.platformClassLoader() : loader))) .build(proxyDesc, clb -> { - clb.withSuperclass(CD_Object); - clb.withFlags(ACC_FINAL | ACC_SYNTHETIC); - clb.withInterfaceSymbols(ifaceDesc); - - // static and instance fields - clb.withField(TYPE_NAME, CD_Class, ACC_PRIVATE | ACC_STATIC | ACC_FINAL); - clb.withField(TARGET_NAME, CD_MethodHandle, ACC_PRIVATE | ACC_FINAL); + clb.withSuperclass(CD_Object) + .withFlags(ACC_FINAL | ACC_SYNTHETIC) + .withInterfaceSymbols(ifaceDesc) + // static and instance fields + .withField(TYPE_NAME, CD_Class, ACC_PRIVATE | ACC_STATIC | ACC_FINAL) + .withField(TARGET_NAME, CD_MethodHandle, ACC_PRIVATE | ACC_FINAL); for (var mi : methods) { clb.withField(mi.fieldName, CD_MethodHandle, ACC_PRIVATE | ACC_FINAL); } // clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, cob -> { - cob.loadConstant(ifaceDesc); - cob.putstatic(proxyDesc, TYPE_NAME, CD_Class); - cob.return_(); + cob.loadConstant(ifaceDesc) + .putstatic(proxyDesc, TYPE_NAME, CD_Class) + .return_(); }); // (Lookup, MethodHandle target, MethodHandle callerBoundTarget) clb.withMethodBody(INIT_NAME, MTD_void_Lookup_MethodHandle_MethodHandle, 0, cob -> { - cob.aload(0); - cob.invokespecial(CD_Object, INIT_NAME, MTD_void); - - // call ensureOriginalLookup to verify the given Lookup has access - cob.aload(1); - cob.invokestatic(proxyDesc, "ensureOriginalLookup", MTD_void_Lookup); - - // this.target = target; - cob.aload(0); - cob.aload(2); - cob.putfield(proxyDesc, TARGET_NAME, CD_MethodHandle); + cob.aload(0) + .invokespecial(CD_Object, INIT_NAME, MTD_void) + // call ensureOriginalLookup to verify the given Lookup has access + .aload(1) + .invokestatic(proxyDesc, ENSURE_ORIGINAL_LOOKUP, MTD_void_Lookup) + // this.target = target; + .aload(0) + .aload(2) + .putfield(proxyDesc, TARGET_NAME, CD_MethodHandle); // method handles adjusted to the method type of each method for (var mi : methods) { // this.m = callerBoundTarget.asType(xxType); - cob.aload(0); - cob.aload(3); - cob.loadConstant(mi.desc); - cob.invokevirtual(CD_MethodHandle, "asType", MTD_MethodHandle_MethodType); - cob.putfield(proxyDesc, mi.fieldName, CD_MethodHandle); + cob.aload(0) + .aload(3) + .loadConstant(mi.desc) + .invokevirtual(CD_MethodHandle, "asType", MTD_MethodHandle_MethodType) + .putfield(proxyDesc, mi.fieldName, CD_MethodHandle); } // complete @@ -425,26 +424,26 @@ private static byte[] createTemplate(ClassLoader loader, ClassDesc proxyDesc, Cl clb.withMethodBody(ENSURE_ORIGINAL_LOOKUP, MTD_void_Lookup, ACC_PRIVATE | ACC_STATIC, cob -> { var failLabel = cob.newLabel(); // check lookupClass - cob.aload(0); - cob.invokevirtual(CD_MethodHandles_Lookup, "lookupClass", MTD_Class); - cob.loadConstant(proxyDesc); - cob.if_acmpne(failLabel); - // check original access - cob.aload(0); - cob.invokevirtual(CD_MethodHandles_Lookup, "lookupModes", MTD_int); - cob.loadConstant(Lookup.ORIGINAL); - cob.iand(); - cob.ifeq(failLabel); - // success - cob.return_(); - // throw exception - cob.labelBinding(failLabel); - cob.new_(CD_IllegalAccessException); - cob.dup(); - cob.aload(0); // lookup - cob.invokevirtual(CD_Object, "toString", MTD_String); - cob.invokespecial(CD_IllegalAccessException, INIT_NAME, MTD_void_String); - cob.athrow(); + cob.aload(0) + .invokevirtual(CD_MethodHandles_Lookup, "lookupClass", MTD_Class) + .loadConstant(proxyDesc) + .if_acmpne(failLabel) + // check original access + .aload(0) + .invokevirtual(CD_MethodHandles_Lookup, "lookupModes", MTD_int) + .loadConstant(Lookup.ORIGINAL) + .iand() + .ifeq(failLabel) + // success + .return_() + // throw exception + .labelBinding(failLabel) + .new_(CD_IllegalAccessException) + .dup() + .aload(0) // lookup + .invokevirtual(CD_Object, "toString", MTD_String) + .invokespecial(CD_IllegalAccessException, INIT_NAME, MTD_void_String) + .athrow(); }); // implementation methods @@ -453,14 +452,14 @@ private static byte[] createTemplate(ClassLoader loader, ClassDesc proxyDesc, Cl clb.withMethodBody(methodName, mi.desc, ACC_PUBLIC, cob -> cob .trying(bcb -> { // return this.handleField.invokeExact(arguments...); - bcb.aload(0); - bcb.getfield(proxyDesc, mi.fieldName, CD_MethodHandle); + bcb.aload(0) + .getfield(proxyDesc, mi.fieldName, CD_MethodHandle); for (int j = 0; j < mi.desc.parameterCount(); j++) { bcb.loadLocal(TypeKind.from(mi.desc.parameterType(j)), bcb.parameterSlot(j)); } - bcb.invokevirtual(CD_MethodHandle, "invokeExact", mi.desc); - bcb.return_(TypeKind.from(mi.desc.returnType())); + bcb.invokevirtual(CD_MethodHandle, "invokeExact", mi.desc) + .return_(TypeKind.from(mi.desc.returnType())); }, ctb -> ctb // catch (Error | RuntimeException | Declared ex) { throw ex; } .catchingMulti(mi.thrown, CodeBuilder::athrow) diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 9e292373f9caf..b45ff858cd371 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -463,8 +463,8 @@ public static T classDataAt(Lookup caller, String name, Class type, int i * If there is a security manager, its {@code checkPermission} method * is called with a {@code ReflectPermission("suppressAccessChecks")} permission. * @param the desired type of the result, either {@link Member} or a subtype - * @param target a direct method handle to crack into symbolic reference components * @param expected a class object representing the desired result type {@code T} + * @param target a direct method handle to crack into symbolic reference components * @return a reference to the method, constructor, or field object * @throws SecurityException if the caller is not privileged to call {@code setAccessible} * @throws NullPointerException if either argument is {@code null} diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 97848e1fcb3e5..cca16a18580ac 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -28,9 +28,9 @@ import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.constant.ClassOrInterfaceDescImpl; import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.MethodTypeDescImpl; -import jdk.internal.constant.ReferenceClassDescImpl; import jdk.internal.misc.VM; import jdk.internal.util.ClassFileDumper; import jdk.internal.util.ReferenceKey; @@ -1088,10 +1088,10 @@ private static final class InlineHiddenClassStrategy { static final MethodHandles.Lookup STR_LOOKUP = new MethodHandles.Lookup(String.class); static final ClassDesc CD_CONCAT = ConstantUtils.binaryNameToDesc(CLASS_NAME); - static final ClassDesc CD_StringConcatHelper = ReferenceClassDescImpl.ofValidated("Ljava/lang/StringConcatHelper;"); - static final ClassDesc CD_StringConcatBase = ReferenceClassDescImpl.ofValidated("Ljava/lang/StringConcatHelper$StringConcatBase;"); - static final ClassDesc CD_Array_byte = ReferenceClassDescImpl.ofValidated("[B"); - static final ClassDesc CD_Array_String = ReferenceClassDescImpl.ofValidated("[Ljava/lang/String;"); + static final ClassDesc CD_StringConcatHelper = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/StringConcatHelper;"); + static final ClassDesc CD_StringConcatBase = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/StringConcatHelper$StringConcatBase;"); + static final ClassDesc CD_Array_byte = CD_byte.arrayType(); + static final ClassDesc CD_Array_String = CD_String.arrayType(); static final MethodTypeDesc MTD_byte_char = MethodTypeDescImpl.ofValidated(CD_byte, CD_char); static final MethodTypeDesc MTD_byte = MethodTypeDescImpl.ofValidated(CD_byte); diff --git a/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java b/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java index 83fefe07d5150..f372e0532607a 100644 --- a/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java +++ b/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java @@ -30,8 +30,9 @@ import java.lang.classfile.TypeKind; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.MethodRefEntry; + +import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.MethodTypeDescImpl; -import jdk.internal.constant.ReferenceClassDescImpl; import sun.invoke.util.Wrapper; import static java.lang.constant.ConstantDescs.*; @@ -202,6 +203,6 @@ static ClassDesc classDesc(Class cls) { return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor() : cls == Object.class ? CD_Object : cls == String.class ? CD_String - : ReferenceClassDescImpl.ofValidated(cls.descriptorString()); + : ConstantUtils.referenceClassDesc(cls.descriptorString()); } } diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandle.java b/src/java.base/share/classes/java/lang/invoke/VarHandle.java index f5fae207b93a9..dda5f99971551 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.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 @@ -2371,9 +2371,9 @@ private VarHandleDesc(Kind kind, String name, ClassDesc declaringClass, ClassDes * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle} * for an instance field. * - * @param name the unqualified name of the field * @param declaringClass a {@link ClassDesc} describing the declaring class, * for field var handles + * @param name the unqualified name of the field * @param fieldType a {@link ClassDesc} describing the type of the field * @return the {@linkplain VarHandleDesc} * @throws NullPointerException if any of the arguments are null @@ -2390,9 +2390,9 @@ public static VarHandleDesc ofField(ClassDesc declaringClass, String name, Class * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle} * for a static field. * - * @param name the unqualified name of the field * @param declaringClass a {@link ClassDesc} describing the declaring class, * for field var handles + * @param name the unqualified name of the field * @param fieldType a {@link ClassDesc} describing the type of the field * @return the {@linkplain VarHandleDesc} * @throws NullPointerException if any of the arguments are null diff --git a/src/java.base/share/classes/java/lang/package-info.java b/src/java.base/share/classes/java/lang/package-info.java index 0484ecb29527d..9ca4482c8191f 100644 --- a/src/java.base/share/classes/java/lang/package-info.java +++ b/src/java.base/share/classes/java/lang/package-info.java @@ -29,8 +29,8 @@ * Object}, which is the root of the class hierarchy, and {@link * Class}, instances of which represent classes at run time. * - *

    Frequently it is necessary to represent a value of primitive - * type as if it were an object.The {@index + *

    Frequently it is necessary to represent a + * value of primitive type as if it were an object.The {@index * "wrapper classes"} {@link Boolean}, {@link Byte}, {@link * Character}, {@link Short}, {@link Integer}, {@link Long}, {@link * Float}, and {@link Double} serve this purpose. An object of type diff --git a/src/java.base/share/classes/java/lang/ref/PhantomReference.java b/src/java.base/share/classes/java/lang/ref/PhantomReference.java index e474748349776..47a989cde4689 100644 --- a/src/java.base/share/classes/java/lang/ref/PhantomReference.java +++ b/src/java.base/share/classes/java/lang/ref/PhantomReference.java @@ -77,6 +77,19 @@ boolean refersToImpl(T obj) { @IntrinsicCandidate private native boolean refersTo0(Object o); + /* Override the implementation of Reference.clear. + * Phantom references are weaker than finalization, so the referent + * access needs to be handled differently for garbage collectors that + * do reference processing concurrently. + */ + @Override + void clearImpl() { + clear0(); + } + + @IntrinsicCandidate + private native void clear0(); + /** * Creates a new phantom reference that refers to the given object and * is registered with the given queue. diff --git a/src/java.base/share/classes/java/lang/ref/Reference.java b/src/java.base/share/classes/java/lang/ref/Reference.java index 747aa64902f8e..88cd2a3190b71 100644 --- a/src/java.base/share/classes/java/lang/ref/Reference.java +++ b/src/java.base/share/classes/java/lang/ref/Reference.java @@ -403,13 +403,23 @@ boolean refersToImpl(T obj) { * necessary. */ public void clear() { - clear0(); + clearImpl(); } - /* Implementation of clear(), also used by enqueue(). A simple - * assignment of the referent field won't do for some garbage - * collectors. + /* Implementation of clear(). A simple assignment of the referent field + * won't do for some garbage collectors. There is the override for phantom + * references, which requires different semantics. This method is also + * used by enqueue(). + * + *

    This method exists only to avoid making clear0() virtual. Making + * clear0() virtual has the undesirable effect of C2 often preferring + * to call the native implementation over the intrinsic. */ + void clearImpl() { + clear0(); + } + + @IntrinsicCandidate private native void clear0(); /* -- Operations on inactive FinalReferences -- */ @@ -511,7 +521,7 @@ public boolean isEnqueued() { * it was not registered with a queue when it was created */ public boolean enqueue() { - clear0(); // Intentionally clear0() rather than clear() + clearImpl(); // Intentionally clearImpl() to dispatch to overridden method, if needed return this.queue.enqueue(this); } diff --git a/src/java.base/share/classes/java/lang/reflect/AnnotatedElement.java b/src/java.base/share/classes/java/lang/reflect/AnnotatedElement.java index cc1bcd7dfddfd..5ddefa10928a0 100644 --- a/src/java.base/share/classes/java/lang/reflect/AnnotatedElement.java +++ b/src/java.base/share/classes/java/lang/reflect/AnnotatedElement.java @@ -257,7 +257,7 @@ * {@link java.lang.annotation.AnnotationFormatError} is thrown. * *

    Finally, attempting to read a member whose definition has evolved - * incompatibly will result in a {@link + * incompatibly will result in an {@link * java.lang.annotation.AnnotationTypeMismatchException} or an * {@link java.lang.annotation.IncompleteAnnotationException}. * @@ -286,7 +286,6 @@ public interface AnnotatedElement { * @return true if an annotation for the specified annotation * type is present on this element, else false * @throws NullPointerException if the given annotation class is null - * @since 1.5 */ default boolean isAnnotationPresent(Class annotationClass) { return getAnnotation(annotationClass) != null; @@ -302,7 +301,6 @@ default boolean isAnnotationPresent(Class annotationClass) * @return this element's annotation for the specified annotation type if * present on this element, else null * @throws NullPointerException if the given annotation class is null - * @since 1.5 */ T getAnnotation(Class annotationClass); @@ -316,7 +314,6 @@ default boolean isAnnotationPresent(Class annotationClass) * have no effect on the arrays returned to other callers. * * @return annotations present on this element - * @since 1.5 */ Annotation[] getAnnotations(); @@ -478,7 +475,6 @@ default T[] getDeclaredAnnotationsByType(Class annotat * have no effect on the arrays returned to other callers. * * @return annotations directly present on this element - * @since 1.5 */ Annotation[] getDeclaredAnnotations(); } diff --git a/src/java.base/share/classes/java/lang/reflect/ParameterizedType.java b/src/java.base/share/classes/java/lang/reflect/ParameterizedType.java index 99016623a3e48..c78af9ef2ec5e 100644 --- a/src/java.base/share/classes/java/lang/reflect/ParameterizedType.java +++ b/src/java.base/share/classes/java/lang/reflect/ParameterizedType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, 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 @@ -66,11 +66,15 @@ public interface ParameterizedType extends Type { Type[] getActualTypeArguments(); /** - * Returns the {@code Type} object representing the class or interface - * that declared this type. + * {@return the {@code Type} object representing the class or interface + * that declared this type} + * + * @apiNote + * All {@code ParameterizedType} objects from core reflection return a + * {@link Class}. The static {@code Type} return type allows other + * implementations to represent classes and interfaces not in the current + * runtime. * - * @return the {@code Type} object representing the class or interface - * that declared this type * @since 1.5 */ Type getRawType(); diff --git a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java index abdcaf5ae1fa2..efbb3919ef542 100644 --- a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java +++ b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java @@ -39,9 +39,10 @@ import java.util.ListIterator; import java.util.Map; import java.util.Objects; + +import jdk.internal.constant.ClassOrInterfaceDescImpl; import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.MethodTypeDescImpl; -import jdk.internal.constant.ReferenceClassDescImpl; import sun.security.action.GetBooleanAction; import static java.lang.classfile.ClassFile.*; @@ -64,18 +65,18 @@ final class ProxyGenerator { ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS); private static final ClassDesc - CD_ClassLoader = ReferenceClassDescImpl.ofValidated("Ljava/lang/ClassLoader;"), - CD_Class_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/Class;"), - CD_ClassNotFoundException = ReferenceClassDescImpl.ofValidated("Ljava/lang/ClassNotFoundException;"), - CD_NoClassDefFoundError = ReferenceClassDescImpl.ofValidated("Ljava/lang/NoClassDefFoundError;"), - CD_IllegalAccessException = ReferenceClassDescImpl.ofValidated("Ljava/lang/IllegalAccessException;"), - CD_InvocationHandler = ReferenceClassDescImpl.ofValidated("Ljava/lang/reflect/InvocationHandler;"), - CD_Method = ReferenceClassDescImpl.ofValidated("Ljava/lang/reflect/Method;"), - CD_NoSuchMethodError = ReferenceClassDescImpl.ofValidated("Ljava/lang/NoSuchMethodError;"), - CD_NoSuchMethodException = ReferenceClassDescImpl.ofValidated("Ljava/lang/NoSuchMethodException;"), - CD_Object_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/Object;"), - CD_Proxy = ReferenceClassDescImpl.ofValidated("Ljava/lang/reflect/Proxy;"), - CD_UndeclaredThrowableException = ReferenceClassDescImpl.ofValidated("Ljava/lang/reflect/UndeclaredThrowableException;"); + CD_ClassLoader = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/ClassLoader;"), + CD_Class_array = CD_Class.arrayType(), + CD_ClassNotFoundException = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/ClassNotFoundException;"), + CD_NoClassDefFoundError = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/NoClassDefFoundError;"), + CD_IllegalAccessException = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/IllegalAccessException;"), + CD_InvocationHandler = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/reflect/InvocationHandler;"), + CD_Method = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/reflect/Method;"), + CD_NoSuchMethodError = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/NoSuchMethodError;"), + CD_NoSuchMethodException = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/NoSuchMethodException;"), + CD_Object_array = ConstantUtils.CD_Object_array, + CD_Proxy = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/reflect/Proxy;"), + CD_UndeclaredThrowableException = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/reflect/UndeclaredThrowableException;"); private static final MethodTypeDesc MTD_boolean = MethodTypeDescImpl.ofValidated(CD_boolean), diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index f380cf1070d1d..53f1572fa74b0 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -29,7 +29,6 @@ import java.lang.classfile.CodeBuilder; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; -import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite; @@ -49,12 +48,13 @@ import java.lang.classfile.Label; import java.lang.classfile.instruction.SwitchCase; +import jdk.internal.constant.ClassOrInterfaceDescImpl; import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.MethodTypeDescImpl; -import jdk.internal.constant.ReferenceClassDescImpl; import jdk.internal.misc.PreviewFeatures; import jdk.internal.vm.annotation.Stable; +import static java.lang.constant.ConstantDescs.*; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; import java.util.Arrays; @@ -82,19 +82,19 @@ private SwitchBootstraps() {} private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); private static final boolean previewEnabled = PreviewFeatures.isEnabled(); - private static final ClassDesc CD_BiPredicate = ReferenceClassDescImpl.ofValidated("Ljava/util/function/BiPredicate;"); - private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;"); + private static final ClassDesc CD_BiPredicate = ClassOrInterfaceDescImpl.ofValidated("Ljava/util/function/BiPredicate;"); + private static final ClassDesc CD_Objects = ClassOrInterfaceDescImpl.ofValidated("Ljava/util/Objects;"); private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR = - MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, ConstantDescs.CD_int, ConstantDescs.CD_int); - private static final MethodTypeDesc MTD_TYPE_SWITCH = MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, - ConstantDescs.CD_Object, - ConstantDescs.CD_int); - private static final MethodTypeDesc MTD_TYPE_SWITCH_EXTRA = MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, - ConstantDescs.CD_Object, - ConstantDescs.CD_int, + MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_int); + private static final MethodTypeDesc MTD_TYPE_SWITCH = MethodTypeDescImpl.ofValidated(CD_int, + CD_Object, + CD_int); + private static final MethodTypeDesc MTD_TYPE_SWITCH_EXTRA = MethodTypeDescImpl.ofValidated(CD_int, + CD_Object, + CD_int, CD_BiPredicate, - ConstantDescs.CD_List); + CD_List); private static final MethodType MT_TYPE_SWITCH_EXTRA = MethodType.methodType(int.class, Object.class, int.class, @@ -484,19 +484,19 @@ private static Consumer generateTypeSwitchSkeleton(Class selecto return cb -> { // Objects.checkIndex(RESTART_IDX, labelConstants + 1) - cb.iload(RESTART_IDX); - cb.loadConstant(labelConstants.length + 1); - cb.invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR); - cb.pop(); - cb.aload(SELECTOR_OBJ); + cb.iload(RESTART_IDX) + .loadConstant(labelConstants.length + 1) + .invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR) + .pop() + .aload(SELECTOR_OBJ); Label nonNullLabel = cb.newLabel(); - cb.ifnonnull(nonNullLabel); - cb.iconst_m1(); - cb.ireturn(); - cb.labelBinding(nonNullLabel); + cb.ifnonnull(nonNullLabel) + .iconst_m1() + .ireturn() + .labelBinding(nonNullLabel); if (labelConstants.length == 0) { cb.loadConstant(0) - .ireturn(); + .ireturn(); return; } cb.iload(RESTART_IDX); @@ -535,132 +535,132 @@ private static Consumer generateTypeSwitchSkeleton(Class selecto if (!selectorType.isPrimitive() && !Wrapper.isWrapperNumericOrBooleanType(selectorType)) { // Object o = ... // o instanceof Wrapped(float) - cb.aload(SELECTOR_OBJ); - cb.instanceOf(Wrapper.forBasicType(classLabel).wrapperClassDescriptor()); - cb.ifeq(next); + cb.aload(SELECTOR_OBJ) + .instanceOf(Wrapper.forBasicType(classLabel).wrapperClassDescriptor()) + .ifeq(next); } else if (!unconditionalExactnessCheck(Wrapper.asPrimitiveType(selectorType), classLabel)) { // Integer i = ... or int i = ... // o instanceof float Label notNumber = cb.newLabel(); - cb.aload(SELECTOR_OBJ); - cb.instanceOf(ConstantDescs.CD_Number); + cb.aload(SELECTOR_OBJ) + .instanceOf(CD_Number); if (selectorType == long.class || selectorType == float.class || selectorType == double.class || selectorType == Long.class || selectorType == Float.class || selectorType == Double.class) { cb.ifeq(next); } else { cb.ifeq(notNumber); } - cb.aload(SELECTOR_OBJ); - cb.checkcast(ConstantDescs.CD_Number); + cb.aload(SELECTOR_OBJ) + .checkcast(CD_Number); if (selectorType == long.class || selectorType == Long.class) { - cb.invokevirtual(ConstantDescs.CD_Number, + cb.invokevirtual(CD_Number, "longValue", - MethodTypeDesc.of(ConstantDescs.CD_long)); + MethodTypeDesc.of(CD_long)); } else if (selectorType == float.class || selectorType == Float.class) { - cb.invokevirtual(ConstantDescs.CD_Number, + cb.invokevirtual(CD_Number, "floatValue", - MethodTypeDesc.of(ConstantDescs.CD_float)); + MethodTypeDesc.of(CD_float)); } else if (selectorType == double.class || selectorType == Double.class) { - cb.invokevirtual(ConstantDescs.CD_Number, + cb.invokevirtual(CD_Number, "doubleValue", - MethodTypeDesc.of(ConstantDescs.CD_double)); + MethodTypeDesc.of(CD_double)); } else { Label compare = cb.newLabel(); - cb.invokevirtual(ConstantDescs.CD_Number, + cb.invokevirtual(CD_Number, "intValue", - MethodTypeDesc.of(ConstantDescs.CD_int)); - cb.goto_(compare); - cb.labelBinding(notNumber); - cb.aload(SELECTOR_OBJ); - cb.instanceOf(ConstantDescs.CD_Character); - cb.ifeq(next); - cb.aload(SELECTOR_OBJ); - cb.checkcast(ConstantDescs.CD_Character); - cb.invokevirtual(ConstantDescs.CD_Character, + MethodTypeDesc.of(CD_int)) + .goto_(compare) + .labelBinding(notNumber) + .aload(SELECTOR_OBJ) + .instanceOf(CD_Character) + .ifeq(next) + .aload(SELECTOR_OBJ) + .checkcast(CD_Character) + .invokevirtual(CD_Character, "charValue", - MethodTypeDesc.of(ConstantDescs.CD_char)); - cb.labelBinding(compare); + MethodTypeDesc.of(CD_char)) + .labelBinding(compare); } TypePairs typePair = TypePairs.of(Wrapper.asPrimitiveType(selectorType), classLabel); String methodName = TypePairs.typePairToName.get(typePair); - cb.invokestatic(referenceClassDesc(ExactConversionsSupport.class), + cb.invokestatic(ConstantUtils.referenceClassDesc(ExactConversionsSupport.class), methodName, - MethodTypeDesc.of(ConstantDescs.CD_boolean, classDesc(typePair.from))); - cb.ifeq(next); + MethodTypeDesc.of(CD_boolean, classDesc(typePair.from))) + .ifeq(next); } } else { Optional classLabelConstableOpt = classLabel.describeConstable(); if (classLabelConstableOpt.isPresent()) { - cb.aload(SELECTOR_OBJ); - cb.instanceOf(classLabelConstableOpt.orElseThrow()); - cb.ifeq(next); + cb.aload(SELECTOR_OBJ) + .instanceOf(classLabelConstableOpt.orElseThrow()) + .ifeq(next); } else { - cb.aload(EXTRA_CLASS_LABELS); - cb.loadConstant(extraClassLabels.size()); - cb.invokeinterface(ConstantDescs.CD_List, + cb.aload(EXTRA_CLASS_LABELS) + .loadConstant(extraClassLabels.size()) + .invokeinterface(CD_List, "get", - MethodTypeDesc.of(ConstantDescs.CD_Object, - ConstantDescs.CD_int)); - cb.checkcast(ConstantDescs.CD_Class); - cb.aload(SELECTOR_OBJ); - cb.invokevirtual(ConstantDescs.CD_Class, + MethodTypeDesc.of(CD_Object, + CD_int)) + .checkcast(CD_Class) + .aload(SELECTOR_OBJ) + .invokevirtual(CD_Class, "isInstance", - MethodTypeDesc.of(ConstantDescs.CD_boolean, - ConstantDescs.CD_Object)); - cb.ifeq(next); + MethodTypeDesc.of(CD_boolean, + CD_Object)) + .ifeq(next); extraClassLabels.add(classLabel); } } } else if (caseLabel instanceof EnumDesc enumLabel) { int enumIdx = enumDescs.size(); enumDescs.add(enumLabel); - cb.aload(ENUM_CACHE); - cb.loadConstant(enumIdx); - cb.invokestatic(ConstantDescs.CD_Integer, + cb.aload(ENUM_CACHE) + .loadConstant(enumIdx) + .invokestatic(CD_Integer, "valueOf", - MethodTypeDesc.of(ConstantDescs.CD_Integer, - ConstantDescs.CD_int)); - cb.aload(SELECTOR_OBJ); - cb.invokeinterface(CD_BiPredicate, + MethodTypeDesc.of(CD_Integer, + CD_int)) + .aload(SELECTOR_OBJ) + .invokeinterface(CD_BiPredicate, "test", - MethodTypeDesc.of(ConstantDescs.CD_boolean, - ConstantDescs.CD_Object, - ConstantDescs.CD_Object)); - cb.ifeq(next); + MethodTypeDesc.of(CD_boolean, + CD_Object, + CD_Object)) + .ifeq(next); } else if (caseLabel instanceof String stringLabel) { - cb.ldc(stringLabel); - cb.aload(SELECTOR_OBJ); - cb.invokevirtual(ConstantDescs.CD_Object, + cb.ldc(stringLabel) + .aload(SELECTOR_OBJ) + .invokevirtual(CD_Object, "equals", - MethodTypeDesc.of(ConstantDescs.CD_boolean, - ConstantDescs.CD_Object)); - cb.ifeq(next); + MethodTypeDesc.of(CD_boolean, + CD_Object)) + .ifeq(next); } else if (caseLabel instanceof Integer integerLabel) { Label compare = cb.newLabel(); Label notNumber = cb.newLabel(); - cb.aload(SELECTOR_OBJ); - cb.instanceOf(ConstantDescs.CD_Number); - cb.ifeq(notNumber); - cb.aload(SELECTOR_OBJ); - cb.checkcast(ConstantDescs.CD_Number); - cb.invokevirtual(ConstantDescs.CD_Number, + cb.aload(SELECTOR_OBJ) + .instanceOf(CD_Number) + .ifeq(notNumber) + .aload(SELECTOR_OBJ) + .checkcast(CD_Number) + .invokevirtual(CD_Number, "intValue", - MethodTypeDesc.of(ConstantDescs.CD_int)); - cb.goto_(compare); - cb.labelBinding(notNumber); - cb.aload(SELECTOR_OBJ); - cb.instanceOf(ConstantDescs.CD_Character); - cb.ifeq(next); - cb.aload(SELECTOR_OBJ); - cb.checkcast(ConstantDescs.CD_Character); - cb.invokevirtual(ConstantDescs.CD_Character, + MethodTypeDesc.of(CD_int)) + .goto_(compare) + .labelBinding(notNumber) + .aload(SELECTOR_OBJ) + .instanceOf(CD_Character) + .ifeq(next) + .aload(SELECTOR_OBJ) + .checkcast(CD_Character) + .invokevirtual(CD_Character, "charValue", - MethodTypeDesc.of(ConstantDescs.CD_char)); - cb.labelBinding(compare); + MethodTypeDesc.of(CD_char)) + .labelBinding(compare) - cb.loadConstant(integerLabel); - cb.if_icmpne(next); + .loadConstant(integerLabel) + .if_icmpne(next); } else if ((caseLabel instanceof Long || caseLabel instanceof Float || caseLabel instanceof Double || @@ -674,23 +674,23 @@ private static Consumer generateTypeSwitchSkeleton(Class selecto cb.invokestatic(caseLabelWrapper.wrapperClassDescriptor(), "valueOf", MethodTypeDesc.of(caseLabelWrapper.wrapperClassDescriptor(), - caseLabelWrapper.basicClassDescriptor())); - cb.aload(SELECTOR_OBJ); - cb.invokevirtual(ConstantDescs.CD_Object, + caseLabelWrapper.basicClassDescriptor())) + .aload(SELECTOR_OBJ) + .invokevirtual(CD_Object, "equals", - MethodTypeDesc.of(ConstantDescs.CD_boolean, - ConstantDescs.CD_Object)); - cb.ifeq(next); + MethodTypeDesc.of(CD_boolean, + CD_Object)) + .ifeq(next); } else { throw new InternalError("Unsupported label type: " + caseLabel.getClass()); } - cb.loadConstant(idx); - cb.ireturn(); + cb.loadConstant(idx) + .ireturn(); } - cb.labelBinding(dflt); - cb.loadConstant(labelConstants.length); - cb.ireturn(); + cb.labelBinding(dflt) + .loadConstant(labelConstants.length) + .ireturn(); }; } diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java index d915568a50212..abd49aa69bccf 100644 --- a/src/java.base/share/classes/java/math/BigDecimal.java +++ b/src/java.base/share/classes/java/math/BigDecimal.java @@ -3109,13 +3109,9 @@ public BigDecimal scaleByPowerOfTen(int n) { * @since 1.5 */ public BigDecimal stripTrailingZeros() { - if (intCompact == 0 || (intVal != null && intVal.signum() == 0)) { - return BigDecimal.ZERO; - } else if (intCompact != INFLATED) { - return createAndStripZerosToMatchScale(intCompact, scale, Long.MIN_VALUE); - } else { - return createAndStripZerosToMatchScale(intVal, scale, Long.MIN_VALUE); - } + return intCompact == 0 || (intVal != null && intVal.signum() == 0) + ? BigDecimal.ZERO + : stripZerosToMatchScale(intVal, intCompact, scale, Long.MIN_VALUE); } // Comparison Operations @@ -5219,29 +5215,116 @@ private static boolean needIncrement(MutableBigInteger mdivisor, int roundingMod return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, mq.isOdd()); } + /** + * {@code FIVE_TO_2_TO[n] == 5^(2^n)} + */ + private static final BigInteger[] FIVE_TO_2_TO = new BigInteger[16 + 1]; + + static { + BigInteger pow = FIVE_TO_2_TO[0] = BigInteger.valueOf(5L); + for (int i = 1; i < FIVE_TO_2_TO.length; i++) + FIVE_TO_2_TO[i] = pow = pow.multiply(pow); + } + + /** + * @param n a non-negative integer + * @return {@code 5^(2^n)} + */ + private static BigInteger fiveToTwoToThe(int n) { + int i = Math.min(n, FIVE_TO_2_TO.length - 1); + BigInteger pow = FIVE_TO_2_TO[i]; + for (; i < n; i++) + pow = pow.multiply(pow); + + return pow; + } + + private static final double LOG_5_OF_2 = 0.43067655807339306; // double closest to log5(2) + /** * Remove insignificant trailing zeros from this * {@code BigInteger} value until the preferred scale is reached or no * more zeros can be removed. If the preferred scale is less than * Integer.MIN_VALUE, all the trailing zeros will be removed. + * Assumes {@code intVal != 0}. * * @return new {@code BigDecimal} with a scale possibly reduced * to be closed to the preferred scale. * @throws ArithmeticException if scale overflows. */ private static BigDecimal createAndStripZerosToMatchScale(BigInteger intVal, int scale, long preferredScale) { + // avoid overflow of scale - preferredScale + preferredScale = Math.clamp(preferredScale, Integer.MIN_VALUE - 1L, Integer.MAX_VALUE); + int powsOf2 = intVal.getLowestSetBit(); + // scale - preferredScale >= remainingZeros >= max{n : (intVal % 10^n) == 0 && n <= scale - preferredScale} + // a multiple of 10^n must be a multiple of 2^n + long remainingZeros = Math.min(scale - preferredScale, powsOf2); + if (remainingZeros <= 0L) + return valueOf(intVal, scale, 0); + + final int sign = intVal.signum; + if (sign < 0) + intVal = intVal.negate(); // speed up computation of shiftRight() and bitLength() + + intVal = intVal.shiftRight(powsOf2); // remove powers of 2 + // Let k = max{n : (intVal % 5^n) == 0}, m = max{n : 5^n <= intVal}, so m >= k. + // Let b = intVal.bitLength(). It can be shown that + // | b * LOG_5_OF_2 - b log5(2) | < 2^(-21) (fp viz. real arithmetic), + // which entails m <= maxPowsOf5 <= m + 1, where maxPowsOf5 is as below. + // Hence, maxPowsOf5 >= k. + long maxPowsOf5 = Math.round(intVal.bitLength() * LOG_5_OF_2); + remainingZeros = Math.min(remainingZeros, maxPowsOf5); + BigInteger[] qr; // quotient-remainder pair - while (intVal.compareMagnitude(BigInteger.TEN) >= 0 - && scale > preferredScale) { - if (intVal.testBit(0)) - break; // odd number cannot end in 0 - qr = intVal.divideAndRemainder(BigInteger.TEN); - if (qr[1].signum() != 0) - break; // non-0 remainder - intVal = qr[0]; - scale = checkScale(intVal,(long) scale - 1); // could Overflow + // Remove 5^(2^i) from the factors of intVal, until 5^remainingZeros < 5^(2^i). + // Let z = max{n >= 0 : ((intVal * 2^powsOf2) % 10^n) == 0 && n <= scale - preferredScale}, + // then the condition min(scale - preferredScale, powsOf2) >= remainingZeros >= z + // and the values ((intVal * 2^powsOf2) / 10^z) and (scale - z) + // are preserved invariants after each iteration. + // Note that if intVal % 5^(2^i) != 0, the loop condition will become false. + for (int i = 0; remainingZeros >= 1L << i; i++) { + final int exp = 1 << i; + qr = intVal.divideAndRemainder(fiveToTwoToThe(i)); + if (qr[1].signum != 0) { // non-0 remainder + remainingZeros = exp - 1; + } else { + intVal = qr[0]; + scale = checkScale(intVal, (long) scale - exp); // could Overflow + remainingZeros -= exp; + powsOf2 -= exp; + } + } + + // bitLength(remainingZeros) == min{n >= 0 : 5^(2^n) > 5^remainingZeros} + // so, while the loop condition is true, + // the invariant i == max{n : 5^(2^n) <= 5^remainingZeros}, + // which is equivalent to i == bitLength(remainingZeros) - 1, + // is preserved at the beginning of each iteration. + // Note that the loop stops exactly when remainingZeros == 0. + // Using the same definition of z for the first loop, the invariants + // min(scale - preferredScale, powsOf2) >= remainingZeros >= z, + // ((intVal * 2^powsOf2) / 10^z) and (scale - z) + // are preserved in this loop as well, so, when the loop ends, + // remainingZeros == 0 implies z == 0, hence (intVal * 2^powsOf2) and scale + // have the correct values to return. + for (int i = BigInteger.bitLengthForLong(remainingZeros) - 1; i >= 0; i--) { + final int exp = 1 << i; + qr = intVal.divideAndRemainder(fiveToTwoToThe(i)); + if (qr[1].signum != 0) { // non-0 remainder + remainingZeros = exp - 1; + } else { + intVal = qr[0]; + scale = checkScale(intVal, (long) scale - exp); // could Overflow + remainingZeros -= exp; + powsOf2 -= exp; + + if (remainingZeros < exp >> 1) // else i == bitLength(remainingZeros) already + i = BigInteger.bitLengthForLong(remainingZeros); + } } - return valueOf(intVal, scale, 0); + + intVal = intVal.shiftLeft(powsOf2); // restore remaining powers of 2 + return valueOf(sign >= 0 ? intVal : intVal.negate(), scale, 0); } /** @@ -5249,31 +5332,27 @@ private static BigDecimal createAndStripZerosToMatchScale(BigInteger intVal, int * {@code long} value until the preferred scale is reached or no * more zeros can be removed. If the preferred scale is less than * Integer.MIN_VALUE, all the trailing zeros will be removed. + * Assumes {@code compactVal != 0 && compactVal != INFLATED}. * * @return new {@code BigDecimal} with a scale possibly reduced * to be closed to the preferred scale. * @throws ArithmeticException if scale overflows. */ private static BigDecimal createAndStripZerosToMatchScale(long compactVal, int scale, long preferredScale) { - while (Math.abs(compactVal) >= 10L && scale > preferredScale) { - if ((compactVal & 1L) != 0L) - break; // odd number cannot end in 0 - long r = compactVal % 10L; - if (r != 0L) - break; // non-0 remainder - compactVal /= 10; - scale = checkScale(compactVal, (long) scale - 1); // could Overflow + while (compactVal % 10L == 0L && scale > preferredScale) { + compactVal /= 10L; + scale = checkScale(compactVal, scale - 1L); // could Overflow } return valueOf(compactVal, scale); } - private static BigDecimal stripZerosToMatchScale(BigInteger intVal, long intCompact, int scale, int preferredScale) { - if(intCompact!=INFLATED) { - return createAndStripZerosToMatchScale(intCompact, scale, preferredScale); - } else { - return createAndStripZerosToMatchScale(intVal==null ? INFLATED_BIGINT : intVal, - scale, preferredScale); - } + /** + * Assumes {@code intVal != 0 && intCompact != 0}. + */ + private static BigDecimal stripZerosToMatchScale(BigInteger intVal, long intCompact, int scale, long preferredScale) { + return intCompact != INFLATED + ? createAndStripZerosToMatchScale(intCompact, scale, preferredScale) + : createAndStripZerosToMatchScale(intVal == null ? INFLATED_BIGINT : intVal, scale, preferredScale); } /* diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index 3a5fd1439373c..fb6d1eca3f562 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -2779,6 +2779,13 @@ static int bitLengthForInt(int n) { return 32 - Integer.numberOfLeadingZeros(n); } + /** + * Package private method to return bit length for a long. + */ + static int bitLengthForLong(long n) { + return 64 - Long.numberOfLeadingZeros(n); + } + /** * Left shift int array a up to len by n bits. Returns the array that * results from the shift since space may have to be reallocated. diff --git a/src/java.base/share/classes/java/net/doc-files/net-properties.html b/src/java.base/share/classes/java/net/doc-files/net-properties.html index a61844cca6e09..a67df0c0d0092 100644 --- a/src/java.base/share/classes/java/net/doc-files/net-properties.html +++ b/src/java.base/share/classes/java/net/doc-files/net-properties.html @@ -253,6 +253,15 @@

    Misc HTTP URL stream protocol handler properties

    The channel binding tokens generated are of the type "tls-server-end-point" as defined in RFC 5929.

    + +
  • {@systemProperty jdk.http.maxHeaderSize} (default: 393216 or 384kB)
    + This is the maximum header field section size that a client is prepared to accept. + This is computed as the sum of the size of the uncompressed header name, plus + the size of the uncompressed header value, plus an overhead of 32 bytes for + each field section line. If a peer sends a field section that exceeds this + size a {@link java.net.ProtocolException ProtocolException} will be raised. + This applies to all versions of the HTTP protocol. A value of zero or a negative + value means no limit. If left unspecified, the default value is 393216 bytes.

    All these properties are checked only once at startup.

    diff --git a/src/java.base/share/classes/java/security/CodeSource.java b/src/java.base/share/classes/java/security/CodeSource.java index b1cf0bf3c7d2a..821964cded590 100644 --- a/src/java.base/share/classes/java/security/CodeSource.java +++ b/src/java.base/share/classes/java/security/CodeSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -556,7 +556,6 @@ private void writeObject(java.io.ObjectOutputStream oos) private void readObject(java.io.ObjectInputStream ois) throws IOException, ClassNotFoundException { - CertificateFactory cf; Hashtable cfs = null; List certList = null; @@ -577,10 +576,8 @@ private void readObject(java.io.ObjectInputStream ois) // read the certificate type, and instantiate a certificate // factory of that type (reuse existing factory if possible) String certType = ois.readUTF(); - if (cfs.containsKey(certType)) { - // reuse certificate factory - cf = cfs.get(certType); - } else { + CertificateFactory cf = cfs.get(certType); + if (cf == null) { // create new certificate factory try { cf = CertificateFactory.getInstance(certType); diff --git a/src/java.base/share/classes/java/security/DrbgParameters.java b/src/java.base/share/classes/java/security/DrbgParameters.java index ecf8d50aab121..d979aba953192 100644 --- a/src/java.base/share/classes/java/security/DrbgParameters.java +++ b/src/java.base/share/classes/java/security/DrbgParameters.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 @@ -227,6 +227,9 @@ * Calling {@link SecureRandom#generateSeed(int)} will directly read * from this system default entropy source. * + * @spec https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf + * Recommendation for Random Number Generation Using Deterministic Random Bit Generators + * * @since 9 */ public class DrbgParameters { diff --git a/src/java.base/share/classes/java/security/Key.java b/src/java.base/share/classes/java/security/Key.java index 4ba26bf1034b5..28c0098c064b7 100644 --- a/src/java.base/share/classes/java/security/Key.java +++ b/src/java.base/share/classes/java/security/Key.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,6 +86,10 @@ * Security Appendix * of the Java Object Serialization Specification for more information. * + * @spec serialization/index.html Java Object Serialization Specification + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile * @see PublicKey * @see PrivateKey * @see KeyPair @@ -124,6 +128,7 @@ public interface Key extends java.io.Serializable { * Java Security Standard Algorithm Names Specification * for information about standard key algorithm names. * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @return the name of the algorithm associated with this key. */ String getAlgorithm(); diff --git a/src/java.base/share/classes/java/security/KeyRep.java b/src/java.base/share/classes/java/security/KeyRep.java index 0a82bf82ae013..2a8877500363c 100644 --- a/src/java.base/share/classes/java/security/KeyRep.java +++ b/src/java.base/share/classes/java/security/KeyRep.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 @@ -44,6 +44,7 @@ * Security Appendix * of the Java Object Serialization Specification for more information. * + * @spec serialization/index.html Java Object Serialization Specification * @see Key * @see KeyFactory * @see javax.crypto.spec.SecretKeySpec diff --git a/src/java.base/share/classes/java/security/Permissions.java b/src/java.base/share/classes/java/security/Permissions.java index 42c1adc90021c..3bdeac6f92945 100644 --- a/src/java.base/share/classes/java/security/Permissions.java +++ b/src/java.base/share/classes/java/security/Permissions.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 @@ -407,6 +407,11 @@ private void readObject(ObjectInputStream in) throws IOException, @SuppressWarnings("unchecked") Hashtable, PermissionCollection> perms = (Hashtable, PermissionCollection>)gfields.get("perms", null); + + if (perms == null) { + throw new InvalidObjectException("perms can't be null"); + } + permsMap = new ConcurrentHashMap<>(perms.size()*2); permsMap.putAll(perms); diff --git a/src/java.base/share/classes/java/security/SecureRandom.java b/src/java.base/share/classes/java/security/SecureRandom.java index fac7f6b9383b7..734f25e6615a7 100644 --- a/src/java.base/share/classes/java/security/SecureRandom.java +++ b/src/java.base/share/classes/java/security/SecureRandom.java @@ -140,6 +140,11 @@ *
  • {@link SecureRandomSpi#engineReseed(SecureRandomParameters)} * * + * @spec https://www.rfc-editor.org/info/rfc4086 + * RFC 4086: Randomness Requirements for Security + * @spec https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-2.pdf + * Security Requirements for Cryptographic Modules + * * @see java.security.SecureRandomSpi * @see java.util.Random * diff --git a/src/java.base/share/classes/java/security/Security.java b/src/java.base/share/classes/java/security/Security.java index 6628b717eb073..322605ef5edb4 100644 --- a/src/java.base/share/classes/java/security/Security.java +++ b/src/java.base/share/classes/java/security/Security.java @@ -423,6 +423,7 @@ private static String getProviderProperty(String key, Provider provider) { * * @return the value of the specified property. * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @deprecated This method used to return the value of a proprietary * property in the master file of the "SUN" Cryptographic Service * Provider in order to determine how to parse algorithm-specific @@ -657,6 +658,7 @@ public static Provider getProvider(String name) { * if the filter is not in the required format * @throws NullPointerException if filter is {@code null} * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @see #getProviders(java.util.Map) * @since 1.3 */ @@ -734,6 +736,7 @@ public static Provider[] getProviders(String filter) { * if the filter is not in the required format * @throws NullPointerException if filter is {@code null} * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @see #getProviders(java.lang.String) * @since 1.3 */ diff --git a/src/java.base/share/classes/java/security/SignedObject.java b/src/java.base/share/classes/java/security/SignedObject.java index e2f9c764ec2da..f65300fc80814 100644 --- a/src/java.base/share/classes/java/security/SignedObject.java +++ b/src/java.base/share/classes/java/security/SignedObject.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 @@ -152,20 +152,20 @@ public final class SignedObject implements Serializable { */ public SignedObject(Serializable object, PrivateKey signingKey, Signature signingEngine) - throws IOException, InvalidKeyException, SignatureException { - // creating a stream pipe-line, from a to b - ByteArrayOutputStream b = new ByteArrayOutputStream(); - ObjectOutput a = new ObjectOutputStream(b); + throws IOException, InvalidKeyException, SignatureException { + // creating a stream pipe-line, from a to b + ByteArrayOutputStream b = new ByteArrayOutputStream(); + ObjectOutput a = new ObjectOutputStream(b); - // write and flush the object content to byte array - a.writeObject(object); - a.flush(); - a.close(); - this.content = b.toByteArray(); - b.close(); + // write and flush the object content to byte array + a.writeObject(object); + a.flush(); + a.close(); + this.content = b.toByteArray(); + b.close(); - // now sign the encapsulated object - this.sign(signingKey, signingEngine); + // now sign the encapsulated object + this.sign(signingKey, signingEngine); } /** @@ -245,12 +245,12 @@ public boolean verify(PublicKey verificationKey, * @throws SignatureException if signing fails. */ private void sign(PrivateKey signingKey, Signature signingEngine) - throws InvalidKeyException, SignatureException { - // initialize the signing engine - signingEngine.initSign(signingKey); - signingEngine.update(this.content.clone()); - this.signature = signingEngine.sign().clone(); - this.thealgorithm = signingEngine.getAlgorithm(); + throws InvalidKeyException, SignatureException { + // initialize the signing engine + signingEngine.initSign(signingKey); + signingEngine.update(this.content.clone()); + this.signature = signingEngine.sign(); + this.thealgorithm = signingEngine.getAlgorithm(); } /** @@ -263,10 +263,16 @@ private void sign(PrivateKey signingKey, Signature signingEngine) */ @Serial private void readObject(ObjectInputStream s) - throws IOException, ClassNotFoundException { - ObjectInputStream.GetField fields = s.readFields(); - content = ((byte[])fields.get("content", null)).clone(); - signature = ((byte[])fields.get("signature", null)).clone(); - thealgorithm = (String)fields.get("thealgorithm", null); + throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = s.readFields(); + byte[] c = (byte[]) fields.get("content", null); + byte[] sig = (byte[]) fields.get("signature", null); + String a = (String) fields.get("thealgorithm", null); + if (c == null || sig == null || a == null) { + throw new InvalidObjectException("One or more null fields"); + } + content = c.clone(); + signature = sig.clone(); + thealgorithm = a; } } diff --git a/src/java.base/share/classes/java/security/Timestamp.java b/src/java.base/share/classes/java/security/Timestamp.java index 10a93a9b180f7..96df37a8c1f2d 100644 --- a/src/java.base/share/classes/java/security/Timestamp.java +++ b/src/java.base/share/classes/java/security/Timestamp.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 @@ -27,6 +27,7 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.io.InvalidObjectException; import java.io.Serializable; import java.security.cert.CertPath; import java.security.cert.Certificate; @@ -78,7 +79,7 @@ public final class Timestamp implements Serializable { * {@code null}. */ public Timestamp(Date timestamp, CertPath signerCertPath) { - if (timestamp == null || signerCertPath == null) { + if (isNull(timestamp, signerCertPath)) { throw new NullPointerException(); } this.timestamp = new Date(timestamp.getTime()); // clone @@ -166,9 +167,16 @@ public String toString() { */ @java.io.Serial private void readObject(ObjectInputStream ois) - throws IOException, ClassNotFoundException { + throws IOException, ClassNotFoundException { ois.defaultReadObject(); + if (isNull(timestamp, signerCertPath)) { + throw new InvalidObjectException("Invalid null field(s)"); + } myhash = -1; timestamp = new Date(timestamp.getTime()); } + + private static boolean isNull(Date d, CertPath c) { + return (d == null || c == null); + } } diff --git a/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java b/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java index a5f4de22d89bc..c0bdf5fc2a1f8 100644 --- a/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java +++ b/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; +import java.io.InvalidObjectException; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -196,23 +197,32 @@ private void readObject(ObjectInputStream in) throws IOException, ObjectInputStream.GetField gfields = in.readFields(); // Get permissions - @SuppressWarnings("unchecked") // writeObject writes a Hashtable> // for the permissions key, so this cast is safe, unless the data is corrupt. - Hashtable> permissions = - (Hashtable>) - gfields.get("permissions", null); - perms = new ConcurrentHashMap<>(permissions.size()*2); + try { + @SuppressWarnings("unchecked") + Hashtable> permissions = + (Hashtable>) + gfields.get("permissions", null); + + if (permissions == null) { + throw new InvalidObjectException("Invalid null permissions"); + } - // Convert each entry (Vector) into a List - Set>> set = permissions.entrySet(); - for (Map.Entry> e : set) { - // Convert Vector into ArrayList - Vector vec = e.getValue(); - List list = new CopyOnWriteArrayList<>(vec); + perms = new ConcurrentHashMap<>(permissions.size()*2); - // Add to Hashtable being serialized - perms.put(e.getKey(), list); + // Convert each entry (Vector) into a List + Set>> set = permissions.entrySet(); + for (Map.Entry> e : set) { + // Convert Vector into ArrayList + Vector vec = e.getValue(); + List list = new CopyOnWriteArrayList<>(vec); + + // Add to Hashtable being serialized + perms.put(e.getKey(), list); + } + } catch (ClassCastException cce) { + throw new InvalidObjectException("Invalid type for permissions"); } } } diff --git a/src/java.base/share/classes/java/security/cert/CRL.java b/src/java.base/share/classes/java/security/cert/CRL.java index fec267de05180..fee08c3c2ed9d 100644 --- a/src/java.base/share/classes/java/security/cert/CRL.java +++ b/src/java.base/share/classes/java/security/cert/CRL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, 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 @@ -56,6 +56,8 @@ public abstract class CRL { * "{@docRoot}/../specs/security/standard-names.html"> * Java Security Standard Algorithm Names document * for information about standard CRL types. + * + * @spec security/standard-names.html Java Security Standard Algorithm Names */ protected CRL(String type) { this.type = type; diff --git a/src/java.base/share/classes/java/security/cert/CRLReason.java b/src/java.base/share/classes/java/security/cert/CRLReason.java index 2bc83f3356b29..c2b19136c437b 100644 --- a/src/java.base/share/classes/java/security/cert/CRLReason.java +++ b/src/java.base/share/classes/java/security/cert/CRLReason.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 @@ -31,6 +31,9 @@ * RFC 5280: Internet X.509 Public Key Infrastructure Certificate and CRL * Profile. * + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile * @author Sean Mullan * @since 1.7 * @see X509CRLEntry#getRevocationReason diff --git a/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java b/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java index 70083033fc6e6..3987786aecda9 100644 --- a/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java +++ b/src/java.base/share/classes/java/security/cert/CertificateRevokedException.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 @@ -28,6 +28,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.IOException; +import java.io.InvalidObjectException; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -70,6 +71,13 @@ public class CertificateRevokedException extends CertificateException { private transient Map extensions; + private static boolean isNull(Date revocationDate, + CRLReason reason, X500Principal authority, + Map extensions) { + return (revocationDate == null || reason == null || authority == null + || extensions == null); + } + /** * Constructs a {@code CertificateRevokedException} with * the specified revocation date, reason code, authority name, and map @@ -78,12 +86,12 @@ public class CertificateRevokedException extends CertificateException { * @param revocationDate the date on which the certificate was revoked. The * date is copied to protect against subsequent modification. * @param reason the revocation reason - * @param extensions a map of X.509 Extensions. Each key is an OID String - * that maps to the corresponding Extension. The map is copied to - * prevent subsequent modification. * @param authority the {@code X500Principal} that represents the name * of the authority that signed the certificate's revocation status * information + * @param extensions a map of X.509 Extensions. Each key is an OID String + * that maps to the corresponding Extension. The map is copied to + * prevent subsequent modification. * @throws NullPointerException if {@code revocationDate}, * {@code reason}, {@code authority}, or * {@code extensions} is {@code null} @@ -92,8 +100,7 @@ public class CertificateRevokedException extends CertificateException { */ public CertificateRevokedException(Date revocationDate, CRLReason reason, X500Principal authority, Map extensions) { - if (revocationDate == null || reason == null || authority == null || - extensions == null) { + if (isNull(revocationDate, reason, authority, extensions)) { throw new NullPointerException(); } this.revocationDate = new Date(revocationDate.getTime()); @@ -234,9 +241,6 @@ private void readObject(ObjectInputStream ois) // (revocationDate, reason, authority) ois.defaultReadObject(); - // Defensively copy the revocation date - revocationDate = new Date(revocationDate.getTime()); - // Read in the size (number of mappings) of the extensions map // and create the extensions map int size = ois.readInt(); @@ -247,6 +251,13 @@ private void readObject(ObjectInputStream ois) } else { extensions = HashMap.newHashMap(Math.min(size, 20)); } + // make sure all fields are set before checking + if (isNull(revocationDate, reason, authority, extensions)) { + throw new InvalidObjectException("Invalid null field(s)"); + } + + // Defensively copy the revocation date + revocationDate = new Date(revocationDate.getTime()); // Read in the extensions and put the mappings in the extensions map for (int i = 0; i < size; i++) { diff --git a/src/java.base/share/classes/java/security/cert/PKIXRevocationChecker.java b/src/java.base/share/classes/java/security/cert/PKIXRevocationChecker.java index d36fcafd3e062..387b5ed8185e8 100644 --- a/src/java.base/share/classes/java/security/cert/PKIXRevocationChecker.java +++ b/src/java.base/share/classes/java/security/cert/PKIXRevocationChecker.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 @@ -81,14 +81,13 @@ * necessary locking. Multiple threads each manipulating separate objects * need not synchronize. * + * @spec https://www.rfc-editor.org/info/rfc2560 + * RFC 2560: X.509 Internet Public Key Infrastructure Online Certificate + * Status Protocol - OCSP + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile * @since 1.8 - * - * @see RFC 2560: X.509 - * Internet Public Key Infrastructure Online Certificate Status Protocol - - * OCSP - * @see RFC 5280: - * Internet X.509 Public Key Infrastructure Certificate and Certificate - * Revocation List (CRL) Profile */ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { private URI ocspResponder; diff --git a/src/java.base/share/classes/java/security/cert/TrustAnchor.java b/src/java.base/share/classes/java/security/cert/TrustAnchor.java index 2626bcf3c2ddd..33d1e5fb43377 100644 --- a/src/java.base/share/classes/java/security/cert/TrustAnchor.java +++ b/src/java.base/share/classes/java/security/cert/TrustAnchor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,6 +125,10 @@ public class TrustAnchor { * decoded * @throws NullPointerException if the specified * {@code X509Certificate} is {@code null} + * + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile */ public TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) { @@ -207,6 +211,10 @@ public TrustAnchor(X500Principal caPrincipal, PublicKey pubKey, * or incorrectly formatted or the name constraints cannot be decoded * @throws NullPointerException if the specified {@code caName} or * {@code pubKey} parameter is {@code null} + * + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names */ public TrustAnchor(String caName, PublicKey pubKey, byte[] nameConstraints) { diff --git a/src/java.base/share/classes/java/security/cert/X509CRL.java b/src/java.base/share/classes/java/security/cert/X509CRL.java index ddb622af1fe16..111de1daf0e43 100644 --- a/src/java.base/share/classes/java/security/cert/X509CRL.java +++ b/src/java.base/share/classes/java/security/cert/X509CRL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,6 +95,9 @@ * } * } * + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile * @author Hemma Prafullchandra * @since 1.2 * @@ -457,6 +460,11 @@ public X509CRLEntry getRevokedCertificate(X509Certificate certificate) { * relevant ASN.1 definitions. * * @return the signature algorithm OID string. + * + * @spec https://www.rfc-editor.org/info/rfc3279 + * RFC 3279: Algorithms and Identifiers for the Internet X.509 + * Public Key Infrastructure Certificate and Certificate + * Revocation List (CRL) Profile */ public abstract String getSigAlgOID(); diff --git a/src/java.base/share/classes/java/security/cert/X509CRLSelector.java b/src/java.base/share/classes/java/security/cert/X509CRLSelector.java index 337dcc6342ddb..5660749884a44 100644 --- a/src/java.base/share/classes/java/security/cert/X509CRLSelector.java +++ b/src/java.base/share/classes/java/security/cert/X509CRLSelector.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 @@ -65,6 +65,9 @@ * provide the necessary locking. Multiple threads each manipulating * separate objects need not synchronize. * + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile * @see CRLSelector * @see X509CRL * @@ -193,6 +196,10 @@ public void setIssuers(Collection issuers) { * * @param names a {@code Collection} of names (or {@code null}) * @throws IOException if a parsing error occurs + * + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names * @see #getIssuerNames */ public void setIssuerNames(Collection names) throws IOException { @@ -238,6 +245,9 @@ public void addIssuer(X500Principal issuer) { * RFC 2253 form * @throws IOException if a parsing error occurs * + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names * @deprecated Use {@link #addIssuer(X500Principal)} or * {@link #addIssuerName(byte[])} instead. This method should not be * relied on as it can fail to match some CRLs because of a loss of @@ -493,6 +503,10 @@ public Collection getIssuers() { * protect against subsequent modifications. * * @return a {@code Collection} of names (or {@code null}) + * + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names * @see #setIssuerNames */ public Collection getIssuerNames() { diff --git a/src/java.base/share/classes/java/security/cert/X509CertSelector.java b/src/java.base/share/classes/java/security/cert/X509CertSelector.java index 42f036b851852..7860fd528d5f7 100644 --- a/src/java.base/share/classes/java/security/cert/X509CertSelector.java +++ b/src/java.base/share/classes/java/security/cert/X509CertSelector.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 @@ -74,6 +74,9 @@ * provide the necessary locking. Multiple threads each manipulating * separate objects need not synchronize. * + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile * @see CertSelector * @see X509Certificate * @@ -194,6 +197,9 @@ public void setIssuer(X500Principal issuer) { * (or {@code null}) * @throws IOException if a parsing error occurs (incorrect form for DN) * + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names * @deprecated Use {@link #setIssuer(X500Principal)} or * {@link #setIssuer(byte[])} instead. This method should not be relied on * as it can fail to match some certificates because of a loss of encoding @@ -286,6 +292,9 @@ public void setSubject(X500Principal subject) { * (or {@code null}) * @throws IOException if a parsing error occurs (incorrect form for DN) * + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names * @deprecated Use {@link #setSubject(X500Principal)} or * {@link #setSubject(byte[])} instead. This method should not be relied * on as it can fail to match some certificates because of a loss of @@ -728,6 +737,12 @@ public void setSubjectAlternativeNames(Collection> names) * RFC 5280, section 4.2.1.6) * @param name the name in string form (not {@code null}) * @throws IOException if a parsing error occurs + * + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names + * @spec https://www.rfc-editor.org/info/rfc822 + * RFC 822: STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES */ public void addSubjectAlternativeName(int type, String name) throws IOException { @@ -1269,6 +1284,9 @@ public X500Principal getIssuer() { * @return the required issuer distinguished name in RFC 2253 format * (or {@code null}) * + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names * @deprecated Use {@link #getIssuer()} or {@link #getIssuerAsBytes()} * instead. This method should not be relied on as it can fail to match * some certificates because of a loss of encoding information in the @@ -1328,6 +1346,9 @@ public X500Principal getSubject() { * @return the required subject distinguished name in RFC 2253 format * (or {@code null}) * + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names * @deprecated Use {@link #getSubject()} or {@link #getSubjectAsBytes()} * instead. This method should not be relied on as it can fail to match * some certificates because of a loss of encoding information in the diff --git a/src/java.base/share/classes/java/security/cert/X509Certificate.java b/src/java.base/share/classes/java/security/cert/X509Certificate.java index 22f2423145dbc..79f37a82d47bb 100644 --- a/src/java.base/share/classes/java/security/cert/X509Certificate.java +++ b/src/java.base/share/classes/java/security/cert/X509Certificate.java @@ -95,6 +95,9 @@ * } * * + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile * @author Hemma Prafullchandra * @since 1.2 * @@ -386,6 +389,11 @@ public abstract byte[] getTBSCertificate() * relevant ASN.1 definitions. * * @return the signature algorithm OID string. + * + * @spec https://www.rfc-editor.org/info/rfc3279 + * RFC 3279: Algorithms and Identifiers for the Internet X.509 + * Public Key Infrastructure Certificate and Certificate + * Revocation List (CRL) Profile */ public abstract String getSigAlgOID(); @@ -614,6 +622,12 @@ public List getExtendedKeyUsage() throws CertificateParsingException { * @return an immutable {@code Collection} of subject alternative * names (or {@code null}) * @throws CertificateParsingException if the extension cannot be decoded + * + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names + * @spec https://www.rfc-editor.org/info/rfc822 + * RFC 822: STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES * @since 1.4 */ public Collection> getSubjectAlternativeNames() diff --git a/src/java.base/share/classes/java/security/cert/package-info.java b/src/java.base/share/classes/java/security/cert/package-info.java index 0a5f0b7b532bc..e0c5b76cfd8e1 100644 --- a/src/java.base/share/classes/java/security/cert/package-info.java +++ b/src/java.base/share/classes/java/security/cert/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, 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 @@ -52,6 +52,13 @@ *
  • {@extLink security_guide_pki Java PKI Programmer's Guide} * * + * @spec security/standard-names.html Java Security Standard Algorithm Names + * @spec https://www.rfc-editor.org/info/rfc2560 + * RFC 2560: X.509 Internet Public Key Infrastructure Online Certificate + * Status Protocol - OCSP + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile * @since 1.2 */ package java.security.cert; diff --git a/src/java.base/share/classes/java/security/interfaces/DSAKeyPairGenerator.java b/src/java.base/share/classes/java/security/interfaces/DSAKeyPairGenerator.java index a4cedf1b54b44..d3ab1d0177cc5 100644 --- a/src/java.base/share/classes/java/security/interfaces/DSAKeyPairGenerator.java +++ b/src/java.base/share/classes/java/security/interfaces/DSAKeyPairGenerator.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 @@ -105,12 +105,12 @@ public interface DSAKeyPairGenerator { * @param modlen the modulus length in bits. Valid values are any * multiple of 64 between 512 and 1024, inclusive, 2048, and 3072. * - * @param random the random bit source to use to generate key bits; - * can be null. - * * @param genParams whether to generate new parameters for * the modulus length requested. * + * @param random the random bit source to use to generate key bits; + * can be null. + * * @throws InvalidParameterException if {@code modlen} is * invalid, or unsupported, or if {@code genParams} is false and there * are no precomputed parameters for the requested modulus length. diff --git a/src/java.base/share/classes/java/security/interfaces/EdECKey.java b/src/java.base/share/classes/java/security/interfaces/EdECKey.java index bec29eeed8e93..ae00dd0678d5e 100644 --- a/src/java.base/share/classes/java/security/interfaces/EdECKey.java +++ b/src/java.base/share/classes/java/security/interfaces/EdECKey.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 @@ -35,6 +35,8 @@ * This interface allows access to the algorithm parameters associated with * the key. * + * @spec https://www.rfc-editor.org/info/rfc8032 + * RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA) * @since 15 */ public interface EdECKey { diff --git a/src/java.base/share/classes/java/security/interfaces/EdECPrivateKey.java b/src/java.base/share/classes/java/security/interfaces/EdECPrivateKey.java index 2a1b194a90a40..df193891ce1d2 100644 --- a/src/java.base/share/classes/java/security/interfaces/EdECPrivateKey.java +++ b/src/java.base/share/classes/java/security/interfaces/EdECPrivateKey.java @@ -40,6 +40,8 @@ * string lengths that are a multiple of 8, and the key is represented using * a byte array. * + * @spec https://www.rfc-editor.org/info/rfc8032 + * RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA) * @since 15 */ public interface EdECPrivateKey extends EdECKey, PrivateKey { diff --git a/src/java.base/share/classes/java/security/interfaces/EdECPublicKey.java b/src/java.base/share/classes/java/security/interfaces/EdECPublicKey.java index f5a0f3c319449..5f3462164efc9 100644 --- a/src/java.base/share/classes/java/security/interfaces/EdECPublicKey.java +++ b/src/java.base/share/classes/java/security/interfaces/EdECPublicKey.java @@ -38,6 +38,8 @@ * An Edwards-Curve public key is a point on the curve, which is represented using an * EdECPoint. * + * @spec https://www.rfc-editor.org/info/rfc8032 + * RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA) * @since 15 */ public interface EdECPublicKey extends EdECKey, PublicKey { diff --git a/src/java.base/share/classes/java/security/interfaces/RSAKey.java b/src/java.base/share/classes/java/security/interfaces/RSAKey.java index f28a76869db99..1d023e58ebb30 100644 --- a/src/java.base/share/classes/java/security/interfaces/RSAKey.java +++ b/src/java.base/share/classes/java/security/interfaces/RSAKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, 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,6 +33,8 @@ * PKCS#1 v2.2 standard, * such as those for RSA, or RSASSA-PSS algorithms. * + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @author Jan Luehe * * @see RSAPublicKey diff --git a/src/java.base/share/classes/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java b/src/java.base/share/classes/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java index 079130e5fb5f9..a523d36ac708a 100644 --- a/src/java.base/share/classes/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java +++ b/src/java.base/share/classes/java/security/interfaces/RSAMultiPrimePrivateCrtKey.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 @@ -33,6 +33,8 @@ * PKCS#1 v2.2 standard, * using the Chinese Remainder Theorem (CRT) information values. * + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @author Valerie Peng * * diff --git a/src/java.base/share/classes/java/security/interfaces/RSAPrivateCrtKey.java b/src/java.base/share/classes/java/security/interfaces/RSAPrivateCrtKey.java index 1b2bed7f9c1bc..7a8bea29e7e2e 100644 --- a/src/java.base/share/classes/java/security/interfaces/RSAPrivateCrtKey.java +++ b/src/java.base/share/classes/java/security/interfaces/RSAPrivateCrtKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, 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 @@ -32,6 +32,8 @@ * PKCS#1 v2.2 standard, * using the Chinese Remainder Theorem (CRT) information values. * + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @author Jan Luehe * @since 1.2 * diff --git a/src/java.base/share/classes/java/security/package-info.java b/src/java.base/share/classes/java/security/package-info.java index ecbf629cbd912..349a895922fb7 100644 --- a/src/java.base/share/classes/java/security/package-info.java +++ b/src/java.base/share/classes/java/security/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, 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 @@ -79,6 +79,7 @@ * * * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @since 1.1 */ package java.security; diff --git a/src/java.base/share/classes/java/security/spec/DSAGenParameterSpec.java b/src/java.base/share/classes/java/security/spec/DSAGenParameterSpec.java index b51f1f54904a6..3292d6b2bf7ca 100644 --- a/src/java.base/share/classes/java/security/spec/DSAGenParameterSpec.java +++ b/src/java.base/share/classes/java/security/spec/DSAGenParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, 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 @@ -29,6 +29,9 @@ * generating DSA parameters as specified in * FIPS 186-3 Digital Signature Standard (DSS). * + * @spec https://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf + * FIPS 186-3 Digital Signature Standard (DSS) + * * @see AlgorithmParameterSpec * * @since 1.8 diff --git a/src/java.base/share/classes/java/security/spec/EdDSAParameterSpec.java b/src/java.base/share/classes/java/security/spec/EdDSAParameterSpec.java index 673e9377b1408..df81d4d94d3f9 100644 --- a/src/java.base/share/classes/java/security/spec/EdDSAParameterSpec.java +++ b/src/java.base/share/classes/java/security/spec/EdDSAParameterSpec.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 @@ -41,6 +41,8 @@ *
  • Otherwise, the mode is Ed25519 or Ed448
  • * * + * @spec https://www.rfc-editor.org/info/rfc8032 + * RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA) * @since 15 */ diff --git a/src/java.base/share/classes/java/security/spec/EdECPoint.java b/src/java.base/share/classes/java/security/spec/EdECPoint.java index cb080f8557d3d..81fd9bc554326 100644 --- a/src/java.base/share/classes/java/security/spec/EdECPoint.java +++ b/src/java.base/share/classes/java/security/spec/EdECPoint.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 @@ -42,6 +42,8 @@ * {@code BigInteger}, and implementations that consume objects of this class * may reject integer values which are not in the range [0, p). * + * @spec https://www.rfc-editor.org/info/rfc8032 + * RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA) * @since 15 */ diff --git a/src/java.base/share/classes/java/security/spec/EdECPrivateKeySpec.java b/src/java.base/share/classes/java/security/spec/EdECPrivateKeySpec.java index 370dfc92e5903..74f453aac08af 100644 --- a/src/java.base/share/classes/java/security/spec/EdECPrivateKeySpec.java +++ b/src/java.base/share/classes/java/security/spec/EdECPrivateKeySpec.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 @@ -34,6 +34,8 @@ * a byte array. This class only supports bit string lengths that are a * multiple of 8. * + * @spec https://www.rfc-editor.org/info/rfc8032 + * RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA) * @since 15 */ public final class EdECPrivateKeySpec implements KeySpec { diff --git a/src/java.base/share/classes/java/security/spec/EdECPublicKeySpec.java b/src/java.base/share/classes/java/security/spec/EdECPublicKeySpec.java index fc52b3b7968e3..f884983acf693 100644 --- a/src/java.base/share/classes/java/security/spec/EdECPublicKeySpec.java +++ b/src/java.base/share/classes/java/security/spec/EdECPublicKeySpec.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 @@ -33,6 +33,8 @@ * algorithm parameters. The public key is a point on the curve, which is * represented using an {@code EdECPoint}. * + * @spec https://www.rfc-editor.org/info/rfc8032 + * RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA) * @since 15 */ public final class EdECPublicKeySpec implements KeySpec { diff --git a/src/java.base/share/classes/java/security/spec/MGF1ParameterSpec.java b/src/java.base/share/classes/java/security/spec/MGF1ParameterSpec.java index 64e8801501588..2a26adb7e4eba 100644 --- a/src/java.base/share/classes/java/security/spec/MGF1ParameterSpec.java +++ b/src/java.base/share/classes/java/security/spec/MGF1ParameterSpec.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 @@ -55,6 +55,8 @@ * ... -- Allows for future expansion -- * } * + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @see PSSParameterSpec * @see javax.crypto.spec.OAEPParameterSpec * diff --git a/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java b/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java index 5c77089f1ca23..a05ce1b4b7a7c 100644 --- a/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java +++ b/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java @@ -65,6 +65,8 @@ * } * * + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @see MGF1ParameterSpec * @see AlgorithmParameterSpec * @see java.security.Signature @@ -96,6 +98,8 @@ public class PSSParameterSpec implements AlgorithmParameterSpec { /** * The PSS parameter set with all default values. + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @deprecated This field uses the default values defined in the PKCS #1 * standard. Some of these defaults are no longer recommended due * to advances in cryptanalysis -- see the @@ -170,6 +174,8 @@ public PSSParameterSpec(String mdName, String mgfName, * @param saltLen the length of salt in bytes * @throws IllegalArgumentException if {@code saltLen} is * less than 0 + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @deprecated This constructor uses the default values defined in * the PKCS #1 standard except for the salt length. Some of these * defaults are no longer recommended due to advances in diff --git a/src/java.base/share/classes/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java b/src/java.base/share/classes/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java index cdb55b97418e9..a3a08739a9bbe 100644 --- a/src/java.base/share/classes/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java +++ b/src/java.base/share/classes/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.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 @@ -34,6 +34,8 @@ * using the Chinese Remainder Theorem (CRT) information values * for efficiency. * + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @author Valerie Peng * * diff --git a/src/java.base/share/classes/java/security/spec/RSAOtherPrimeInfo.java b/src/java.base/share/classes/java/security/spec/RSAOtherPrimeInfo.java index b434075c6834e..140c44e309e30 100644 --- a/src/java.base/share/classes/java/security/spec/RSAOtherPrimeInfo.java +++ b/src/java.base/share/classes/java/security/spec/RSAOtherPrimeInfo.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 @@ -42,6 +42,8 @@ * * * + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @author Valerie Peng * * diff --git a/src/java.base/share/classes/java/security/spec/RSAPrivateCrtKeySpec.java b/src/java.base/share/classes/java/security/spec/RSAPrivateCrtKeySpec.java index c8bed964b0eb9..70639cf7867fe 100644 --- a/src/java.base/share/classes/java/security/spec/RSAPrivateCrtKeySpec.java +++ b/src/java.base/share/classes/java/security/spec/RSAPrivateCrtKeySpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ * PKCS#1 v2.2 standard, * using the Chinese Remainder Theorem (CRT) information values for efficiency. * + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @author Jan Luehe * @since 1.2 * diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index 1a968170a30e4..54e045e0a85ef 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -349,10 +349,11 @@ public String getInfinity() { * unchanged. * * @param infinity the string representing infinity + * @throws NullPointerException if {@code infinity} is {@code null} */ public void setInfinity(String infinity) { + this.infinity = Objects.requireNonNull(infinity); hashCode = 0; - this.infinity = infinity; } /** @@ -370,10 +371,11 @@ public String getNaN() { * unchanged. * * @param NaN the string representing "not a number" + * @throws NullPointerException if {@code NaN} is {@code null} */ public void setNaN(String NaN) { + this.NaN = Objects.requireNonNull(NaN); hashCode = 0; - this.NaN = NaN; } /** @@ -414,14 +416,18 @@ public String getCurrencySymbol() } /** - * Sets the currency symbol for the currency of these - * DecimalFormatSymbols in their locale. + * Sets the currency symbol for the currency of this + * {@code DecimalFormatSymbols} in their locale. Unlike {@link + * #setInternationalCurrencySymbol(String)}, this method does not update + * the currency attribute nor the international currency symbol attribute. * * @param currency the currency symbol + * @throws NullPointerException if {@code currency} is {@code null} * @since 1.2 */ public void setCurrencySymbol(String currency) { + Objects.requireNonNull(currency); initializeCurrency(locale); hashCode = 0; currencySymbol = currency; @@ -448,35 +454,29 @@ public String getInternationalCurrencySymbol() * this also sets the currency attribute to the corresponding Currency * instance and the currency symbol attribute to the currency's symbol * in the DecimalFormatSymbols' locale. If the currency code is not valid, - * then the currency attribute is set to null and the currency symbol - * attribute is not modified. + * then the currency attribute and the currency symbol attribute are not modified. * * @param currencyCode the currency code + * @throws NullPointerException if {@code currencyCode} is {@code null} * @see #setCurrency * @see #setCurrencySymbol * @since 1.2 */ - public void setInternationalCurrencySymbol(String currencyCode) - { + public void setInternationalCurrencySymbol(String currencyCode) { + Objects.requireNonNull(currencyCode); + // init over setting currencyInit flag as true so that currency has + // fallback if code is not valid initializeCurrency(locale); hashCode = 0; intlCurrencySymbol = currencyCode; - currency = null; - if (currencyCode != null) { - try { - currency = Currency.getInstance(currencyCode); - currencySymbol = currency.getSymbol(); - } catch (IllegalArgumentException e) { - } - } + try { + currency = Currency.getInstance(currencyCode); + currencySymbol = currency.getSymbol(locale); + } catch (IllegalArgumentException _) {} // Simply ignore if not valid } /** - * Gets the currency of these DecimalFormatSymbols. May be null if the - * currency symbol attribute was previously set to a value that's not - * a valid ISO 4217 currency code. - * - * @return the currency used, or null + * {@return the {@code Currency} of this {@code DecimalFormatSymbols}} * @since 1.4 */ public Currency getCurrency() { @@ -485,7 +485,7 @@ public Currency getCurrency() { } /** - * Sets the currency of these DecimalFormatSymbols. + * Sets the currency of this {@code DecimalFormatSymbols}. * This also sets the currency symbol attribute to the currency's symbol * in the DecimalFormatSymbols' locale, and the international currency * symbol attribute to the currency's ISO 4217 currency code. @@ -497,9 +497,7 @@ public Currency getCurrency() { * @see #setInternationalCurrencySymbol */ public void setCurrency(Currency currency) { - if (currency == null) { - throw new NullPointerException(); - } + Objects.requireNonNull(currency); initializeCurrency(locale); hashCode = 0; this.currency = currency; @@ -555,9 +553,7 @@ public String getExponentSeparator() */ public void setExponentSeparator(String exp) { - if (exp == null) { - throw new NullPointerException(); - } + Objects.requireNonNull(exp); hashCode = 0; exponentialSeparator = exp; } @@ -767,7 +763,8 @@ public boolean equals(Object obj) { patternSeparator == other.patternSeparator && infinity.equals(other.infinity) && NaN.equals(other.NaN) && - getCurrencySymbol().equals(other.getCurrencySymbol()) && // possible currency init occurs here + // Currency fields are lazy. Init via get call to ensure non-null + getCurrencySymbol().equals(other.getCurrencySymbol()) && intlCurrencySymbol.equals(other.intlCurrencySymbol) && currency == other.currency && monetarySeparator == other.monetarySeparator && @@ -800,7 +797,8 @@ public int hashCode() { patternSeparator, infinity, NaN, - getCurrencySymbol(), // possible currency init occurs here + // Currency fields are lazy. Init via get call to ensure non-null + getCurrencySymbol(), intlCurrencySymbol, currency, monetarySeparator, diff --git a/src/java.base/share/classes/java/text/MessageFormat.java b/src/java.base/share/classes/java/text/MessageFormat.java index 58872834567d5..dbe312e8583ca 100644 --- a/src/java.base/share/classes/java/text/MessageFormat.java +++ b/src/java.base/share/classes/java/text/MessageFormat.java @@ -41,6 +41,7 @@ import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; +import java.io.ObjectStreamException; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; @@ -109,17 +110,21 @@ * * *

    - * The ArgumentIndex value is a non-negative integer written + * The {@code ArgumentIndex} value is a non-negative integer written * using the digits {@code '0'} through {@code '9'}, and represents an index into the * {@code arguments} array passed to the {@code format} methods * or the result array returned by the {@code parse} methods. *

    - * The FormatType and FormatStyle values are used to create + * Any constructor or method that takes a String pattern parameter will throw an {@code IllegalArgumentException} if the + * pattern contains an {@code ArgumentIndex} value that is equal to or exceeds an implementation limit. + *

    + * The {@code FormatType} and {@code FormatStyle} values are used to create * a {@code Format} instance for the format element. The following * table shows how the values map to {@code Format} instances. These values * are case-insensitive when passed to {@link #applyPattern(String)}. Combinations * not shown in the table are illegal. A SubformatPattern must * be a valid pattern string for the {@code Format} subclass used. + * @implNote In the reference implementation, the limit of {@code ArgumentIndex} is 10,000. * * * @@ -1181,6 +1186,8 @@ public Object[] parse(String source, ParsePosition pos) { maximumArgumentNumber = argumentNumbers[i]; } } + + // Constructors/applyPattern ensure that resultArray.length < MAX_ARGUMENT_INDEX Object[] resultArray = new Object[maximumArgumentNumber + 1]; int patternOffset = 0; @@ -1459,6 +1466,9 @@ protected Object readResolve() throws InvalidObjectException { * @serial */ private int[] argumentNumbers = new int[INITIAL_FORMATS]; + // Implementation limit for ArgumentIndex pattern element. Valid indices must + // be less than this value + private static final int MAX_ARGUMENT_INDEX = 10000; /** * One less than the number of entries in {@code offsets}. Can also be thought of @@ -1639,6 +1649,11 @@ private void setFormatFromPattern(int position, int offsetNumber, + argumentNumber); } + if (argumentNumber >= MAX_ARGUMENT_INDEX) { + throw new IllegalArgumentException( + argumentNumber + " exceeds the ArgumentIndex implementation limit"); + } + // resize format information arrays if necessary if (offsetNumber >= formats.length) { int newLength = formats.length * 2; @@ -2006,24 +2021,53 @@ private static FormatStyle fromString(String text) { */ @java.io.Serial private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - boolean isValid = maxOffset >= -1 - && formats.length > maxOffset - && offsets.length > maxOffset - && argumentNumbers.length > maxOffset; + ObjectInputStream.GetField fields = in.readFields(); + if (fields.defaulted("argumentNumbers") || fields.defaulted("offsets") + || fields.defaulted("formats") || fields.defaulted("locale") + || fields.defaulted("pattern") || fields.defaulted("maxOffset")){ + throw new InvalidObjectException("Stream has missing data"); + } + + locale = (Locale) fields.get("locale", null); + String patt = (String) fields.get("pattern", null); + int maxOff = fields.get("maxOffset", -2); + int[] argNums = ((int[]) fields.get("argumentNumbers", null)).clone(); + int[] offs = ((int[]) fields.get("offsets", null)).clone(); + Format[] fmts = ((Format[]) fields.get("formats", null)).clone(); + + // Check arrays/maxOffset have correct value/length + boolean isValid = maxOff >= -1 && argNums.length > maxOff + && offs.length > maxOff && fmts.length > maxOff; + + // Check the correctness of arguments and offsets if (isValid) { - int lastOffset = pattern.length() + 1; - for (int i = maxOffset; i >= 0; --i) { - if ((offsets[i] < 0) || (offsets[i] > lastOffset)) { + int lastOffset = patt.length(); + for (int i = maxOff; i >= 0; --i) { + if (argNums[i] < 0 || argNums[i] >= MAX_ARGUMENT_INDEX + || offs[i] < 0 || offs[i] > lastOffset) { isValid = false; break; } else { - lastOffset = offsets[i]; + lastOffset = offs[i]; } } } + if (!isValid) { - throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream."); + throw new InvalidObjectException("Stream has invalid data"); } + maxOffset = maxOff; + pattern = patt; + offsets = offs; + formats = fmts; + argumentNumbers = argNums; + } + + /** + * Serialization without data not supported for this class. + */ + @java.io.Serial + private void readObjectNoData() throws ObjectStreamException { + throw new InvalidObjectException("Deserialized MessageFormat objects need data"); } } diff --git a/src/java.base/share/classes/java/time/ZoneId.java b/src/java.base/share/classes/java/time/ZoneId.java index 21c9054761c21..47758b64e54ae 100644 --- a/src/java.base/share/classes/java/time/ZoneId.java +++ b/src/java.base/share/classes/java/time/ZoneId.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 @@ -186,15 +186,12 @@ public abstract sealed class ZoneId implements Serializable permits ZoneOffset, * This map allows the IDs to continue to be used via the * {@link #of(String, Map)} factory method. *

    - * This map contains a mapping of the IDs that is in line with TZDB 2005r and + * This map contains a mapping of the IDs that is in line with TZDB 2024b and * later, where 'EST', 'MST' and 'HST' map to IDs which do not include daylight - * savings. + * savings since 1970. This mapping may change in update releases in support of new versions of TZDB. *

    * This maps as follows: *

    * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @since 1.4 */ package javax.crypto; diff --git a/src/java.base/share/classes/javax/crypto/spec/ChaCha20ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/ChaCha20ParameterSpec.java index 75c0526946042..b1752ef940d8d 100644 --- a/src/java.base/share/classes/javax/crypto/spec/ChaCha20ParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/ChaCha20ParameterSpec.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 @@ -39,6 +39,8 @@ *

    This class can be used to initialize a {@code Cipher} object that * implements the ChaCha20 algorithm. * + * @spec https://www.rfc-editor.org/info/rfc7539 + * RFC 7539: ChaCha20 and Poly1305 for IETF Protocols * @since 11 */ public final class ChaCha20ParameterSpec implements AlgorithmParameterSpec { diff --git a/src/java.base/share/classes/javax/crypto/spec/GCMParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/GCMParameterSpec.java index 879d729c2ca0f..bb5fe5cdd5c8c 100644 --- a/src/java.base/share/classes/javax/crypto/spec/GCMParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/GCMParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, 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 @@ -56,6 +56,12 @@ * applications. Other values can be specified for this class, but not * all CSP implementations will support them. * + * @spec https://www.rfc-editor.org/info/rfc5116 + * RFC 5116: An Interface and Algorithms for Authenticated Encryption + * @spec https://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * Recommendation for Block Cipher Modes of Operation: Galois/Counter + * Mode (GCM) and GMAC + * * @see javax.crypto.Cipher * * @since 1.7 diff --git a/src/java.base/share/classes/javax/crypto/spec/OAEPParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/OAEPParameterSpec.java index efc8f3708770f..ba46399f044c6 100644 --- a/src/java.base/share/classes/javax/crypto/spec/OAEPParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/OAEPParameterSpec.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 @@ -72,6 +72,8 @@ * EncodingParameters ::= OCTET STRING(SIZE(0..MAX)) * * + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @see java.security.spec.MGF1ParameterSpec * @see PSource * diff --git a/src/java.base/share/classes/javax/crypto/spec/PBEKeySpec.java b/src/java.base/share/classes/javax/crypto/spec/PBEKeySpec.java index b21b610e78040..e47deab6fbe2f 100644 --- a/src/java.base/share/classes/javax/crypto/spec/PBEKeySpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/PBEKeySpec.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 @@ -54,6 +54,8 @@ * this class requests the password as a char array, so it can be overwritten * when done. * + * @spec https://www.rfc-editor.org/info/rfc2898 + * RFC 2898: PKCS #5: Password-Based Cryptography Specification Version 2.0 * @author Jan Luehe * @author Valerie Peng * diff --git a/src/java.base/share/classes/javax/crypto/spec/PBEParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/PBEParameterSpec.java index 84d175dfd9f7d..a44822bafec2c 100644 --- a/src/java.base/share/classes/javax/crypto/spec/PBEParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/PBEParameterSpec.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 @@ -33,6 +33,8 @@ * PKCS #5 * standard. * + * @spec https://www.rfc-editor.org/info/rfc2898 + * RFC 2898: PKCS #5: Password-Based Cryptography Specification Version 2.0 * @author Jan Luehe * * @since 1.4 diff --git a/src/java.base/share/classes/javax/crypto/spec/PSource.java b/src/java.base/share/classes/javax/crypto/spec/PSource.java index 1cd57c6f03b2c..19546a630dec7 100644 --- a/src/java.base/share/classes/javax/crypto/spec/PSource.java +++ b/src/java.base/share/classes/javax/crypto/spec/PSource.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 @@ -42,6 +42,9 @@ * } * EncodingParameters ::= OCTET STRING(SIZE(0..MAX)) * + * + * @spec https://www.rfc-editor.org/info/rfc8017 + * RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2 * @author Valerie Peng * * @since 1.5 diff --git a/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.java index 6c32ee119c54b..3c2e5a57da68a 100644 --- a/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.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 @@ -39,6 +39,8 @@ *

    This class can be used to initialize a {@code Cipher} object that * implements the RC2 algorithm. * + * @spec https://www.rfc-editor.org/info/rfc2268 + * RFC 2268: A Description of the RC2(r) Encryption Algorithm * @author Jan Luehe * * @since 1.4 diff --git a/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java index 67daf8bb19ab5..86d128afbf8b0 100644 --- a/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java @@ -39,6 +39,8 @@ *

    This class can be used to initialize a {@code Cipher} object that * implements the RC5 algorithm. * + * @spec https://www.rfc-editor.org/info/rfc2040 + * RFC 2040: The RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS Algorithms * @author Jan Luehe * * @since 1.4 diff --git a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java index e76a51e5d68c7..d36510a21a82f 100644 --- a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.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 @@ -98,13 +98,13 @@ public class SecretKeySpec implements KeySpec, SecretKey { * for information about standard algorithm names. * @exception IllegalArgumentException if algorithm * is null or key is null or empty. + * + * @spec security/standard-names.html Java Security Standard Algorithm Names */ public SecretKeySpec(byte[] key, String algorithm) { - if (key == null || algorithm == null) { - throw new IllegalArgumentException("Missing argument"); - } - if (key.length == 0) { - throw new IllegalArgumentException("Empty key"); + String errMsg = doSanityCheck(key, algorithm); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); } this.key = key.clone(); this.algorithm = algorithm; @@ -146,6 +146,8 @@ public SecretKeySpec(byte[] key, String algorithm) { * @exception ArrayIndexOutOfBoundsException is thrown if * offset or len index bytes outside the * key. + * + * @spec security/standard-names.html Java Security Standard Algorithm Names */ public SecretKeySpec(byte[] key, int offset, int len, String algorithm) { if (key == null || algorithm == null) { @@ -266,14 +268,22 @@ void clear() { private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); - - if (key == null || algorithm == null) { - throw new InvalidObjectException("Missing argument"); + String errMsg = doSanityCheck(key, algorithm); + if (errMsg != null) { + throw new InvalidObjectException(errMsg); } + byte[] temp = key; + this.key = temp.clone(); + Arrays.fill(temp, (byte) 0); + } - this.key = key.clone(); - if (key.length == 0) { - throw new InvalidObjectException("Invalid key length"); + private static String doSanityCheck(byte[] key, String algorithm) { + String errMsg = null; + if (key == null || algorithm == null) { + errMsg = "Missing argument"; + } else if (key.length == 0) { + errMsg = "Empty key"; } + return errMsg; } } diff --git a/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java b/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java index c1ddf221ab503..2b98f4845cf66 100644 --- a/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java +++ b/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, 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 @@ -63,6 +63,7 @@ public ExtendedSSLSession() {} * order of preference. The return value is an empty array if * no signature algorithm is supported. * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @see SSLParameters#getAlgorithmConstraints */ public abstract String[] getLocalSupportedSignatureAlgorithms(); @@ -86,6 +87,7 @@ public ExtendedSSLSession() {} * order of preference. The return value is an empty array if * the peer has not sent the supported signature algorithms. * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @see X509KeyManager * @see X509ExtendedKeyManager */ diff --git a/src/java.base/share/classes/javax/net/ssl/SNIHostName.java b/src/java.base/share/classes/javax/net/ssl/SNIHostName.java index 5abb9df1200f3..039ee41aab07d 100644 --- a/src/java.base/share/classes/javax/net/ssl/SNIHostName.java +++ b/src/java.base/share/classes/javax/net/ssl/SNIHostName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,11 @@ *

    * Note that {@code SNIHostName} objects are immutable. * + * @spec https://www.rfc-editor.org/info/rfc5890 + * RFC 5890: Internationalized Domain Names for Applications (IDNA): + * Definitions and Document Framework + * @spec https://www.rfc-editor.org/info/rfc6066 + * RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions * @see SNIServerName * @see StandardConstants#SNI_HOST_NAME * @@ -92,6 +97,15 @@ public final class SNIHostName extends SNIServerName { * * @throws NullPointerException if {@code hostname} is {@code null} * @throws IllegalArgumentException if {@code hostname} is illegal + * + * @spec https://www.rfc-editor.org/info/rfc1122 + * RFC 1122: Requirements for Internet Hosts - Communication Layers + * @spec https://www.rfc-editor.org/info/rfc1123 + * RFC 1123: Requirements for Internet Hosts - Application and Support + * @spec https://www.rfc-editor.org/info/rfc3490 + * RFC 3490: Internationalizing Domain Names in Applications (IDNA) + * @spec https://www.rfc-editor.org/info/rfc6066 + * RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions */ public SNIHostName(String hostname) { // IllegalArgumentException will be thrown if {@code hostname} is @@ -159,6 +173,17 @@ public SNIHostName(String hostname) { * * @throws NullPointerException if {@code encoded} is {@code null} * @throws IllegalArgumentException if {@code encoded} is illegal + * + * @spec https://www.rfc-editor.org/info/rfc1122 + * RFC 1122: Requirements for Internet Hosts - Communication Layers + * @spec https://www.rfc-editor.org/info/rfc1123 + * RFC 1123: Requirements for Internet Hosts - Application and Support + * @spec https://www.rfc-editor.org/info/rfc3490 + * RFC 3490: Internationalizing Domain Names in Applications (IDNA) + * @spec https://www.rfc-editor.org/info/rfc4366 + * RFC 4366: Transport Layer Security (TLS) Extensions + * @spec https://www.rfc-editor.org/info/rfc6066 + * RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions */ public SNIHostName(byte[] encoded) { // NullPointerException will be thrown if {@code encoded} is null @@ -198,6 +223,11 @@ public SNIHostName(byte[] encoded) { * * @return the {@link StandardCharsets#US_ASCII}-compliant hostname * of this {@code SNIHostName} object + * + * @spec https://www.rfc-editor.org/info/rfc5890 + * RFC 5890: Internationalized Domain Names for Applications (IDNA): Definitions and Document Framework + * @spec https://www.rfc-editor.org/info/rfc6066 + * RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions */ public String getAsciiName() { return hostname; @@ -215,6 +245,9 @@ public String getAsciiName() { * the other server name object to compare with. * @return true if, and only if, the {@code other} is considered * equal to this instance + * + * @spec https://www.rfc-editor.org/info/rfc6066 + * RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions */ @Override public boolean equals(Object other) { diff --git a/src/java.base/share/classes/javax/net/ssl/SNIServerName.java b/src/java.base/share/classes/javax/net/ssl/SNIServerName.java index 142bb33de8ed2..85eab316664e9 100644 --- a/src/java.base/share/classes/javax/net/ssl/SNIServerName.java +++ b/src/java.base/share/classes/javax/net/ssl/SNIServerName.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 @@ -41,6 +41,8 @@ * {@code SNIServerName} objects are immutable. Subclasses should not provide * methods that can change the state of an instance once it has been created. * + * @spec https://www.rfc-editor.org/info/rfc6066 + * RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions * @see SSLParameters#getServerNames() * @see SSLParameters#setServerNames(List) * diff --git a/src/java.base/share/classes/javax/net/ssl/SSLEngine.java b/src/java.base/share/classes/javax/net/ssl/SSLEngine.java index 9a74c69f9f5ca..27f3c31e0e9f3 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLEngine.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLEngine.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 @@ -413,6 +413,8 @@ * because there is no way to guarantee the eventual packet ordering. * * + * @spec https://www.rfc-editor.org/info/rfc2246 + * RFC 2246: The TLS Protocol Version 1.0 * @see SSLContext * @see SSLSocket * @see SSLServerSocket @@ -859,6 +861,8 @@ public abstract SSLEngineResult unwrap(ByteBuffer src, * if this engine has not received the proper SSL/TLS/DTLS close * notification message from the peer. * + * @spec https://www.rfc-editor.org/info/rfc2246 + * RFC 2246: The TLS Protocol Version 1.0 * @see #isInboundDone() * @see #isOutboundDone() */ @@ -1351,6 +1355,8 @@ public void setSSLParameters(SSLParameters params) { * Application-Layer Protocol Negotiation (ALPN), can negotiate * application-level values between peers. * + * @spec https://www.rfc-editor.org/info/rfc7301 + * RFC 7301: Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension * @implSpec * The implementation in this class throws * {@code UnsupportedOperationException} and performs no other action. diff --git a/src/java.base/share/classes/javax/net/ssl/SSLParameters.java b/src/java.base/share/classes/javax/net/ssl/SSLParameters.java index eabf0a13f67cc..e1f4399406471 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLParameters.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLParameters.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 @@ -300,6 +300,7 @@ public String getEndpointIdentificationAlgorithm() { * Java Security Standard Algorithm Names document * for information about standard algorithm names. * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @see X509ExtendedTrustManager * * @since 1.7 @@ -674,6 +675,9 @@ public String[] getApplicationProtocols() { * @throws IllegalArgumentException if protocols is null, or if * any element in a non-empty array is null or an * empty (zero-length) string + * + * @spec https://www.rfc-editor.org/info/rfc7301 + * RFC 7301: Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension * @see #getApplicationProtocols * @since 9 */ diff --git a/src/java.base/share/classes/javax/net/ssl/SSLSocket.java b/src/java.base/share/classes/javax/net/ssl/SSLSocket.java index d0c3c9ac2ddae..25d572a561616 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLSocket.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLSocket.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 @@ -770,6 +770,9 @@ public void setSSLParameters(SSLParameters params) { * if a value was successfully negotiated. * @throws UnsupportedOperationException if the underlying provider * does not implement the operation. + * + * @spec https://www.rfc-editor.org/info/rfc7301 + * RFC 7301: Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension * @since 9 */ public String getApplicationProtocol() { diff --git a/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java b/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java index bd7c3d0157aac..cb5e3318052cc 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.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 @@ -198,6 +198,8 @@ public abstract Socket createSocket(Socket s, String host, * does not implement the operation * @throws NullPointerException if {@code s} is {@code null} * + * @spec https://www.rfc-editor.org/info/rfc6066 + * RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions * @since 1.8 */ public Socket createSocket(Socket s, InputStream consumed, diff --git a/src/java.base/share/classes/javax/net/ssl/StandardConstants.java b/src/java.base/share/classes/javax/net/ssl/StandardConstants.java index 8e1df977b977f..ca560390cb18f 100644 --- a/src/java.base/share/classes/javax/net/ssl/StandardConstants.java +++ b/src/java.base/share/classes/javax/net/ssl/StandardConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 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 @@ -49,6 +49,8 @@ private StandardConstants() { *

    * The value of this constant is {@value}. * + * @spec https://www.rfc-editor.org/info/rfc6066 + * RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions * @see SNIServerName * @see SNIHostName */ diff --git a/src/java.base/share/classes/javax/net/ssl/package-info.java b/src/java.base/share/classes/javax/net/ssl/package-info.java index f41b3b7f19a8b..cdf3b2246f632 100644 --- a/src/java.base/share/classes/javax/net/ssl/package-info.java +++ b/src/java.base/share/classes/javax/net/ssl/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ * * * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @since 1.4 */ package javax.net.ssl; diff --git a/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java b/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java index c005b4ea02b0b..1c35491e4e21f 100644 --- a/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java +++ b/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,20 +102,18 @@ public class ChoiceCallback implements Callback, java.io.Serializable { public ChoiceCallback(String prompt, String[] choices, int defaultChoice, boolean multipleSelectionsAllowed) { - if (prompt == null || prompt.isEmpty() || - choices == null || choices.length == 0 || - defaultChoice < 0 || defaultChoice >= choices.length) - throw new IllegalArgumentException(); - + choices = (choices == null || choices.length == 0 ? choices : + choices.clone()); + String errMsg = doSanityCheck(prompt, choices, defaultChoice, + multipleSelectionsAllowed); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); + } this.prompt = prompt; this.defaultChoice = defaultChoice; this.multipleSelectionsAllowed = multipleSelectionsAllowed; - this.choices = choices.clone(); - for (int i = 0; i < choices.length; i++) { - if (choices[i] == null || choices[i].isEmpty()) - throw new IllegalArgumentException(); - } + this.choices = choices; } /** @@ -183,9 +181,11 @@ public void setSelectedIndex(int selection) { * @see #getSelectedIndexes */ public void setSelectedIndexes(int[] selections) { - if (!multipleSelectionsAllowed) + if (!multipleSelectionsAllowed) { throw new UnsupportedOperationException(); - this.selections = selections == null ? null : selections.clone(); + } + this.selections = ((selections == null || selections.length == 0) ? + selections : selections.clone()); } /** @@ -211,26 +211,35 @@ public int[] getSelectedIndexes() { private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); + choices = (choices == null || choices.length == 0 ? + choices : choices.clone()); + String errMsg = doSanityCheck(prompt, choices, defaultChoice, + multipleSelectionsAllowed); + if (errMsg != null) { + throw new InvalidObjectException(errMsg); + } + selections = (selections == null || selections.length == 0 ? + selections : selections.clone()); + if (selections != null && selections.length > 1 && + !multipleSelectionsAllowed) { + throw new InvalidObjectException("Multiple selections not allowed"); + } + } + + private static String doSanityCheck(String prompt, String[] choices, + int defaultChoice, boolean allowMultiple) { if ((prompt == null) || prompt.isEmpty() || (choices == null) || (choices.length == 0) || (defaultChoice < 0) || (defaultChoice >= choices.length)) { - throw new InvalidObjectException( - "Missing/invalid prompt/choices"); + return "Missing/invalid prompt/choices"; } - choices = choices.clone(); for (int i = 0; i < choices.length; i++) { - if ((choices[i] == null) || choices[i].isEmpty()) - throw new InvalidObjectException("Null/empty choices"); - } - - if (selections != null) { - selections = selections.clone(); - if (!multipleSelectionsAllowed && (selections.length != 1)) { - throw new InvalidObjectException( - "Multiple selections not allowed"); + if ((choices[i] == null) || choices[i].isEmpty()) { + return "Null/empty choices value"; } } + return null; } } diff --git a/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java b/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java index 437ce7041a7d7..a00fc7013ecc1 100644 --- a/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java +++ b/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package javax.security.auth.callback; import java.io.IOException; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; /** @@ -189,25 +190,10 @@ public class ConfirmationCallback implements Callback, java.io.Serializable { */ public ConfirmationCallback(int messageType, int optionType, int defaultOption) { - - if (messageType < INFORMATION || messageType > ERROR || - optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION) - throw new IllegalArgumentException(); - - switch (optionType) { - case YES_NO_OPTION: - if (defaultOption != YES && defaultOption != NO) - throw new IllegalArgumentException(); - break; - case YES_NO_CANCEL_OPTION: - if (defaultOption != YES && defaultOption != NO && - defaultOption != CANCEL) - throw new IllegalArgumentException(); - break; - case OK_CANCEL_OPTION: - if (defaultOption != OK && defaultOption != CANCEL) - throw new IllegalArgumentException(); - break; + String errMsg = doSanityCheck(messageType, optionType, false, null, + defaultOption, null, false); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); } this.prompt = null; @@ -250,21 +236,20 @@ public ConfirmationCallback(int messageType, public ConfirmationCallback(int messageType, String[] options, int defaultOption) { - if (messageType < INFORMATION || messageType > ERROR || - options == null || options.length == 0 || - defaultOption < 0 || defaultOption >= options.length) - throw new IllegalArgumentException(); + if (options != null) { + options = options.clone(); + } + String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true, + options, defaultOption, null, false); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); + } this.prompt = null; this.messageType = messageType; this.optionType = UNSPECIFIED_OPTION; this.defaultOption = defaultOption; - - this.options = options.clone(); - for (int i = 0; i < options.length; i++) { - if (options[i] == null || options[i].isEmpty()) - throw new IllegalArgumentException(); - } + this.options = options; } /** @@ -304,27 +289,11 @@ public ConfirmationCallback(int messageType, public ConfirmationCallback(String prompt, int messageType, int optionType, int defaultOption) { - if (prompt == null || prompt.isEmpty() || - messageType < INFORMATION || messageType > ERROR || - optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION) - throw new IllegalArgumentException(); - - switch (optionType) { - case YES_NO_OPTION: - if (defaultOption != YES && defaultOption != NO) - throw new IllegalArgumentException(); - break; - case YES_NO_CANCEL_OPTION: - if (defaultOption != YES && defaultOption != NO && - defaultOption != CANCEL) - throw new IllegalArgumentException(); - break; - case OK_CANCEL_OPTION: - if (defaultOption != OK && defaultOption != CANCEL) - throw new IllegalArgumentException(); - break; + String errMsg = doSanityCheck(messageType, optionType, false, null, + defaultOption, prompt, true); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); } - this.prompt = prompt; this.messageType = messageType; this.optionType = optionType; @@ -369,22 +338,20 @@ public ConfirmationCallback(String prompt, int messageType, public ConfirmationCallback(String prompt, int messageType, String[] options, int defaultOption) { - if (prompt == null || prompt.isEmpty() || - messageType < INFORMATION || messageType > ERROR || - options == null || options.length == 0 || - defaultOption < 0 || defaultOption >= options.length) - throw new IllegalArgumentException(); + if (options != null) { + options = options.clone(); + } + String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true, + options, defaultOption, prompt, true); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); + } this.prompt = prompt; this.messageType = messageType; this.optionType = UNSPECIFIED_OPTION; this.defaultOption = defaultOption; - - this.options = options.clone(); - for (int i = 0; i < options.length; i++) { - if (options[i] == null || options[i].isEmpty()) - throw new IllegalArgumentException(); - } + this.options = options; } /** @@ -491,6 +458,49 @@ public int getSelectedIndex() { return selection; } + private static String doSanityCheck(int msgType, int optionType, + boolean isUnspecifiedOption, String[] options, int defOption, + String prompt, boolean checkPrompt) { + // validate msgType + if (msgType < INFORMATION || msgType > ERROR) { + return "Invalid msgType"; + } + // validate prompt if checkPrompt == true + if (checkPrompt && (prompt == null || prompt.isEmpty())) { + return "Invalid prompt"; + } + // validate optionType + if (isUnspecifiedOption) { + if (optionType != UNSPECIFIED_OPTION) { + return "Invalid optionType"; + } + // check options + if (options == null || options.length == 0 || + defOption < 0 || defOption >= options.length) { + return "Invalid options and/or default option"; + } + for (String ov : options) { + if (ov == null || ov.isEmpty()) { + return "Invalid option value"; + } + } + } else { + if (optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION) { + return "Invalid optionType"; + } + // validate defOption based on optionType + if ((optionType == YES_NO_OPTION && (defOption != YES && + defOption != NO)) || + (optionType == YES_NO_CANCEL_OPTION && (defOption != YES && + defOption != NO && defOption != CANCEL)) || + (optionType == OK_CANCEL_OPTION && (defOption != OK && + defOption != CANCEL))) { + return "Invalid default option"; + } + } + return null; + } + /** * Restores the state of this object from the stream. * @@ -502,8 +512,15 @@ public int getSelectedIndex() { private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); + if (options != null) { options = options.clone(); } + String errMsg = doSanityCheck(messageType, optionType, + (optionType == UNSPECIFIED_OPTION), options, defaultOption, + prompt, false); + if (errMsg != null) { + throw new InvalidObjectException(errMsg); + } } } diff --git a/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java b/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java index bbe7ab882a6a1..2bee38ceaaaf0 100644 --- a/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java +++ b/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,9 @@ private void readObject(ObjectInputStream stream) } if (inputPassword != null) { - inputPassword = inputPassword.clone(); + char[] temp = inputPassword; + inputPassword = temp.clone(); + Arrays.fill(temp, '0'); cleanable = CleanerFactory.cleaner().register( this, cleanerFor(inputPassword)); } diff --git a/src/java.base/share/classes/javax/security/auth/login/package-info.java b/src/java.base/share/classes/javax/security/auth/login/package-info.java index 70d25f1acaa8b..658f219f20bce 100644 --- a/src/java.base/share/classes/javax/security/auth/login/package-info.java +++ b/src/java.base/share/classes/javax/security/auth/login/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ * * * + * @spec security/standard-names.html Java Security Standard Algorithm Names * @since 1.4 */ package javax.security.auth.login; diff --git a/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java b/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java index efc5b7891b81a..93e34ad65ef4f 100644 --- a/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java +++ b/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java @@ -60,6 +60,14 @@ * {@code X509Certificate} return X500Principals representing the * issuer and subject fields of the certificate. * + * @spec https://www.rfc-editor.org/info/rfc1779 + * RFC 1779: A String Representation of Distinguished Names + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile * @see java.security.cert.X509Certificate * @since 1.4 */ @@ -141,6 +149,10 @@ public X500Principal asX500Principal(X500Name name) { * is {@code null} * @exception IllegalArgumentException if the {@code name} * is improperly specified + * + * @spec https://www.rfc-editor.org/info/rfc4512 + * RFC 4512: Lightweight Directory Access Protocol (LDAP): + * Directory Information Models */ public X500Principal(String name) { this(name, Collections.emptyMap()); @@ -181,6 +193,10 @@ public X500Principal(String name) { * @exception IllegalArgumentException if the {@code name} is * improperly specified or a keyword in the {@code name} maps to an * OID that is not in the correct form + * + * @spec https://www.rfc-editor.org/info/rfc4512 + * RFC 4512: Lightweight Directory Access Protocol (LDAP): + * Directory Information Models * @since 1.6 */ public X500Principal(String name, Map keywordMap) { diff --git a/src/java.base/share/classes/javax/security/auth/x500/package-info.java b/src/java.base/share/classes/javax/security/auth/x500/package-info.java index 45859a79bedf0..b2afa89d2517e 100644 --- a/src/java.base/share/classes/javax/security/auth/x500/package-info.java +++ b/src/java.base/share/classes/javax/security/auth/x500/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,17 @@ * Directory Information Models * * + * @spec https://www.rfc-editor.org/info/rfc1779 + * RFC 1779: A String Representation of Distinguished Names + * @spec https://www.rfc-editor.org/info/rfc2253 + * RFC 2253: Lightweight Directory Access Protocol (v3): + * UTF-8 String Representation of Distinguished Names + * @spec https://www.rfc-editor.org/info/rfc4512 + * RFC 4512: Lightweight Directory Access Protocol (LDAP): + * Directory Information Models + * @spec https://www.rfc-editor.org/info/rfc5280 + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate + * and Certificate Revocation List (CRL) Profile * @since 1.4 */ package javax.security.auth.x500; diff --git a/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java index 2c9d904005d80..9ff0f2e8b920d 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java @@ -25,6 +25,7 @@ package jdk.internal.access; +import java.util.BitSet; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; @@ -38,7 +39,7 @@ public interface JavaUtilZipFileAccess { public List getManifestAndSignatureRelatedFiles(JarFile zip); public String getManifestName(JarFile zip, boolean onlyIfSignatureRelatedFiles); public int getManifestNum(JarFile zip); - public int[] getMetaInfVersions(JarFile zip); + public BitSet getMetaInfVersions(JarFile zip, String name); public Enumeration entries(ZipFile zip); public Stream stream(ZipFile zip); public Stream entryNameStream(ZipFile zip); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java index 50c0bdc2a9fc0..b29b9f6f9551e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java @@ -140,14 +140,13 @@ public CharacterRangeTableAttribute readAttribute(AttributedElement e, ClassRead } @Override - protected void writeBody(BufWriter buf, CharacterRangeTableAttribute attr) { + protected void writeBody(BufWriter bufWriter, CharacterRangeTableAttribute attr) { List ranges = attr.characterRangeTable(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(ranges.size()); for (CharacterRangeInfo info : ranges) { - buf.writeU2(info.startPc()); - buf.writeU2(info.endPc()); - buf.writeInt(info.characterRangeStart()); - buf.writeInt(info.characterRangeEnd()); + buf.writeU2U2(info.startPc(), info.endPc()); + buf.writeIntInt(info.characterRangeStart(), info.characterRangeEnd()); buf.writeU2(info.flags()); } } @@ -238,9 +237,10 @@ public EnclosingMethodAttribute readAttribute(AttributedElement e, ClassReader c } @Override - protected void writeBody(BufWriter buf, EnclosingMethodAttribute attr) { - buf.writeIndex(attr.enclosingClass()); - buf.writeIndexOrZero(attr.enclosingMethod().orElse(null)); + protected void writeBody(BufWriter bufWriter, EnclosingMethodAttribute attr) { + BufWriterImpl buf = (BufWriterImpl) bufWriter; + buf.writeU2U2(buf.cpIndex(attr.enclosingClass()), + buf.cpIndexOrZero(attr.enclosingMethod().orElse(null))); } } @@ -275,13 +275,14 @@ public InnerClassesAttribute readAttribute(AttributedElement e, ClassReader cf, } @Override - protected void writeBody(BufWriter buf, InnerClassesAttribute attr) { + protected void writeBody(BufWriter bufWriter, InnerClassesAttribute attr) { List classes = attr.classes(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(classes.size()); for (InnerClassInfo ic : classes) { - buf.writeIndex(ic.innerClass()); - buf.writeIndexOrZero(ic.outerClass().orElse(null)); - buf.writeIndexOrZero(ic.innerName().orElse(null)); + buf.writeU2U2U2(buf.cpIndex(ic.innerClass()), + buf.cpIndexOrZero(ic.outerClass().orElse(null)), + buf.cpIndexOrZero(ic.innerName().orElse(null))); buf.writeU2(ic.flagsMask()); } } @@ -300,12 +301,12 @@ public LineNumberTableAttribute readAttribute(AttributedElement e, ClassReader c } @Override - protected void writeBody(BufWriter buf, LineNumberTableAttribute attr) { + protected void writeBody(BufWriter bufWriter, LineNumberTableAttribute attr) { List lines = attr.lineNumbers(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(lines.size()); for (LineNumberInfo line : lines) { - buf.writeU2(line.startPc()); - buf.writeU2(line.lineNumber()); + buf.writeU2U2(line.startPc(), line.lineNumber()); } } } @@ -323,15 +324,13 @@ public LocalVariableTableAttribute readAttribute(AttributedElement e, ClassReade } @Override - protected void writeBody(BufWriter buf, LocalVariableTableAttribute attr) { + protected void writeBody(BufWriter bufWriter, LocalVariableTableAttribute attr) { List infos = attr.localVariables(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(infos.size()); for (LocalVariableInfo info : infos) { - buf.writeU2(info.startPc()); - buf.writeU2(info.length()); - buf.writeIndex(info.name()); - buf.writeIndex(info.type()); - buf.writeU2(info.slot()); + buf.writeU2U2(info.startPc(), info.length()); + buf.writeU2U2U2(buf.cpIndex(info.name()), buf.cpIndex(info.type()), info.slot()); } } } @@ -349,15 +348,13 @@ public LocalVariableTypeTableAttribute readAttribute(AttributedElement e, ClassR } @Override - protected void writeBody(BufWriter buf, LocalVariableTypeTableAttribute attr) { + protected void writeBody(BufWriter bufWriter, LocalVariableTypeTableAttribute attr) { List infos = attr.localVariableTypes(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(infos.size()); for (LocalVariableTypeInfo info : infos) { - buf.writeU2(info.startPc()); - buf.writeU2(info.length()); - buf.writeIndex(info.name()); - buf.writeIndex(info.signature()); - buf.writeU2(info.slot()); + buf.writeU2U2(info.startPc(), info.length()); + buf.writeU2U2U2(buf.cpIndex(info.name()), buf.cpIndex(info.signature()), info.slot()); } } } @@ -375,12 +372,13 @@ public MethodParametersAttribute readAttribute(AttributedElement e, ClassReader } @Override - protected void writeBody(BufWriter buf, MethodParametersAttribute attr) { + protected void writeBody(BufWriter bufWriter, MethodParametersAttribute attr) { List parameters = attr.parameters(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU1(parameters.size()); for (MethodParameterInfo info : parameters) { - buf.writeIndexOrZero(info.name().orElse(null)); - buf.writeU2(info.flagsMask()); + buf.writeU2U2(buf.cpIndexOrZero(info.name().orElse(null)), + info.flagsMask()); } } } @@ -398,26 +396,27 @@ public ModuleAttribute readAttribute(AttributedElement e, ClassReader cf, int p) } @Override - protected void writeBody(BufWriter buf, ModuleAttribute attr) { - buf.writeIndex(attr.moduleName()); - buf.writeU2(attr.moduleFlagsMask()); - buf.writeIndexOrZero(attr.moduleVersion().orElse(null)); + protected void writeBody(BufWriter bufWriter, ModuleAttribute attr) { + BufWriterImpl buf = (BufWriterImpl) bufWriter; + buf.writeU2U2U2(buf.cpIndex(attr.moduleName()), + attr.moduleFlagsMask(), + buf.cpIndexOrZero(attr.moduleVersion().orElse(null))); buf.writeU2(attr.requires().size()); for (ModuleRequireInfo require : attr.requires()) { - buf.writeIndex(require.requires()); - buf.writeU2(require.requiresFlagsMask()); - buf.writeIndexOrZero(require.requiresVersion().orElse(null)); + buf.writeU2U2U2(buf.cpIndex(require.requires()), + require.requiresFlagsMask(), + buf.cpIndexOrZero(require.requiresVersion().orElse(null))); } buf.writeU2(attr.exports().size()); for (ModuleExportInfo export : attr.exports()) { - buf.writeIndex(export.exportedPackage()); - buf.writeU2(export.exportsFlagsMask()); + buf.writeU2U2(buf.cpIndex(export.exportedPackage()), + export.exportsFlagsMask()); Util.writeListIndices(buf, export.exportsTo()); } buf.writeU2(attr.opens().size()); for (ModuleOpenInfo open : attr.opens()) { - buf.writeIndex(open.openedPackage()); - buf.writeU2(open.opensFlagsMask()); + buf.writeU2U2(buf.cpIndex(open.openedPackage()), + open.opensFlagsMask()); Util.writeListIndices(buf, open.opensTo()); } Util.writeListIndices(buf, attr.uses()); @@ -442,13 +441,13 @@ public ModuleHashesAttribute readAttribute(AttributedElement e, ClassReader cf, } @Override - protected void writeBody(BufWriter buf, ModuleHashesAttribute attr) { - buf.writeIndex(attr.algorithm()); + protected void writeBody(BufWriter bufWriter, ModuleHashesAttribute attr) { List hashes = attr.hashes(); - buf.writeU2(hashes.size()); + BufWriterImpl buf = (BufWriterImpl) bufWriter; + buf.writeU2U2(buf.cpIndex(attr.algorithm()), hashes.size()); for (ModuleHashInfo hash : hashes) { - buf.writeIndex(hash.moduleName()); - buf.writeU2(hash.hash().length); + buf.writeU2U2(buf.cpIndex(hash.moduleName()), + hash.hash().length); buf.writeBytes(hash.hash()); } } @@ -593,13 +592,14 @@ public RecordAttribute readAttribute(AttributedElement e, ClassReader cf, int p) } @Override - protected void writeBody(BufWriter buf, RecordAttribute attr) { + protected void writeBody(BufWriter bufWriter, RecordAttribute attr) { List components = attr.components(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(components.size()); for (RecordComponentInfo info : components) { - buf.writeIndex(info.name()); - buf.writeIndex(info.descriptor()); - Util.writeAttributes((BufWriterImpl) buf, info.attributes()); + buf.writeU2U2(buf.cpIndex(info.name()), + buf.cpIndex(info.descriptor())); + Util.writeAttributes(buf, info.attributes()); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java index dcbd8c8fee83d..71b08c1915f63 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java @@ -88,15 +88,12 @@ public boolean writeLocalTo(BufWriterImpl b) { return false; } int length = endBci - startBci; - b.writeU2(startBci); - b.writeU2(length); + b.writeU2U2(startBci, length); if (b.canWriteDirect(code.constantPool())) { - b.writeU2(nameIndex()); - b.writeU2(secondaryIndex()); + b.writeU2U2(nameIndex(), secondaryIndex()); } else { - b.writeIndex(name()); - b.writeIndex(secondaryEntry()); + b.writeU2U2(b.cpIndex(name()), b.cpIndex(secondaryEntry())); } b.writeU2(slot()); return true; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index d325842793705..2197ac81e378a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java @@ -24,47 +24,18 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.constantpool.PoolEntry; -import java.lang.constant.ConstantDesc; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.lang.classfile.Instruction; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.instruction.SwitchCase; -import java.lang.classfile.constantpool.FieldRefEntry; -import java.lang.classfile.constantpool.InterfaceMethodRefEntry; -import java.lang.classfile.constantpool.InvokeDynamicEntry; -import java.lang.classfile.constantpool.LoadableConstantEntry; -import java.lang.classfile.constantpool.MemberRefEntry; -import java.lang.classfile.instruction.ArrayLoadInstruction; -import java.lang.classfile.instruction.ArrayStoreInstruction; -import java.lang.classfile.instruction.BranchInstruction; -import java.lang.classfile.instruction.ConstantInstruction; -import java.lang.classfile.instruction.ConvertInstruction; -import java.lang.classfile.instruction.DiscontinuedInstruction; -import java.lang.classfile.instruction.FieldInstruction; -import java.lang.classfile.instruction.IncrementInstruction; -import java.lang.classfile.instruction.InvokeDynamicInstruction; -import java.lang.classfile.instruction.InvokeInstruction; -import java.lang.classfile.instruction.LoadInstruction; -import java.lang.classfile.instruction.LookupSwitchInstruction; -import java.lang.classfile.instruction.MonitorInstruction; -import java.lang.classfile.instruction.NewMultiArrayInstruction; -import java.lang.classfile.instruction.NewObjectInstruction; -import java.lang.classfile.instruction.NewPrimitiveArrayInstruction; -import java.lang.classfile.instruction.NewReferenceArrayInstruction; -import java.lang.classfile.instruction.NopInstruction; -import java.lang.classfile.instruction.OperatorInstruction; -import java.lang.classfile.instruction.ReturnInstruction; -import java.lang.classfile.instruction.StackInstruction; -import java.lang.classfile.instruction.StoreInstruction; -import java.lang.classfile.instruction.TableSwitchInstruction; -import java.lang.classfile.instruction.ThrowInstruction; -import java.lang.classfile.instruction.TypeCheckInstruction; import java.lang.classfile.Label; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; +import java.lang.classfile.constantpool.*; +import java.lang.classfile.instruction.*; +import java.lang.constant.ConstantDesc; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static java.util.Objects.requireNonNull; public abstract sealed class AbstractInstruction extends AbstractElement @@ -247,6 +218,9 @@ public String toString() { public record SwitchCaseImpl(int caseValue, Label target) implements SwitchCase { + public SwitchCaseImpl { + requireNonNull(target); + } } public static final class BoundLookupSwitchInstruction @@ -699,7 +673,8 @@ public void writeTo(DirectCodeBuilder writer) { if (writer.canWriteDirect(code.constantPool())) super.writeTo(writer); else - writer.writeLoadConstant(op, constantEntry()); + // We have writer.canWriteDirect(constantEntry().constantPool()) == false + writer.writeAdaptLoadConstant(op, constantEntry()); } @Override @@ -801,7 +776,12 @@ public TypeKind typeKind() { @Override public void writeTo(DirectCodeBuilder writer) { - writer.writeLocalVar(op, slot); + var op = this.op; + if (op.sizeIfFixed() == 1) { + writer.writeBytecode(op); + } else { + writer.writeLocalVar(op, slot); + } } @Override @@ -832,7 +812,12 @@ public TypeKind typeKind() { @Override public void writeTo(DirectCodeBuilder writer) { - writer.writeLocalVar(op, slot); + var op = this.op; + if (op.sizeIfFixed() == 1) { + writer.writeBytecode(op); + } else { + writer.writeLocalVar(op, slot); + } } @Override @@ -882,7 +867,7 @@ public static final class UnboundBranchInstruction public UnboundBranchInstruction(Opcode op, Label target) { super(op); - this.target = target; + this.target = requireNonNull(target); } @Override @@ -909,7 +894,7 @@ public static final class UnboundLookupSwitchInstruction public UnboundLookupSwitchInstruction(Label defaultTarget, List cases) { super(Opcode.LOOKUPSWITCH); - this.defaultTarget = defaultTarget; + this.defaultTarget = requireNonNull(defaultTarget); this.cases = List.copyOf(cases); } @@ -945,7 +930,7 @@ public UnboundTableSwitchInstruction(int lowValue, int highValue, Label defaultT super(Opcode.TABLESWITCH); this.lowValue = lowValue; this.highValue = highValue; - this.defaultTarget = defaultTarget; + this.defaultTarget = requireNonNull(defaultTarget); this.cases = List.copyOf(cases); } @@ -1020,7 +1005,7 @@ public static final class UnboundFieldInstruction public UnboundFieldInstruction(Opcode op, FieldRefEntry fieldEntry) { super(op); - this.fieldEntry = fieldEntry; + this.fieldEntry = requireNonNull(fieldEntry); } @Override @@ -1045,7 +1030,7 @@ public static final class UnboundInvokeInstruction public UnboundInvokeInstruction(Opcode op, MemberRefEntry methodEntry) { super(op); - this.methodEntry = methodEntry; + this.methodEntry = requireNonNull(methodEntry); } @Override @@ -1061,7 +1046,7 @@ public boolean isInterface() { @Override public int count() { return op == Opcode.INVOKEINTERFACE - ? Util.parameterSlots(Util.methodTypeSymbol(methodEntry.nameAndType())) + 1 + ? Util.parameterSlots(Util.methodTypeSymbol(methodEntry.type())) + 1 : 0; } @@ -1085,7 +1070,7 @@ public static final class UnboundInvokeDynamicInstruction public UnboundInvokeDynamicInstruction(InvokeDynamicEntry indyEntry) { super(Opcode.INVOKEDYNAMIC); - this.indyEntry = indyEntry; + this.indyEntry = requireNonNull(indyEntry); } @Override @@ -1110,7 +1095,7 @@ public static final class UnboundNewObjectInstruction public UnboundNewObjectInstruction(ClassEntry classEntry) { super(Opcode.NEW); - this.classEntry = classEntry; + this.classEntry = requireNonNull(classEntry); } @Override @@ -1135,7 +1120,7 @@ public static final class UnboundNewPrimitiveArrayInstruction public UnboundNewPrimitiveArrayInstruction(TypeKind typeKind) { super(Opcode.NEWARRAY); - this.typeKind = typeKind; + this.typeKind = requireNonNull(typeKind); } @Override @@ -1160,7 +1145,7 @@ public static final class UnboundNewReferenceArrayInstruction public UnboundNewReferenceArrayInstruction(ClassEntry componentTypeEntry) { super(Opcode.ANEWARRAY); - this.componentTypeEntry = componentTypeEntry; + this.componentTypeEntry = requireNonNull(componentTypeEntry); } @Override @@ -1187,7 +1172,7 @@ public static final class UnboundNewMultidimensionalArrayInstruction public UnboundNewMultidimensionalArrayInstruction(ClassEntry arrayTypeEntry, int dimensions) { super(Opcode.MULTIANEWARRAY); - this.arrayTypeEntry = arrayTypeEntry; + this.arrayTypeEntry = requireNonNull(arrayTypeEntry); this.dimensions = dimensions; } @@ -1245,7 +1230,7 @@ public static final class UnboundTypeCheckInstruction public UnboundTypeCheckInstruction(Opcode op, ClassEntry typeEntry) { super(op); - this.typeEntry = typeEntry; + this.typeEntry = requireNonNull(typeEntry); } @Override @@ -1347,7 +1332,7 @@ public static final class UnboundLoadConstantInstruction public UnboundLoadConstantInstruction(Opcode op, LoadableConstantEntry constant) { super(op); - this.constant = constant; + this.constant = requireNonNull(constant); } @Override @@ -1362,7 +1347,12 @@ public ConstantDesc constantValue() { @Override public void writeTo(DirectCodeBuilder writer) { - writer.writeLoadConstant(op, constant); + var constant = this.constant; + if (writer.canWriteDirect(constant.constantPool())) + // Allows writing ldc_w small index constants upon user request + writer.writeDirectLoadConstant(op, constant); + else + writer.writeAdaptLoadConstant(op, constant); } @Override @@ -1395,7 +1385,7 @@ public static final class UnboundJsrInstruction public UnboundJsrInstruction(Opcode op, Label target) { super(op); - this.target = target; + this.target = requireNonNull(target); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index 1d8d298857a7b..35b9f2dd1bb33 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -24,38 +24,19 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.constantpool.ConstantPoolException; +import java.lang.classfile.constantpool.*; import java.lang.constant.*; import java.lang.invoke.TypeDescriptor; import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.constantpool.ConstantDynamicEntry; -import java.lang.classfile.constantpool.ConstantPool; -import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.constantpool.DoubleEntry; -import java.lang.classfile.constantpool.FieldRefEntry; -import java.lang.classfile.constantpool.FloatEntry; -import java.lang.classfile.constantpool.IntegerEntry; -import java.lang.classfile.constantpool.InterfaceMethodRefEntry; -import java.lang.classfile.constantpool.InvokeDynamicEntry; -import java.lang.classfile.constantpool.LongEntry; -import java.lang.classfile.constantpool.MemberRefEntry; -import java.lang.classfile.constantpool.MethodHandleEntry; -import java.lang.classfile.constantpool.MethodRefEntry; -import java.lang.classfile.constantpool.MethodTypeEntry; -import java.lang.classfile.constantpool.ModuleEntry; -import java.lang.classfile.constantpool.NameAndTypeEntry; -import java.lang.classfile.constantpool.PackageEntry; -import java.lang.classfile.constantpool.PoolEntry; -import java.lang.classfile.constantpool.StringEntry; -import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.Stable; +import static java.util.Objects.requireNonNull; + public abstract sealed class AbstractPoolEntry { /* Invariant: a {CP,BSM} entry for pool P refer only to {CP,BSM} entries @@ -246,66 +227,69 @@ private void inflate() { this.contentHash = hash; charLen = rawLen; state = State.BYTE; + } else { + inflateNonAscii(singleBytes, hash); } - else { - char[] chararr = new char[rawLen]; - int chararr_count = singleBytes; - // Inflate prefix of bytes to characters - JLA.inflateBytesToChars(rawBytes, offset, chararr, 0, singleBytes); - - int px = offset + singleBytes; - int utfend = offset + rawLen; - while (px < utfend) { - int c = (int) rawBytes[px] & 0xff; - switch (c >> 4) { - case 0, 1, 2, 3, 4, 5, 6, 7: { - // 0xxx xxxx - px++; - chararr[chararr_count++] = (char) c; - hash = 31 * hash + c; - break; + } + + private void inflateNonAscii(int singleBytes, int hash) { + char[] chararr = new char[rawLen]; + int chararr_count = singleBytes; + // Inflate prefix of bytes to characters + JLA.inflateBytesToChars(rawBytes, offset, chararr, 0, singleBytes); + + int px = offset + singleBytes; + int utfend = offset + rawLen; + while (px < utfend) { + int c = (int) rawBytes[px] & 0xff; + switch (c >> 4) { + case 0, 1, 2, 3, 4, 5, 6, 7: { + // 0xxx xxxx + px++; + chararr[chararr_count++] = (char) c; + hash = 31 * hash + c; + break; + } + case 12, 13: { + // 110x xxxx 10xx xxxx + px += 2; + if (px > utfend) { + throw malformedInput(utfend); } - case 12, 13: { - // 110x xxxx 10xx xxxx - px += 2; - if (px > utfend) { - throw malformedInput(utfend); - } - int char2 = rawBytes[px - 1]; - if ((char2 & 0xC0) != 0x80) { - throw malformedInput(px); - } - char v = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); - chararr[chararr_count++] = v; - hash = 31 * hash + v; - break; + int char2 = rawBytes[px - 1]; + if ((char2 & 0xC0) != 0x80) { + throw malformedInput(px); } - case 14: { - // 1110 xxxx 10xx xxxx 10xx xxxx - px += 3; - if (px > utfend) { - throw malformedInput(utfend); - } - int char2 = rawBytes[px - 2]; - int char3 = rawBytes[px - 1]; - if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { - throw malformedInput(px - 1); - } - char v = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | (char3 & 0x3F)); - chararr[chararr_count++] = v; - hash = 31 * hash + v; - break; + char v = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); + chararr[chararr_count++] = v; + hash = 31 * hash + v; + break; + } + case 14: { + // 1110 xxxx 10xx xxxx 10xx xxxx + px += 3; + if (px > utfend) { + throw malformedInput(utfend); } - default: - // 10xx xxxx, 1111 xxxx - throw malformedInput(px); + int char2 = rawBytes[px - 2]; + int char3 = rawBytes[px - 1]; + if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { + throw malformedInput(px - 1); + } + char v = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | (char3 & 0x3F)); + chararr[chararr_count++] = v; + hash = 31 * hash + v; + break; } + default: + // 10xx xxxx, 1111 xxxx + throw malformedInput(px); } - this.contentHash = hash; - charLen = chararr_count; - this.chars = chararr; - state = State.CHAR; } + this.contentHash = hash; + charLen = chararr_count; + this.chars = chararr; + state = State.CHAR; } private ConstantPoolException malformedInput(int px) { @@ -398,45 +382,13 @@ else if ((state == State.STRING && u.state == State.STRING)) return stringValue().equals(u.stringValue()); } - /** - * Returns if this utf8 entry's content equals a substring - * of {@code s} obtained as {@code s.substring(start, end - start)}. - * This check avoids a substring allocation. - */ - public boolean equalsRegion(String s, int start, int end) { - // start and end values trusted - if (state == State.RAW) - inflate(); - int len = charLen; - if (len != end - start) - return false; - - var sv = stringValue; - if (sv != null) { - return sv.regionMatches(0, s, start, len); - } - - var chars = this.chars; - if (chars != null) { - for (int i = 0; i < len; i++) - if (chars[i] != s.charAt(start + i)) - return false; - } else { - var bytes = this.rawBytes; - for (int i = 0; i < len; i++) - if (bytes[offset + i] != s.charAt(start + i)) - return false; - } - return true; - } - @Override public boolean equalsString(String s) { if (state == State.RAW) inflate(); switch (state) { case STRING: - return stringValue.equals(s); + return stringValue.equals(requireNonNull(s)); case CHAR: if (charLen != s.length() || contentHash != s.hashCode()) return false; @@ -461,14 +413,13 @@ public boolean equalsString(String s) { @Override void writeTo(BufWriterImpl pool) { - pool.writeU1(TAG_UTF8); if (rawBytes != null) { - pool.writeU2(rawLen); + pool.writeU1U2(TAG_UTF8, rawLen); pool.writeBytes(rawBytes, offset, rawLen); } else { // state == STRING and no raw bytes - pool.writeUTF(stringValue); + pool.writeUtfEntry(stringValue); } } @@ -502,8 +453,7 @@ public T ref1() { } void writeTo(BufWriterImpl pool) { - pool.writeU1(tag()); - pool.writeU2(ref1.index()); + pool.writeU1U2(tag(), ref1.index()); } @Override @@ -532,9 +482,7 @@ public U ref2() { } void writeTo(BufWriterImpl pool) { - pool.writeU1(tag()); - pool.writeU2(ref1.index()); - pool.writeU2(ref2.index()); + pool.writeU1U2U2(tag(), ref1.index(), ref2.index()); } @Override @@ -864,9 +812,7 @@ public NameAndTypeEntryImpl nameAndType() { } void writeTo(BufWriterImpl pool) { - pool.writeU1(tag()); - pool.writeU2(bsmIndex); - pool.writeU2(nameAndType.index()); + pool.writeU1U2U2(tag(), bsmIndex, nameAndType.index()); } @Override @@ -984,9 +930,7 @@ public DirectMethodHandleDesc asSymbol() { @Override void writeTo(BufWriterImpl pool) { - pool.writeU1(TAG_METHOD_HANDLE); - pool.writeU1(refKind); - pool.writeU2(reference.index()); + pool.writeU1U1U2(TAG_METHOD_HANDLE, refKind, reference.index()); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java index dc170ce72b501..ea3af78a600a0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java @@ -24,17 +24,17 @@ */ package jdk.internal.classfile.impl; -import java.util.Optional; - -import java.lang.classfile.BufWriter; +import java.lang.classfile.Label; +import java.lang.classfile.PseudoInstruction; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.Utf8Entry; import java.lang.classfile.instruction.CharacterRange; import java.lang.classfile.instruction.ExceptionCatch; import java.lang.classfile.instruction.LocalVariable; import java.lang.classfile.instruction.LocalVariableType; -import java.lang.classfile.Label; -import java.lang.classfile.PseudoInstruction; +import java.util.Optional; + +import static java.util.Objects.requireNonNull; public abstract sealed class AbstractPseudoInstruction extends AbstractElement @@ -55,17 +55,14 @@ public static final class ExceptionCatchImpl public ExceptionCatchImpl(Label handler, Label tryStart, Label tryEnd, ClassEntry catchTypeEntry) { this.catchTypeEntry = catchTypeEntry; - this.handler = handler; - this.tryStart = tryStart; - this.tryEnd = tryEnd; + this.handler = requireNonNull(handler); + this.tryStart = requireNonNull(tryStart); + this.tryEnd = requireNonNull(tryEnd); } public ExceptionCatchImpl(Label handler, Label tryStart, Label tryEnd, Optional catchTypeEntry) { - this.catchTypeEntry = catchTypeEntry.orElse(null); - this.handler = handler; - this.tryStart = tryStart; - this.tryEnd = tryEnd; + this(handler, tryStart, tryEnd, catchTypeEntry.orElse(null)); } @Override @@ -115,8 +112,8 @@ public static final class UnboundCharacterRange public UnboundCharacterRange(Label startScope, Label endScope, int characterRangeStart, int characterRangeEnd, int flags) { - this.startScope = startScope; - this.endScope = endScope; + this.startScope = requireNonNull(startScope); + this.endScope = requireNonNull(endScope); this.characterRangeStart = characterRangeStart; this.characterRangeEnd = characterRangeEnd; this.flags = flags; @@ -165,10 +162,10 @@ private abstract static sealed class AbstractLocalPseudo extends AbstractPseudoI public AbstractLocalPseudo(int slot, Utf8Entry name, Utf8Entry descriptor, Label startScope, Label endScope) { BytecodeHelpers.validateSlot(slot); this.slot = slot; - this.name = name; - this.descriptor = descriptor; - this.startScope = startScope; - this.endScope = endScope; + this.name = requireNonNull(name); + this.descriptor = requireNonNull(descriptor); + this.startScope = requireNonNull(startScope); + this.endScope = requireNonNull(endScope); } public int slot() { @@ -200,11 +197,8 @@ public boolean writeLocalTo(BufWriterImpl b) { return false; } int length = endBci - startBci; - b.writeU2(startBci); - b.writeU2(length); - b.writeIndex(name); - b.writeIndex(descriptor); - b.writeU2(slot()); + b.writeU2U2(startBci, length); + b.writeU2U2U2(b.cpIndex(name), b.cpIndex(descriptor), slot()); return true; } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java index 9502ff7b246c9..1ff8c0014eaf8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java @@ -24,15 +24,14 @@ */ package jdk.internal.classfile.impl; -import java.util.Collections; -import java.util.List; -import java.util.function.Consumer; -import java.util.stream.Stream; - import java.lang.classfile.Attribute; import java.lang.classfile.AttributedElement; import java.lang.classfile.ClassFileElement; import java.lang.classfile.CompoundElement; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; public abstract sealed class AbstractUnboundModel extends AbstractElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java index 537110d2b23f6..ed682bbabb2b6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java @@ -24,9 +24,9 @@ */ package jdk.internal.classfile.impl; -import java.util.Set; import java.lang.classfile.AccessFlags; import java.lang.reflect.AccessFlag; +import java.util.Set; public final class AccessFlagsImpl extends AbstractElement implements AccessFlags { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java index 6aeda552b4787..92b33d491cddb 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java @@ -24,14 +24,22 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.*; -import java.lang.classfile.constantpool.*; - +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.constantpool.DoubleEntry; +import java.lang.classfile.constantpool.FloatEntry; +import java.lang.classfile.constantpool.IntegerEntry; +import java.lang.classfile.constantpool.LongEntry; +import java.lang.classfile.constantpool.Utf8Entry; import java.util.List; +import static java.util.Objects.requireNonNull; + public record AnnotationImpl(Utf8Entry className, List elements) implements Annotation { public AnnotationImpl { + requireNonNull(className); elements = List.copyOf(elements); } @@ -50,6 +58,11 @@ public String toString() { public record AnnotationElementImpl(Utf8Entry name, AnnotationValue value) implements AnnotationElement { + public AnnotationElementImpl { + requireNonNull(name); + requireNonNull(value); + } + @Override public String toString() { return name + "=" + value; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index e33012ef18353..5c4058e6dce4e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -25,22 +25,19 @@ package jdk.internal.classfile.impl; -import java.lang.classfile.Annotation; -import java.lang.classfile.AnnotationElement; -import java.lang.classfile.AnnotationValue; -import java.lang.classfile.BufWriter; -import java.lang.classfile.ClassReader; -import java.lang.classfile.constantpool.*; -import java.lang.classfile.TypeAnnotation; +import java.lang.classfile.*; +import java.lang.classfile.constantpool.DoubleEntry; +import java.lang.classfile.constantpool.FloatEntry; +import java.lang.classfile.constantpool.IntegerEntry; +import java.lang.classfile.constantpool.LongEntry; +import java.lang.classfile.constantpool.Utf8Entry; +import java.util.List; + +import jdk.internal.access.SharedSecrets; import static java.lang.classfile.AnnotationValue.*; import static java.lang.classfile.TypeAnnotation.TargetInfo.*; -import java.util.List; -import java.lang.classfile.Label; -import java.lang.classfile.constantpool.Utf8Entry; -import jdk.internal.access.SharedSecrets; - public final class AnnotationReader { private AnnotationReader() { } @@ -282,9 +279,8 @@ private static int skipTypeAnnotation(ClassReader classReader, int p) { } public static void writeAnnotation(BufWriterImpl buf, Annotation annotation) { - buf.writeIndex(annotation.className()); var elements = annotation.elements(); - buf.writeU2(elements.size()); + buf.writeU2U2(buf.cpIndex(annotation.className()), elements.size()); for (var e : elements) { buf.writeIndex(e.name()); AnnotationReader.writeAnnotationValue(buf, e.value()); @@ -315,8 +311,7 @@ public static void writeTypeAnnotation(BufWriterImpl buf, TypeAnnotation ta) { case TypeAnnotation.TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex()); case TypeAnnotation.SupertypeTarget st -> buf.writeU2(st.supertypeIndex()); case TypeAnnotation.TypeParameterBoundTarget tpbt -> { - buf.writeU1(tpbt.typeParameterIndex()); - buf.writeU1(tpbt.boundIndex()); + buf.writeU1U1(tpbt.typeParameterIndex(), tpbt.boundIndex()); } case TypeAnnotation.EmptyTarget _ -> { // nothing to write @@ -327,24 +322,21 @@ public static void writeTypeAnnotation(BufWriterImpl buf, TypeAnnotation ta) { buf.writeU2(lvt.table().size()); for (var e : lvt.table()) { int startPc = labelToBci(lr, e.startLabel(), ta); - buf.writeU2(startPc); - buf.writeU2(labelToBci(lr, e.endLabel(), ta) - startPc); - buf.writeU2(e.index()); + buf.writeU2U2U2(startPc, labelToBci(lr, e.endLabel(), ta) - startPc, e.index()); } } case TypeAnnotation.CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex()); case TypeAnnotation.OffsetTarget ot -> buf.writeU2(labelToBci(lr, ot.target(), ta)); case TypeAnnotation.TypeArgumentTarget tat -> { - buf.writeU2(labelToBci(lr, tat.target(), ta)); - buf.writeU1(tat.typeArgumentIndex()); + buf.writeU2U1(labelToBci(lr, tat.target(), ta), + tat.typeArgumentIndex()); } } // target_path buf.writeU1(ta.targetPath().size()); for (TypeAnnotation.TypePathComponent component : ta.targetPath()) { - buf.writeU1(component.typePathKind().tag()); - buf.writeU1(component.typeArgumentIndex()); + buf.writeU1U1(component.typePathKind().tag(), component.typeArgumentIndex()); } // annotation data diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java index fb9ecc98902d7..fffb963eab3c3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java @@ -24,14 +24,14 @@ */ package jdk.internal.classfile.impl; -import java.util.ArrayList; -import java.util.List; - import java.lang.classfile.Attribute; import java.lang.classfile.AttributeMapper; +import java.util.Arrays; public class AttributeHolder { - private final List> attributes = new ArrayList<>(); + private static final Attribute[] EMPTY_ATTRIBUTE_ARRAY = {}; + private int attributesCount = 0; + private Attribute[] attributes = EMPTY_ATTRIBUTE_ARRAY; public > void withAttribute(Attribute a) { if (a == null) @@ -39,36 +39,54 @@ public > void withAttribute(Attribute a) { @SuppressWarnings("unchecked") AttributeMapper am = (AttributeMapper) a.attributeMapper(); - if (!am.allowMultiple() && isPresent(am)) { - remove(am); + int attributesCount = this.attributesCount; + var attributes = this.attributes; + if (!am.allowMultiple()) { + // remove if + for (int i = attributesCount - 1; i >= 0; i--) { + if (attributes[i].attributeMapper() == am) { + attributesCount--; + System.arraycopy(attributes, i + 1, attributes, i, attributesCount - i); + } + } + } + + // add attribute + if (attributesCount >= attributes.length) { + int newCapacity = attributesCount + 4; + this.attributes = attributes = Arrays.copyOf(attributes, newCapacity); } - attributes.add(a); + attributes[attributesCount] = a; + this.attributesCount = attributesCount + 1; } public int size() { - return attributes.size(); + return attributesCount; } public void writeTo(BufWriterImpl buf) { - Util.writeAttributes(buf, attributes); + int attributesCount = this.attributesCount; + buf.writeU2(attributesCount); + for (int i = 0; i < attributesCount; i++) { + Util.writeAttribute(buf, attributes[i]); + } } @SuppressWarnings("unchecked") > A get(AttributeMapper am) { - for (Attribute a : attributes) + for (int i = 0; i < attributesCount; i++) { + Attribute a = attributes[i]; if (a.attributeMapper() == am) - return (A)a; + return (A) a; + } return null; } boolean isPresent(AttributeMapper am) { - for (Attribute a : attributes) - if (a.attributeMapper() == am) + for (int i = 0; i < attributesCount; i++) { + if (attributes[i].attributeMapper() == am) return true; + } return false; } - - private void remove(AttributeMapper am) { - attributes.removeIf(a -> a.attributeMapper() == am); - } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java index b28bcc0b4b56f..62d812ce8d41f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java @@ -26,12 +26,13 @@ import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; +import java.lang.classfile.Instruction; import java.lang.classfile.Label; import java.lang.classfile.TypeKind; import java.lang.classfile.instruction.LabelTarget; - import java.util.Objects; -import java.lang.classfile.Instruction; + +import static java.util.Objects.requireNonNull; public final class BlockCodeBuilderImpl extends NonterminalCodeBuilder @@ -80,7 +81,7 @@ private int topLocal(CodeBuilder parent) { @Override public CodeBuilder with(CodeElement element) { - parent.with(element); + parent.with(requireNonNull(element)); hasInstructions |= element instanceof Instruction; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java index 267c11c584578..ed36b5ce172bf 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java @@ -24,12 +24,11 @@ */ package jdk.internal.classfile.impl; -import java.util.List; - -import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.BootstrapMethodEntry; +import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.LoadableConstantEntry; import java.lang.classfile.constantpool.MethodHandleEntry; +import java.util.List; import static jdk.internal.classfile.impl.AbstractPoolEntry.MethodHandleEntryImpl; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java index 36ef2fa55ebef..59a2b03c91ed1 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java @@ -27,15 +27,7 @@ import java.lang.classfile.*; import java.lang.classfile.attribute.*; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.constantpool.ConstantPool; -import java.lang.classfile.constantpool.ConstantValueEntry; -import java.lang.classfile.constantpool.LoadableConstantEntry; -import java.lang.classfile.constantpool.ModuleEntry; -import java.lang.classfile.constantpool.NameAndTypeEntry; -import java.lang.classfile.constantpool.PackageEntry; -import java.lang.classfile.constantpool.PoolEntry; -import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.classfile.constantpool.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundLocalVariable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundLocalVariable.java index 3bbcd243cc11e..cb2f9c1f1b7f7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundLocalVariable.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundLocalVariable.java @@ -25,10 +25,10 @@ package jdk.internal.classfile.impl; -import java.lang.constant.ClassDesc; import java.lang.classfile.attribute.LocalVariableInfo; import java.lang.classfile.constantpool.Utf8Entry; import java.lang.classfile.instruction.LocalVariable; +import java.lang.constant.ClassDesc; public final class BoundLocalVariable extends AbstractBoundLocalVariable diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundRecordComponentInfo.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundRecordComponentInfo.java index fd96b245af19b..c246199de50e8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundRecordComponentInfo.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundRecordComponentInfo.java @@ -24,12 +24,11 @@ */ package jdk.internal.classfile.impl; -import java.util.List; - import java.lang.classfile.Attribute; import java.lang.classfile.ClassReader; import java.lang.classfile.attribute.RecordComponentInfo; import java.lang.classfile.constantpool.Utf8Entry; +import java.util.List; public final class BoundRecordComponentInfo implements RecordComponentInfo { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java index 4cc6c205fe4ff..db1300a809afc 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java @@ -25,19 +25,21 @@ */ package jdk.internal.classfile.impl; - -import java.util.Arrays; - import java.lang.classfile.BufWriter; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.PoolEntry; +import java.util.Arrays; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.vm.annotation.ForceInline; +import static java.lang.classfile.constantpool.PoolEntry.TAG_UTF8; +import static jdk.internal.util.ModifiedUtf.putChar; +import static jdk.internal.util.ModifiedUtf.utfLen; + public final class BufWriterImpl implements BufWriter { private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); @@ -111,6 +113,93 @@ public void writeU2(int x) { this.offset = offset + 2; } + @ForceInline + public void writeU1U1(int x1, int x2) { + reserveSpace(2); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) x1; + elems[offset + 1] = (byte) x2; + this.offset = offset + 2; + } + + public void writeU1U2(int u1, int u2) { + reserveSpace(3); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) u1; + elems[offset + 1] = (byte) (u2 >> 8); + elems[offset + 2] = (byte) u2; + this.offset = offset + 3; + } + + public void writeU1U1U1(int x1, int x2, int x3) { + reserveSpace(3); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) x1; + elems[offset + 1] = (byte) x2; + elems[offset + 2] = (byte) x3; + this.offset = offset + 3; + } + + public void writeU1U1U2(int x1, int x2, int x3) { + reserveSpace(4); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) x1; + elems[offset + 1] = (byte) x2; + elems[offset + 2] = (byte) (x3 >> 8); + elems[offset + 3] = (byte) x3; + this.offset = offset + 4; + } + + public void writeU1U2U2(int x1, int x2, int x3) { + reserveSpace(5); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) x1; + elems[offset + 1] = (byte) (x2 >> 8); + elems[offset + 2] = (byte) x2; + elems[offset + 3] = (byte) (x3 >> 8); + elems[offset + 4] = (byte) x3; + this.offset = offset + 5; + } + + public void writeU2U1(int x1, int x2) { + reserveSpace(3); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) (x1 >> 8); + elems[offset + 1] = (byte) x1; + elems[offset + 2] = (byte) x2; + this.offset = offset + 3; + } + + public void writeU2U2(int x1, int x2) { + reserveSpace(4); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) (x1 >> 8); + elems[offset + 1] = (byte) x1; + elems[offset + 2] = (byte) (x2 >> 8); + elems[offset + 3] = (byte) x2; + this.offset = offset + 4; + } + + public void writeU2U2U2(int x1, int x2, int x3) { + reserveSpace(6); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) (x1 >> 8); + elems[offset + 1] = (byte) x1; + elems[offset + 2] = (byte) (x2 >> 8); + elems[offset + 3] = (byte) x2; + elems[offset + 4] = (byte) (x3 >> 8); + elems[offset + 5] = (byte) x3; + this.offset = offset + 6; + } + @Override public void writeInt(int x) { reserveSpace(4); @@ -123,6 +212,21 @@ public void writeInt(int x) { this.offset = offset + 4; } + public void writeIntInt(int x1, int x2) { + reserveSpace(8); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) (x1 >> 24); + elems[offset + 1] = (byte) (x1 >> 16); + elems[offset + 2] = (byte) (x1 >> 8); + elems[offset + 3] = (byte) x1; + elems[offset + 4] = (byte) (x2 >> 24); + elems[offset + 5] = (byte) (x2 >> 16); + elems[offset + 6] = (byte) (x2 >> 8); + elems[offset + 7] = (byte) x2; + this.offset = offset + 8; + } + @Override public void writeFloat(float x) { writeInt(Float.floatToIntBits(x)); @@ -159,46 +263,28 @@ public void writeBytes(BufWriterImpl other) { } @SuppressWarnings("deprecation") - void writeUTF(String str) { + void writeUtfEntry(String str) { int strlen = str.length(); int countNonZeroAscii = JLA.countNonZeroAscii(str); - int utflen = strlen; - if (countNonZeroAscii != strlen) { - for (int i = countNonZeroAscii; i < strlen; i++) { - int c = str.charAt(i); - if (c >= 0x80 || c == 0) - utflen += (c >= 0x800) ? 2 : 1; - } - } + int utflen = utfLen(str, countNonZeroAscii); if (utflen > 65535) { throw new IllegalArgumentException("string too long"); } - reserveSpace(utflen + 2); + reserveSpace(utflen + 3); int offset = this.offset; byte[] elems = this.elems; - elems[offset ] = (byte) (utflen >> 8); - elems[offset + 1] = (byte) utflen; - offset += 2; + elems[offset ] = (byte) TAG_UTF8; + elems[offset + 1] = (byte) (utflen >> 8); + elems[offset + 2] = (byte) utflen; + offset += 3; str.getBytes(0, countNonZeroAscii, elems, offset); offset += countNonZeroAscii; - for (int i = countNonZeroAscii; i < strlen; ++i) { - char c = str.charAt(i); - if (c >= '\001' && c <= '\177') { - elems[offset++] = (byte) c; - } else if (c > '\u07FF') { - elems[offset ] = (byte) (0xE0 | c >> 12 & 0xF); - elems[offset + 1] = (byte) (0x80 | c >> 6 & 0x3F); - elems[offset + 2] = (byte) (0x80 | c & 0x3F); - offset += 3; - } else { - elems[offset ] = (byte) (0xC0 | c >> 6 & 0x1F); - elems[offset + 1] = (byte) (0x80 | c & 0x3F); - offset += 2; - } + for (int i = countNonZeroAscii; i < strlen; i++) { + offset = putChar(elems, offset, str.charAt(i)); } this.offset = offset; @@ -285,13 +371,27 @@ public void copyTo(byte[] array, int bufferOffset) { // writeIndex methods ensure that any CP info written // is relative to the correct constant pool - @ForceInline - @Override - public void writeIndex(PoolEntry entry) { + public int cpIndex(PoolEntry entry) { int idx = AbstractPoolEntry.maybeClone(constantPool, entry).index(); if (idx < 1 || idx > Character.MAX_VALUE) throw invalidIndex(idx, entry); - writeU2(idx); + return idx; + } + + public int cpIndexOrZero(PoolEntry entry) { + if (entry == null || entry.index() == 0) + return 0; + return cpIndex(entry); + } + + @ForceInline + @Override + public void writeIndex(PoolEntry entry) { + writeU2(cpIndex(entry)); + } + + public void writeIndex(int bytecode, PoolEntry entry) { + writeU1U2(bytecode, cpIndex(entry)); } static IllegalArgumentException invalidIndex(int idx, PoolEntry entry) { @@ -300,10 +400,7 @@ static IllegalArgumentException invalidIndex(int idx, PoolEntry entry) { @Override public void writeIndexOrZero(PoolEntry entry) { - if (entry == null || entry.index() == 0) - writeU2(0); - else - writeIndex(entry); + writeU2(cpIndexOrZero(entry)); } /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java index c506d265f6895..86991843f57aa 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java @@ -27,17 +27,18 @@ import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; -import java.lang.classfile.TypeKind; -import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.Label; import java.lang.classfile.MethodModel; +import java.lang.classfile.TypeKind; +import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.instruction.ExceptionCatch; - import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Consumer; +import static java.util.Objects.requireNonNull; + public final class BufferedCodeBuilder implements TerminalCodeBuilder { private final SplitConstantPool constantPool; @@ -121,7 +122,7 @@ public ConstantPoolBuilder constantPool() { public CodeBuilder with(CodeElement element) { if (finished) throw new IllegalStateException("Can't add elements after traversal"); - elements.add(element); + elements.add(requireNonNull(element)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java index 8cf274d746c1c..bd42d66dd3e9b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java @@ -24,15 +24,20 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.AccessFlags; +import java.lang.classfile.ClassModel; +import java.lang.classfile.FieldBuilder; +import java.lang.classfile.FieldElement; +import java.lang.classfile.FieldModel; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.Utf8Entry; import java.lang.reflect.AccessFlag; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Consumer; -import java.lang.classfile.*; -import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.constantpool.Utf8Entry; +import static java.util.Objects.requireNonNull; public final class BufferedFieldBuilder implements TerminalFieldBuilder { @@ -49,8 +54,8 @@ public BufferedFieldBuilder(SplitConstantPool constantPool, Utf8Entry type) { this.constantPool = constantPool; this.context = context; - this.name = name; - this.desc = type; + this.name = requireNonNull(name); + this.desc = requireNonNull(type); this.flags = new AccessFlagsImpl(AccessFlag.Location.FIELD); } @@ -61,7 +66,7 @@ public ConstantPoolBuilder constantPool() { @Override public FieldBuilder with(FieldElement element) { - elements.add(element); + elements.add(requireNonNull(element)); if (element instanceof AccessFlags f) this.flags = f; return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java index bc6ab555ae597..747fd876fbf5e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java @@ -24,6 +24,9 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.*; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.Utf8Entry; import java.lang.constant.MethodTypeDesc; import java.lang.reflect.AccessFlag; import java.util.ArrayList; @@ -31,17 +34,7 @@ import java.util.Optional; import java.util.function.Consumer; -import java.lang.classfile.AccessFlags; - -import java.lang.classfile.ClassModel; -import java.lang.classfile.CodeBuilder; -import java.lang.classfile.CodeModel; -import java.lang.classfile.CodeTransform; -import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.MethodBuilder; -import java.lang.classfile.MethodElement; -import java.lang.classfile.MethodModel; -import java.lang.classfile.constantpool.Utf8Entry; +import static java.util.Objects.requireNonNull; public final class BufferedMethodBuilder implements TerminalMethodBuilder { @@ -63,15 +56,15 @@ public BufferedMethodBuilder(SplitConstantPool constantPool, this.elements = new ArrayList<>(); this.constantPool = constantPool; this.context = context; - this.name = nameInfo; - this.desc = typeInfo; + this.name = requireNonNull(nameInfo); + this.desc = requireNonNull(typeInfo); this.flags = new AccessFlagsImpl(AccessFlag.Location.METHOD, flags); this.original = original; } @Override public MethodBuilder with(MethodElement element) { - elements.add(element); + elements.add(requireNonNull(element)); if (element instanceof AccessFlags f) this.flags = checkFlags(f); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index 6994a62c0ab06..25daf4e4648ad 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -25,6 +25,10 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.BootstrapMethodEntry; +import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; +import java.lang.classfile.constantpool.*; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; import java.lang.constant.ConstantDescs; @@ -35,18 +39,7 @@ import java.util.ArrayList; import java.util.List; -import java.lang.classfile.BootstrapMethodEntry; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.constantpool.ConstantDynamicEntry; -import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.Opcode; -import java.lang.classfile.TypeKind; -import java.lang.classfile.constantpool.LoadableConstantEntry; -import java.lang.classfile.constantpool.MemberRefEntry; -import java.lang.classfile.constantpool.MethodHandleEntry; -import java.lang.classfile.constantpool.NameAndTypeEntry; -import java.util.Objects; - +import static java.util.Objects.requireNonNull; import static jdk.internal.classfile.impl.RawBytecodeHelper.*; /** @@ -88,9 +81,9 @@ public static Opcode aload(int slot) { case 2 -> Opcode.ALOAD_2; case 3 -> Opcode.ALOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ALOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ALOAD_W; throw slotOutOfBounds(slot); } @@ -104,9 +97,9 @@ public static Opcode fload(int slot) { case 2 -> Opcode.FLOAD_2; case 3 -> Opcode.FLOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.FLOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.FLOAD_W; throw slotOutOfBounds(slot); } @@ -120,9 +113,9 @@ public static Opcode dload(int slot) { case 2 -> Opcode.DLOAD_2; case 3 -> Opcode.DLOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.DLOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.DLOAD_W; throw slotOutOfBounds(slot); } @@ -136,9 +129,9 @@ public static Opcode lload(int slot) { case 2 -> Opcode.LLOAD_2; case 3 -> Opcode.LLOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.LLOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.LLOAD_W; throw slotOutOfBounds(slot); } @@ -152,9 +145,9 @@ public static Opcode iload(int slot) { case 2 -> Opcode.ILOAD_2; case 3 -> Opcode.ILOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ILOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ILOAD_W; throw slotOutOfBounds(slot); } @@ -180,9 +173,9 @@ public static Opcode astore(int slot) { case 2 -> Opcode.ASTORE_2; case 3 -> Opcode.ASTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ASTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ASTORE_W; throw slotOutOfBounds(slot); } @@ -196,9 +189,9 @@ public static Opcode fstore(int slot) { case 2 -> Opcode.FSTORE_2; case 3 -> Opcode.FSTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.FSTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.FSTORE_W; throw slotOutOfBounds(slot); } @@ -212,9 +205,9 @@ public static Opcode dstore(int slot) { case 2 -> Opcode.DSTORE_2; case 3 -> Opcode.DSTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.DSTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.DSTORE_W; throw slotOutOfBounds(slot); } @@ -228,9 +221,9 @@ public static Opcode lstore(int slot) { case 2 -> Opcode.LSTORE_2; case 3 -> Opcode.LSTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.LSTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.LSTORE_W; throw slotOutOfBounds(slot); } @@ -244,9 +237,9 @@ public static Opcode istore(int slot) { case 2 -> Opcode.ISTORE_2; case 3 -> Opcode.ISTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ISTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ISTORE_W; throw slotOutOfBounds(slot); } @@ -264,6 +257,11 @@ public static Opcode returnOpcode(TypeKind tk) { }; } + public static int returnBytecode(TypeKind tk) { + int kind = Math.max(0, tk.ordinal() - 4); // BYTE, SHORT, CHAR, BOOLEAN becomes INT + return IRETURN + kind; + } + public static Opcode arrayLoadOpcode(TypeKind tk) { return switch (tk) { case BYTE, BOOLEAN -> Opcode.BALOAD; @@ -278,6 +276,20 @@ public static Opcode arrayLoadOpcode(TypeKind tk) { }; } + public static int arrayLoadBytecode(TypeKind tk) { + return switch (tk) { + case BYTE, BOOLEAN -> BALOAD; + case SHORT -> SALOAD; + case INT -> IALOAD; + case FLOAT -> FALOAD; + case LONG -> LALOAD; + case DOUBLE -> DALOAD; + case REFERENCE -> AALOAD; + case CHAR -> CALOAD; + case VOID -> throw new IllegalArgumentException("void not an allowable array type"); + }; + } + public static Opcode arrayStoreOpcode(TypeKind tk) { return switch (tk) { case BYTE, BOOLEAN -> Opcode.BASTORE; @@ -292,6 +304,20 @@ public static Opcode arrayStoreOpcode(TypeKind tk) { }; } + public static int arrayStoreBytecode(TypeKind tk) { + return switch (tk) { + case BYTE, BOOLEAN -> BASTORE; + case SHORT -> SASTORE; + case INT -> IASTORE; + case FLOAT -> FASTORE; + case LONG -> LASTORE; + case DOUBLE -> DASTORE; + case REFERENCE -> AASTORE; + case CHAR -> CASTORE; + case VOID -> throw new IllegalArgumentException("void not an allowable array type"); + }; + } + public static Opcode reverseBranchOpcode(Opcode op) { return switch (op) { case IFEQ -> Opcode.IFNE; @@ -314,6 +340,29 @@ public static Opcode reverseBranchOpcode(Opcode op) { }; } + public static int reverseBranchOpcode(int bytecode) { + return switch (bytecode) { + case IFEQ -> IFNE; + case IFNE -> IFEQ; + case IFLT -> IFGE; + case IFGE -> IFLT; + case IFGT -> IFLE; + case IFLE -> IFGT; + case IF_ICMPEQ -> IF_ICMPNE; + case IF_ICMPNE -> IF_ICMPEQ; + case IF_ICMPLT -> IF_ICMPGE; + case IF_ICMPGE -> IF_ICMPLT; + case IF_ICMPGT -> IF_ICMPLE; + case IF_ICMPLE -> IF_ICMPGT; + case IF_ACMPEQ -> IF_ACMPNE; + case IF_ACMPNE -> IF_ACMPEQ; + case IFNULL -> IFNONNULL; + case IFNONNULL -> IFNULL; + default -> throw new IllegalArgumentException( + String.format("Wrong opcode kind specified; found %d, expected %s", bytecode, Opcode.Kind.BRANCH)); + }; + } + public static Opcode convertOpcode(TypeKind from, TypeKind to) { return switch (from) { case INT -> @@ -377,20 +426,20 @@ public static TypeKind convertToType(Opcode opcode) { public static void validateSlot(Opcode opcode, int slot, boolean load) { int size = opcode.sizeIfFixed(); if (size == 1 && slot == (load ? intrinsicLoadSlot(opcode) : intrinsicStoreSlot(opcode)) || - size == 2 && slot == (slot & 0xFF) || - size == 4 && slot == (slot & 0xFFFF)) + size == 2 && (slot & ~0xFF) == 0 || + size == 4 && (slot & ~0xFFFF) == 0) return; throw slotOutOfBounds(opcode, slot); } public static void validateSlot(int slot) { - if ((slot & 0xFFFF) != slot) + if ((slot & ~0xFFFF) != 0) throw slotOutOfBounds(slot); } public static boolean validateAndIsWideIinc(int slot, int val) { var ret = false; - if ((slot & 0xFF) != slot) { + if ((slot & ~0xFF) != 0) { validateSlot(slot); ret = true; } @@ -404,10 +453,10 @@ public static boolean validateAndIsWideIinc(int slot, int val) { } public static void validateRet(Opcode opcode, int slot) { - if (opcode == Opcode.RET && slot == (slot & 0xFF) || - opcode == Opcode.RET_W && slot == (slot & 0xFFFF)) + if (opcode == Opcode.RET && (slot & ~0xFF) == 0 || + opcode == Opcode.RET_W && (slot & ~0xFFFF) == 0) return; - Objects.requireNonNull(opcode); + requireNonNull(opcode); throw slotOutOfBounds(opcode, slot); } @@ -495,7 +544,7 @@ public static LoadableConstantEntry constantEntry(ConstantPoolBuilder constantPo } if (constantValue instanceof DynamicConstantDesc value) { return handleConstantDescToHandleInfo(constantPool, value); } - throw new UnsupportedOperationException("not yet: " + constantValue); + throw new UnsupportedOperationException("not yet: " + requireNonNull(constantValue)); } public static ConstantDesc intrinsicConstantValue(Opcode opcode) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java index 5d262c397f6ba..abb024cfa204d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java @@ -27,7 +27,6 @@ import java.lang.classfile.CodeBuilder; import java.lang.classfile.Label; import java.lang.classfile.Opcode; - import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; import java.util.HashSet; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java index 8f05f20d739be..48d5ceb72d641 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java @@ -24,12 +24,12 @@ */ package jdk.internal.classfile.impl; -import java.lang.constant.MethodTypeDesc; -import java.util.function.Consumer; - import java.lang.classfile.*; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.Utf8Entry; +import java.util.function.Consumer; + +import static java.util.Objects.requireNonNull; public final class ChainedClassBuilder implements ClassBuilder, Consumer { @@ -47,7 +47,7 @@ public ChainedClassBuilder(ClassBuilder downstream, @Override public ClassBuilder with(ClassElement element) { - consumer.accept(element); + consumer.accept(requireNonNull(element)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java index 8c6c80b3013f3..9baa9f1212336 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.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 @@ -26,11 +26,12 @@ import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; -import java.lang.classfile.TypeKind; import java.lang.classfile.Label; - +import java.lang.classfile.TypeKind; import java.util.function.Consumer; +import static java.util.Objects.requireNonNull; + public final class ChainedCodeBuilder extends NonterminalCodeBuilder implements CodeBuilder { @@ -59,7 +60,7 @@ public int allocateLocal(TypeKind typeKind) { @Override public CodeBuilder with(CodeElement element) { - consumer.accept(element); + consumer.accept(requireNonNull(element)); return this; } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java index b3a30b5351ba7..13ca52f18de2f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java @@ -24,11 +24,12 @@ */ package jdk.internal.classfile.impl; -import java.util.function.Consumer; - import java.lang.classfile.FieldBuilder; import java.lang.classfile.FieldElement; import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.util.function.Consumer; + +import static java.util.Objects.requireNonNull; public final class ChainedFieldBuilder implements FieldBuilder { private final TerminalFieldBuilder terminal; @@ -50,7 +51,7 @@ public ConstantPoolBuilder constantPool() { @Override public FieldBuilder with(FieldElement element) { - consumer.accept(element); + consumer.accept(requireNonNull(element)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java index a7084116b9bd3..7bd0fc2ca1b23 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java @@ -24,14 +24,15 @@ */ package jdk.internal.classfile.impl; -import java.util.function.Consumer; - import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeModel; import java.lang.classfile.CodeTransform; import java.lang.classfile.MethodBuilder; import java.lang.classfile.MethodElement; import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.util.function.Consumer; + +import static java.util.Objects.requireNonNull; public final class ChainedMethodBuilder implements MethodBuilder { final TerminalMethodBuilder terminal; @@ -48,7 +49,7 @@ public ChainedMethodBuilder(MethodBuilder downstream, @Override public MethodBuilder with(MethodElement element) { - consumer.accept(element); + consumer.accept(requireNonNull(element)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java index c6d9e55d8dbcc..3ab5d24f09cf0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java @@ -25,21 +25,23 @@ package jdk.internal.classfile.impl; -import java.util.List; -import java.util.function.Function; -import java.util.function.Consumer; - import java.lang.classfile.AttributeMapper; -import java.lang.classfile.ClassFile; import java.lang.classfile.ClassBuilder; +import java.lang.classfile.ClassFile; import java.lang.classfile.ClassHierarchyResolver; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassTransform; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.Utf8Entry; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + import jdk.internal.classfile.impl.verifier.VerifierImpl; +import static java.util.Objects.requireNonNull; + public final class ClassFileImpl implements ClassFile { private Option stackMapsOption; @@ -123,7 +125,7 @@ public ClassFileImpl withOptions(Option... options) { } else if (o instanceof AttributeMapperOption oo) { amo = oo; } else { // null or unknown Option type - throw new IllegalArgumentException("Invalid option: " + o); + throw new IllegalArgumentException("Invalid option: " + requireNonNull(o)); } } return new ClassFileImpl(smo, deo, lno, apo, cpso, sjo, dco, dlo, chro, amo); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java index 34e6f5f7c1aa7..5be14f42baa1c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java @@ -30,17 +30,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; +import java.lang.classfile.ClassHierarchyResolver; import java.lang.constant.ClassDesc; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.function.Function; -import java.lang.classfile.ClassHierarchyResolver; - -import static java.lang.constant.ConstantDescs.CD_Object; -import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.ClassFile.ACC_INTERFACE; import static java.lang.classfile.constantpool.PoolEntry.*; +import static java.lang.constant.ConstantDescs.CD_Object; import static java.util.Objects.requireNonNull; import static jdk.internal.constant.ConstantUtils.referenceClassDesc; @@ -205,9 +204,9 @@ public StaticClassHierarchyResolver(Collection interfaceNames, Map methods; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java index 02026b1acf33d..b8fce2fd288c8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java @@ -24,44 +24,38 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.*; +import java.lang.classfile.AnnotationValue.*; +import java.lang.classfile.attribute.*; +import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInfo; +import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo; +import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo; +import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo; +import java.lang.classfile.components.ClassPrinter.LeafNode; +import java.lang.classfile.components.ClassPrinter.ListNode; +import java.lang.classfile.components.ClassPrinter.MapNode; +import java.lang.classfile.components.ClassPrinter.Node; +import java.lang.classfile.components.ClassPrinter.Verbosity; +import java.lang.classfile.constantpool.*; +import java.lang.classfile.instruction.*; import java.lang.constant.ConstantDesc; import java.lang.constant.DirectMethodHandleDesc; import java.lang.reflect.AccessFlag; -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.BiConsumer; -import java.util.Set; import java.util.function.Consumer; import java.util.stream.IntStream; import java.util.stream.Stream; -import java.lang.classfile.Annotation; - -import java.lang.classfile.AnnotationElement; -import java.lang.classfile.AnnotationValue; -import java.lang.classfile.AnnotationValue.*; -import java.lang.classfile.Attribute; -import java.lang.classfile.ClassModel; -import java.lang.classfile.components.ClassPrinter.*; -import java.lang.classfile.CodeModel; -import java.lang.classfile.Instruction; -import java.lang.classfile.MethodModel; -import java.lang.classfile.TypeAnnotation; -import java.lang.classfile.attribute.*; -import java.lang.classfile.attribute.StackMapFrameInfo.*; -import java.lang.classfile.constantpool.*; -import java.lang.classfile.instruction.*; -import java.lang.classfile.CompoundElement; -import java.lang.classfile.FieldModel; +import static java.lang.classfile.constantpool.PoolEntry.TAG_CLASS; +import static java.lang.classfile.constantpool.PoolEntry.TAG_DOUBLE; +import static java.lang.classfile.constantpool.PoolEntry.TAG_FLOAT; +import static java.lang.classfile.constantpool.PoolEntry.TAG_LONG; +import static java.lang.classfile.constantpool.PoolEntry.TAG_STRING; import static java.lang.classfile.constantpool.PoolEntry.*; -import static jdk.internal.classfile.impl.ClassPrinterImpl.Style.*; +import static java.util.Objects.requireNonNull; +import static jdk.internal.classfile.impl.ClassPrinterImpl.Style.BLOCK; +import static jdk.internal.classfile.impl.ClassPrinterImpl.Style.FLOW; public final class ClassPrinterImpl { @@ -564,6 +558,7 @@ private static Stream convertVTIs(CodeAttribute lr, List model, Verbosity verbosity) { + requireNonNull(verbosity); // we are using == checks in implementations return switch(model) { case ClassModel cm -> classToTree(cm, verbosity); case FieldModel fm -> fieldToTree(fm, verbosity); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java index 2ef39504e9b74..d325100febfea 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java @@ -25,6 +25,13 @@ package jdk.internal.classfile.impl; +import java.lang.classfile.*; +import java.lang.classfile.attribute.BootstrapMethodsAttribute; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPoolException; +import java.lang.classfile.constantpool.LoadableConstantEntry; +import java.lang.classfile.constantpool.PoolEntry; +import java.lang.classfile.constantpool.Utf8Entry; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -32,10 +39,6 @@ import java.util.Optional; import java.util.function.Function; -import java.lang.classfile.*; -import java.lang.classfile.attribute.BootstrapMethodsAttribute; -import java.lang.classfile.constantpool.*; - import static java.lang.classfile.constantpool.PoolEntry.*; public final class ClassReaderImpl @@ -353,7 +356,11 @@ private static boolean checkTag(int tag, Class cls) { static T checkType(PoolEntry e, int index, Class cls) { if (cls.isInstance(e)) return cls.cast(e); - throw new ConstantPoolException("Not a " + cls.getSimpleName() + " at index: " + index); + throw checkTypeError(index, cls); + } + + private static ConstantPoolException checkTypeError(int index, Class cls) { + return new ConstantPoolException("Not a " + cls.getSimpleName() + " at index: " + index); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java index 1d1d028531ecb..cd9faaf2f9a1f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java @@ -24,69 +24,13 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.Annotation; -import java.lang.classfile.AnnotationElement; -import java.lang.classfile.AnnotationValue; -import java.lang.classfile.ClassBuilder; -import java.lang.classfile.ClassElement; -import java.lang.classfile.ClassSignature; -import java.lang.classfile.CodeBuilder; -import java.lang.classfile.CodeElement; -import java.lang.classfile.CodeModel; -import java.lang.classfile.CodeTransform; -import java.lang.classfile.FieldBuilder; -import java.lang.classfile.FieldElement; -import java.lang.classfile.FieldModel; -import java.lang.classfile.FieldTransform; -import java.lang.classfile.Interfaces; -import java.lang.classfile.MethodBuilder; -import java.lang.classfile.MethodElement; -import java.lang.classfile.MethodModel; -import java.lang.classfile.MethodSignature; -import java.lang.classfile.MethodTransform; -import java.lang.classfile.Signature; -import java.lang.classfile.Superclass; -import java.lang.classfile.TypeAnnotation; -import java.lang.classfile.attribute.AnnotationDefaultAttribute; -import java.lang.classfile.attribute.EnclosingMethodAttribute; -import java.lang.classfile.attribute.ExceptionsAttribute; -import java.lang.classfile.attribute.InnerClassInfo; -import java.lang.classfile.attribute.InnerClassesAttribute; -import java.lang.classfile.attribute.ModuleAttribute; -import java.lang.classfile.attribute.ModuleProvideInfo; -import java.lang.classfile.attribute.NestHostAttribute; -import java.lang.classfile.attribute.NestMembersAttribute; -import java.lang.classfile.attribute.PermittedSubclassesAttribute; -import java.lang.classfile.attribute.RecordAttribute; -import java.lang.classfile.attribute.RecordComponentInfo; -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.SignatureAttribute; +import java.lang.classfile.*; +import java.lang.classfile.attribute.*; import java.lang.classfile.components.ClassRemapper; import java.lang.classfile.constantpool.Utf8Entry; import java.lang.classfile.instruction.ConstantInstruction.LoadConstantInstruction; -import java.lang.classfile.instruction.ExceptionCatch; -import java.lang.classfile.instruction.FieldInstruction; -import java.lang.classfile.instruction.InvokeDynamicInstruction; -import java.lang.classfile.instruction.InvokeInstruction; -import java.lang.classfile.instruction.LocalVariable; -import java.lang.classfile.instruction.LocalVariableType; -import java.lang.classfile.instruction.NewMultiArrayInstruction; -import java.lang.classfile.instruction.NewObjectInstruction; -import java.lang.classfile.instruction.NewReferenceArrayInstruction; -import java.lang.classfile.instruction.TypeCheckInstruction; - -import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDesc; -import java.lang.constant.DirectMethodHandleDesc; -import java.lang.constant.DynamicCallSiteDesc; -import java.lang.constant.DynamicConstantDesc; -import java.lang.constant.MethodHandleDesc; -import java.lang.constant.MethodTypeDesc; +import java.lang.classfile.instruction.*; +import java.lang.constant.*; import java.util.List; import java.util.function.Function; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index aa9603b150855..47908b99f447c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -24,13 +24,6 @@ */ package jdk.internal.classfile.impl; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Consumer; - import java.lang.classfile.*; import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; @@ -38,6 +31,12 @@ import java.lang.classfile.attribute.StackMapTableAttribute; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.instruction.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; import static jdk.internal.classfile.impl.RawBytecodeHelper.*; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java index 9c2554c054c40..7b7d04a8f1d14 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java @@ -34,7 +34,6 @@ import java.lang.classfile.instruction.LocalVariable; import java.lang.classfile.instruction.LocalVariableType; import java.lang.classfile.instruction.StoreInstruction; - import java.util.Arrays; public final class CodeLocalsShifterImpl implements CodeLocalsShifter { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java index e60a906e189fc..af0a59978d7c4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java @@ -28,16 +28,7 @@ import java.lang.classfile.CodeElement; import java.lang.classfile.Label; import java.lang.classfile.components.CodeRelabeler; -import java.lang.classfile.instruction.BranchInstruction; -import java.lang.classfile.instruction.CharacterRange; -import java.lang.classfile.instruction.ExceptionCatch; -import java.lang.classfile.instruction.LabelTarget; -import java.lang.classfile.instruction.LocalVariable; -import java.lang.classfile.instruction.LocalVariableType; -import java.lang.classfile.instruction.LookupSwitchInstruction; -import java.lang.classfile.instruction.SwitchCase; -import java.lang.classfile.instruction.TableSwitchInstruction; - +import java.lang.classfile.instruction.*; import java.util.function.BiFunction; public record CodeRelabelerImpl(BiFunction mapFunction) implements CodeRelabeler { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java index 9288f9fa2a90b..2746caae0043e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java @@ -30,39 +30,8 @@ import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; import java.lang.classfile.components.CodeStackTracker; -import java.lang.classfile.instruction.ArrayLoadInstruction; -import java.lang.classfile.instruction.ArrayStoreInstruction; -import java.lang.classfile.instruction.BranchInstruction; -import java.lang.classfile.instruction.ConstantInstruction; -import java.lang.classfile.instruction.ConvertInstruction; -import java.lang.classfile.instruction.ExceptionCatch; -import java.lang.classfile.instruction.FieldInstruction; -import java.lang.classfile.instruction.InvokeDynamicInstruction; -import java.lang.classfile.instruction.InvokeInstruction; -import java.lang.classfile.instruction.LabelTarget; -import java.lang.classfile.instruction.LoadInstruction; -import java.lang.classfile.instruction.LookupSwitchInstruction; -import java.lang.classfile.instruction.MonitorInstruction; -import java.lang.classfile.instruction.NewMultiArrayInstruction; -import java.lang.classfile.instruction.NewObjectInstruction; -import java.lang.classfile.instruction.NewPrimitiveArrayInstruction; -import java.lang.classfile.instruction.NewReferenceArrayInstruction; -import java.lang.classfile.instruction.NopInstruction; -import java.lang.classfile.instruction.OperatorInstruction; -import java.lang.classfile.instruction.ReturnInstruction; -import java.lang.classfile.instruction.StackInstruction; -import java.lang.classfile.instruction.StoreInstruction; -import java.lang.classfile.instruction.TableSwitchInstruction; -import java.lang.classfile.instruction.ThrowInstruction; -import java.lang.classfile.instruction.TypeCheckInstruction; - -import java.util.AbstractCollection; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Optional; +import java.lang.classfile.instruction.*; +import java.util.*; import java.util.function.Consumer; public final class CodeStackTrackerImpl implements CodeStackTracker { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 5f02ae708ea7b..6dc6251163989 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding 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 @@ -25,28 +26,16 @@ package jdk.internal.classfile.impl; -import java.lang.constant.ClassDesc; +import java.lang.classfile.*; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.Utf8Entry; import java.lang.constant.ConstantDescs; -import java.lang.constant.MethodTypeDesc; -import java.lang.reflect.AccessFlag; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.Consumer; -import java.lang.classfile.ClassBuilder; -import java.lang.classfile.ClassElement; -import java.lang.classfile.ClassModel; -import java.lang.classfile.ClassFile; -import java.lang.classfile.CustomAttribute; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.FieldBuilder; -import java.lang.classfile.FieldModel; -import java.lang.classfile.FieldTransform; -import java.lang.classfile.MethodBuilder; -import java.lang.classfile.MethodModel; -import java.lang.classfile.MethodTransform; -import java.lang.classfile.constantpool.Utf8Entry; +import static java.util.Objects.requireNonNull; public final class DirectClassBuilder extends AbstractDirectBuilder @@ -54,9 +43,13 @@ public final class DirectClassBuilder /** The value of default class access flags */ static final int DEFAULT_CLASS_FLAGS = ClassFile.ACC_PUBLIC; + static final Util.Writable[] EMPTY_WRITABLE_ARRAY = {}; + static final ClassEntry[] EMPTY_CLASS_ENTRY_ARRAY = {}; final ClassEntry thisClassEntry; - private final List fields = new ArrayList<>(); - private final List methods = new ArrayList<>(); + private Util.Writable[] fields = EMPTY_WRITABLE_ARRAY; + private Util.Writable[] methods = EMPTY_WRITABLE_ARRAY; + private int fieldsCount = 0; + private int methodsCount = 0; private ClassEntry superclassEntry; private List interfaceEntries; private int majorVersion; @@ -81,7 +74,7 @@ public ClassBuilder with(ClassElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute) element); + writeAttribute((CustomAttribute) requireNonNull(element)); } return this; } @@ -137,12 +130,20 @@ public ClassBuilder transformMethod(MethodModel method, MethodTransform transfor // internal / for use by elements ClassBuilder withField(Util.Writable field) { - fields.add(field); + if (fieldsCount >= fields.length) { + int newCapacity = fieldsCount + 8; + this.fields = Arrays.copyOf(fields, newCapacity); + } + fields[fieldsCount++] = field; return this; } ClassBuilder withMethod(Util.Writable method) { - methods.add(method); + if (methodsCount >= methods.length) { + int newCapacity = methodsCount + 8; + this.methods = Arrays.copyOf(methods, newCapacity); + } + methods[methodsCount++] = method; return this; } @@ -184,9 +185,7 @@ public byte[] build() { else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisClassEntry.asInternalName())) superclass = constantPool.classEntry(ConstantDescs.CD_Object); int interfaceEntriesSize = interfaceEntries.size(); - List ies = new ArrayList<>(interfaceEntriesSize); - for (int i = 0; i < interfaceEntriesSize; i++) - ies.add(AbstractPoolEntry.maybeClone(constantPool, interfaceEntries.get(i))); + ClassEntry[] ies = interfaceEntriesSize == 0 ? EMPTY_CLASS_ENTRY_ARRAY : buildInterfaceEnties(interfaceEntriesSize); // We maintain two writers, and then we join them at the end int size = sizeHint == 0 ? 256 : sizeHint; @@ -195,8 +194,8 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC // The tail consists of fields and methods, and attributes // This should trigger all the CP/BSM mutation - Util.writeList(tail, fields); - Util.writeList(tail, methods); + Util.writeList(tail, fields, fieldsCount); + Util.writeList(tail, methods, methodsCount); int attributesOffset = tail.size(); attributes.writeTo(tail); @@ -207,16 +206,23 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC } // Now we can make the head - head.writeLong((((long) ClassFile.MAGIC_NUMBER) << 32) - | ((minorVersion & 0xFFFFL) << 16) - | (majorVersion & 0xFFFFL)); + head.writeInt(ClassFile.MAGIC_NUMBER); + head.writeU2U2(minorVersion, majorVersion); constantPool.writeTo(head); - head.writeU2(flags); - head.writeIndex(thisClassEntry); - head.writeIndexOrZero(superclass); - Util.writeListIndices(head, ies); + head.writeU2U2U2(flags, head.cpIndex(thisClassEntry), head.cpIndexOrZero(superclass)); + head.writeU2(interfaceEntriesSize); + for (int i = 0; i < interfaceEntriesSize; i++) { + head.writeIndex(ies[i]); + } // Join head and tail into an exact-size buffer return BufWriterImpl.join(head, tail); } + + private ClassEntry[] buildInterfaceEnties(int interfaceEntriesSize) { + var ies = new ClassEntry[interfaceEntriesSize]; + for (int i = 0; i < interfaceEntriesSize; i++) + ies[i] = AbstractPoolEntry.maybeClone(constantPool, interfaceEntries.get(i)); + return ies; + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index ee312a97dad80..7d554a35974a2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -25,55 +25,43 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.Attribute; -import java.lang.classfile.Attributes; -import java.lang.classfile.ClassFile; -import java.lang.classfile.CodeBuilder; -import java.lang.classfile.CodeElement; -import java.lang.classfile.CodeModel; -import java.lang.classfile.CustomAttribute; -import java.lang.classfile.Label; -import java.lang.classfile.Opcode; -import java.lang.classfile.TypeKind; +import java.lang.classfile.*; import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.attribute.LineNumberTableAttribute; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.constantpool.DoubleEntry; -import java.lang.classfile.constantpool.FieldRefEntry; -import java.lang.classfile.constantpool.InterfaceMethodRefEntry; -import java.lang.classfile.constantpool.InvokeDynamicEntry; -import java.lang.classfile.constantpool.LoadableConstantEntry; -import java.lang.classfile.constantpool.LongEntry; -import java.lang.classfile.constantpool.MemberRefEntry; -import java.lang.classfile.constantpool.MethodRefEntry; +import java.lang.classfile.constantpool.*; import java.lang.classfile.instruction.CharacterRange; import java.lang.classfile.instruction.ExceptionCatch; import java.lang.classfile.instruction.LocalVariable; import java.lang.classfile.instruction.LocalVariableType; import java.lang.classfile.instruction.SwitchCase; -import java.lang.constant.ConstantDesc; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.util.*; import java.util.function.Consumer; import java.util.function.Function; -import static java.lang.classfile.Opcode.*; - +import static java.util.Objects.requireNonNull; import static jdk.internal.classfile.impl.BytecodeHelpers.*; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; public final class DirectCodeBuilder extends AbstractDirectBuilder implements TerminalCodeBuilder { - private final List characterRanges = new ArrayList<>(); + private static final CharacterRange[] EMPTY_CHARACTER_RANGE = {}; + private static final DeferredLabel[] EMPTY_LABEL_ARRAY = {}; + private static final LocalVariable[] EMPTY_LOCAL_VARIABLE_ARRAY = {}; + private static final LocalVariableType[] EMPTY_LOCAL_VARIABLE_TYPE_ARRAY = {}; + private static final AbstractPseudoInstruction.ExceptionCatchImpl[] EMPTY_HANDLER_ARRAY = {}; + private static final DeferredLabel[] EMPTY_DEFERRED_LABEL_ARRAY = {}; + final List handlers = new ArrayList<>(); - private final List localVariables = new ArrayList<>(); - private final List localVariableTypes = new ArrayList<>(); - private final boolean transformFwdJumps, transformBackJumps; + private CharacterRange[] characterRanges = EMPTY_CHARACTER_RANGE; + private LocalVariable[] localVariables = EMPTY_LOCAL_VARIABLE_ARRAY; + private LocalVariableType[] localVariableTypes = EMPTY_LOCAL_VARIABLE_TYPE_ARRAY; + private int characterRangesCount = 0; + private int localVariablesCount = 0; + private int localVariableTypesCount = 0; + private final boolean transformDeferredJumps, transformKnownJumps; private final Label startLabel, endLabel; final MethodInfo methodInfo; final BufWriterImpl bytecodesBufWriter; @@ -83,7 +71,8 @@ public final class DirectCodeBuilder private DedupLineNumberTableAttribute lineNumberWriter; private int topLocal; - List deferredLabels; + private DeferredLabel[] deferredLabels = EMPTY_DEFERRED_LABEL_ARRAY; + private int deferredLabelsCount = 0; /* Locals management lazily computed maxLocal = -1 @@ -117,12 +106,12 @@ private DirectCodeBuilder(MethodInfo methodInfo, SplitConstantPool constantPool, ClassFileImpl context, CodeModel original, - boolean transformFwdJumps) { + boolean transformDeferredJumps) { super(constantPool, context); setOriginal(original); this.methodInfo = methodInfo; - this.transformFwdJumps = transformFwdJumps; - this.transformBackJumps = context.fixShortJumps(); + this.transformDeferredJumps = transformDeferredJumps; + this.transformKnownJumps = context.fixShortJumps(); bytecodesBufWriter = (original instanceof CodeImpl cai) ? new BufWriterImpl(constantPool, context, cai.codeLength()) : new BufWriterImpl(constantPool, context); this.startLabel = new LabelImpl(this, 0); @@ -135,7 +124,7 @@ public CodeBuilder with(CodeElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute) element); + writeAttribute((CustomAttribute) requireNonNull(element)); } return this; } @@ -208,9 +197,7 @@ private void writeExceptionHandlers(BufWriterImpl buf, int pos) { throw new IllegalArgumentException("Unbound label in exception handler"); } } else { - buf.writeU2(startPc); - buf.writeU2(endPc); - buf.writeU2(handlerPc); + buf.writeU2U2U2(startPc, endPc, handlerPc); buf.writeIndexOrZero(h.catchTypeEntry()); handlersSize++; } @@ -227,15 +214,16 @@ private void buildContent() { processDeferredLabels(); if (context.passDebugElements()) { - if (!characterRanges.isEmpty()) { + if (characterRangesCount > 0) { Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.characterRangeTable()) { @Override public void writeBody(BufWriterImpl b) { int pos = b.size(); - int crSize = characterRanges.size(); + int crSize = characterRangesCount; b.writeU2(crSize); - for (CharacterRange cr : characterRanges) { + for (int i = 0; i < characterRangesCount; i++) { + CharacterRange cr = characterRanges[i]; var start = labelToBci(cr.startScope()); var end = labelToBci(cr.endScope()); if (start == -1 || end == -1) { @@ -245,28 +233,27 @@ public void writeBody(BufWriterImpl b) { throw new IllegalArgumentException("Unbound label in character range"); } } else { - b.writeU2(start); - b.writeU2(end - 1); - b.writeInt(cr.characterRangeStart()); - b.writeInt(cr.characterRangeEnd()); + b.writeU2U2(start, end - 1); + b.writeIntInt(cr.characterRangeStart(), cr.characterRangeEnd()); b.writeU2(cr.flags()); } } - if (crSize < characterRanges.size()) + if (crSize < characterRangesCount) b.patchU2(pos, crSize); } }; attributes.withAttribute(a); } - if (!localVariables.isEmpty()) { + if (localVariablesCount > 0) { Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTable()) { @Override public void writeBody(BufWriterImpl b) { int pos = b.size(); - int lvSize = localVariables.size(); + int lvSize = localVariablesCount; b.writeU2(lvSize); - for (LocalVariable l : localVariables) { + for (int i = 0; i < localVariablesCount; i++) { + LocalVariable l = localVariables[i]; if (!Util.writeLocalVariable(b, l)) { if (context.dropDeadLabels()) { lvSize--; @@ -275,21 +262,22 @@ public void writeBody(BufWriterImpl b) { } } } - if (lvSize < localVariables.size()) + if (lvSize < localVariablesCount) b.patchU2(pos, lvSize); } }; attributes.withAttribute(a); } - if (!localVariableTypes.isEmpty()) { + if (localVariableTypesCount > 0) { Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTypeTable()) { @Override public void writeBody(BufWriterImpl b) { int pos = b.size(); - int lvtSize = localVariableTypes.size(); - b.writeU2(localVariableTypes.size()); - for (LocalVariableType l : localVariableTypes) { + int lvtSize = localVariableTypesCount; + b.writeU2(lvtSize); + for (int i = 0; i < localVariableTypesCount; i++) { + LocalVariableType l = localVariableTypes[i]; if (!Util.writeLocalVariable(b, l)) { if (context.dropDeadLabels()) { lvtSize--; @@ -298,7 +286,7 @@ public void writeBody(BufWriterImpl b) { } } } - if (lvtSize < localVariableTypes.size()) + if (lvtSize < localVariableTypesCount) b.patchU2(pos, lvtSize); } }; @@ -315,22 +303,20 @@ public void writeBody(BufWriterImpl b) { private void writeCounters(boolean codeMatch, BufWriterImpl buf) { if (codeMatch) { var originalAttribute = (CodeImpl) original; - buf.writeU2(originalAttribute.maxStack()); - buf.writeU2(originalAttribute.maxLocals()); + buf.writeU2U2(originalAttribute.maxStack(), originalAttribute.maxLocals()); } else { StackCounter cntr = StackCounter.of(DirectCodeBuilder.this, buf); - buf.writeU2(cntr.maxStack()); - buf.writeU2(cntr.maxLocals()); + buf.writeU2U2(cntr.maxStack(), cntr.maxLocals()); } } private void generateStackMaps(BufWriterImpl buf) throws IllegalArgumentException { //new instance of generator immediately calculates maxStack, maxLocals, all frames, // patches dead bytecode blocks and removes them from exception table - StackMapGenerator gen = StackMapGenerator.of(DirectCodeBuilder.this, buf); - attributes.withAttribute(gen.stackMapTableAttribute()); - buf.writeU2(gen.maxStack()); - buf.writeU2(gen.maxLocals()); + var dcb = DirectCodeBuilder.this; + StackMapGenerator gen = StackMapGenerator.of(dcb, buf); + dcb.attributes.withAttribute(gen.stackMapTableAttribute()); + buf.writeU2U2(gen.maxStack(), gen.maxLocals()); } private void tryGenerateStackMaps(boolean codeMatch, BufWriterImpl buf) { @@ -352,40 +338,37 @@ private void tryGenerateStackMaps(boolean codeMatch, BufWriterImpl buf) { @Override public void writeBody(BufWriterImpl buf) { - buf.setLabelContext(DirectCodeBuilder.this); + DirectCodeBuilder dcb = DirectCodeBuilder.this; + buf.setLabelContext(dcb); int codeLength = curPc(); if (codeLength == 0 || codeLength >= 65536) { throw new IllegalArgumentException(String.format( "Code length %d is outside the allowed range in %s%s", codeLength, - methodInfo.methodName().stringValue(), - methodInfo.methodTypeSymbol().displayDescriptor())); + dcb.methodInfo.methodName().stringValue(), + dcb.methodInfo.methodTypeSymbol().displayDescriptor())); } - if (codeAndExceptionsMatch(codeLength)) { - if (context.stackMapsWhenRequired()) { - attributes.withAttribute(original.findAttribute(Attributes.stackMapTable()).orElse(null)); - writeCounters(true, buf); - } else if (context.generateStackMaps()) { - generateStackMaps(buf); - } else if (context.dropStackMaps()) { + boolean codeMatch = dcb.original != null && codeAndExceptionsMatch(codeLength); + var context = dcb.context; + if (context.stackMapsWhenRequired()) { + if (codeMatch) { + dcb.attributes.withAttribute(dcb.original.findAttribute(Attributes.stackMapTable()).orElse(null)); writeCounters(true, buf); - } - } else { - if (context.stackMapsWhenRequired()) { + } else { tryGenerateStackMaps(false, buf); - } else if (context.generateStackMaps()) { - generateStackMaps(buf); - } else if (context.dropStackMaps()) { - writeCounters(false, buf); } + } else if (context.generateStackMaps()) { + generateStackMaps(buf); + } else if (context.dropStackMaps()) { + writeCounters(codeMatch, buf); } buf.writeInt(codeLength); - buf.writeBytes(bytecodesBufWriter); - writeExceptionHandlers(buf); - attributes.writeTo(buf); + buf.writeBytes(dcb.bytecodesBufWriter); + dcb.writeExceptionHandlers(buf); + dcb.attributes.writeTo(buf); buf.setLabelContext(null); } }; @@ -405,8 +388,7 @@ public DedupLineNumberTableAttribute(ConstantPoolBuilder constantPool, ClassFile private void push() { //subsequent identical line numbers are skipped if (lastPc >= 0 && lastLine != writtenLine) { - buf.writeU2(lastPc); - buf.writeU2(lastLine); + buf.writeU2U2(lastPc, lastLine); writtenLine = lastLine; } } @@ -456,32 +438,16 @@ private boolean codeAndExceptionsMatch(int codeLength) { private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { } - private void writeLabelOffset(int nBytes, int instructionPc, Label label) { - int targetBci = labelToBci(label); - if (targetBci == -1) { - int pc = bytecodesBufWriter.skip(nBytes); - if (deferredLabels == null) - deferredLabels = new ArrayList<>(); - deferredLabels.add(new DeferredLabel(pc, nBytes, instructionPc, label)); - } - else { - int branchOffset = targetBci - instructionPc; - if (nBytes == 2 && (short)branchOffset != branchOffset) throw new LabelOverflowException(); - bytecodesBufWriter.writeIntBytes(nBytes, branchOffset); - } - } - private void processDeferredLabels() { - if (deferredLabels != null) { - for (DeferredLabel dl : deferredLabels) { - int branchOffset = labelToBci(dl.label) - dl.instructionPc; - if (dl.size == 2) { - if ((short)branchOffset != branchOffset) throw new LabelOverflowException(); - bytecodesBufWriter.patchU2(dl.labelPc, branchOffset); - } else { - assert dl.size == 4; - bytecodesBufWriter.patchInt(dl.labelPc, branchOffset); - } + for (int i = 0; i < deferredLabelsCount; i++) { + DeferredLabel dl = deferredLabels[i]; + int branchOffset = labelToBci(dl.label) - dl.instructionPc; + if (dl.size == 2) { + if ((short) branchOffset != branchOffset) throw new LabelOverflowException(); + bytecodesBufWriter.patchU2(dl.labelPc, branchOffset); + } else { + assert dl.size == 4; + bytecodesBufWriter.patchInt(dl.labelPc, branchOffset); } } } @@ -489,72 +455,140 @@ private void processDeferredLabels() { // Instruction writing public void writeBytecode(Opcode opcode) { + assert !opcode.isWide(); + bytecodesBufWriter.writeU1(opcode.bytecode()); + } + + // Instruction version, refer to opcode + public void writeLocalVar(Opcode opcode, int slot) { if (opcode.isWide()) { - bytecodesBufWriter.writeU2(opcode.bytecode()); + bytecodesBufWriter.writeU2U2(opcode.bytecode(), slot); } else { - bytecodesBufWriter.writeU1(opcode.bytecode()); + bytecodesBufWriter.writeU1U1(opcode.bytecode(), slot); } } - public void writeLocalVar(Opcode opcode, int localVar) { - writeBytecode(opcode); - switch (opcode.sizeIfFixed()) { - case 1 -> { } - case 2 -> bytecodesBufWriter.writeU1(localVar); - case 4 -> bytecodesBufWriter.writeU2(localVar); - default -> throw new IllegalArgumentException("Unexpected instruction size: " + opcode); + // Shortcut version, refer to and validate slot + private void writeLocalVar(int bytecode, int slot) { + // TODO validation like (slot & 0xFFFF) == slot + if (slot < 256) { + bytecodesBufWriter.writeU1U1(bytecode, slot); + } else { + bytecodesBufWriter.writeU1U1U2(WIDE, bytecode, slot); } } public void writeIncrement(boolean wide, int slot, int val) { if (wide) { - bytecodesBufWriter.writeU1(RawBytecodeHelper.WIDE); - } - bytecodesBufWriter.writeU1(RawBytecodeHelper.IINC); - if (wide) { - bytecodesBufWriter.writeU2(slot); - bytecodesBufWriter.writeU2(val); + bytecodesBufWriter.writeU2U2U2((WIDE << 8) | IINC, slot, val); } else { - bytecodesBufWriter.writeU1(slot); - bytecodesBufWriter.writeU1(val); + bytecodesBufWriter.writeU1U1U1(IINC, slot, val); } } public void writeBranch(Opcode op, Label target) { + if (op.sizeIfFixed() == 3) { + writeShortJump(op.bytecode(), target); + } else { + writeLongJump(op.bytecode(), target); + } + } + + private void writeLongLabelOffset(int instructionPc, Label label) { + int targetBci = labelToBci(label); + + // algebraic union of jump | (instructionPc, target), distinguished by null == target. + int jumpOrInstructionPc; + Label nullOrTarget; + if (targetBci == -1) { + jumpOrInstructionPc = instructionPc; + nullOrTarget = label; + } else { + jumpOrInstructionPc = targetBci - instructionPc; + nullOrTarget = null; + } + + writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget); + } + + private void writeShortJump(int bytecode, Label target) { int instructionPc = curPc(); int targetBci = labelToBci(target); + + // algebraic union of jump | (instructionPc, target), distinguished by null == target. + int jumpOrInstructionPc; + Label nullOrTarget; + if (targetBci == -1) { + jumpOrInstructionPc = instructionPc; + nullOrTarget = target; + } else { + jumpOrInstructionPc = targetBci - instructionPc; + nullOrTarget = null; + } + //transform short-opcode forward jumps if enforced, and backward jumps if enabled and overflowing - if (op.sizeIfFixed() == 3 && (targetBci == -1 - ? transformFwdJumps - : (transformBackJumps - && targetBci - instructionPc < Short.MIN_VALUE))) { - if (op == GOTO) { - writeBytecode(GOTO_W); - writeLabelOffset(4, instructionPc, target); - } else if (op == JSR) { - writeBytecode(JSR_W); - writeLabelOffset(4, instructionPc, target); + if (transformDeferredJumps || transformKnownJumps && nullOrTarget == null && jumpOrInstructionPc < Short.MIN_VALUE) { + fixShortJump(bytecode, jumpOrInstructionPc, nullOrTarget); + } else { + bytecodesBufWriter.writeU1(bytecode); + writeParsedShortLabel(jumpOrInstructionPc, nullOrTarget); + } + } + + private void writeLongJump(int bytecode, Label target) { + int instructionPc = curPc(); + bytecodesBufWriter.writeU1(bytecode); + writeLongLabelOffset(instructionPc, target); + } + + private void fixShortJump(int bytecode, int jumpOrInstructionPc, Label nullOrTarget) { + if (bytecode == GOTO) { + bytecodesBufWriter.writeU1(GOTO_W); + writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget); + } else if (bytecode == JSR) { + bytecodesBufWriter.writeU1(JSR_W); + writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget); + } else { + bytecodesBufWriter.writeU1U2( + BytecodeHelpers.reverseBranchOpcode(bytecode), // u1 + 8); // u1 + s2 + u1 + s4 // s2 + bytecodesBufWriter.writeU1(GOTO_W); // u1 + if (nullOrTarget == null) { + jumpOrInstructionPc -= 3; // jump -= 3; } else { - writeBytecode(BytecodeHelpers.reverseBranchOpcode(op)); - Label bypassJump = newLabel(); - writeLabelOffset(2, instructionPc, bypassJump); - writeBytecode(GOTO_W); - writeLabelOffset(4, instructionPc + 3, target); - labelBinding(bypassJump); + jumpOrInstructionPc += 3; // instructionPc += 3; } + writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget); // s4 + } + } + + private void writeParsedShortLabel(int jumpOrInstructionPc, Label nullOrTarget) { + if (nullOrTarget == null) { + if ((short) jumpOrInstructionPc != jumpOrInstructionPc) + throw new LabelOverflowException(); + bytecodesBufWriter.writeU2(jumpOrInstructionPc); + } else { + int pc = bytecodesBufWriter.skip(2); + addLabel(new DeferredLabel(pc, 2, jumpOrInstructionPc, nullOrTarget)); + } + } + + private void writeParsedLongLabel(int jumpOrInstructionPc, Label nullOrTarget) { + if (nullOrTarget == null) { + bytecodesBufWriter.writeInt(jumpOrInstructionPc); } else { - writeBytecode(op); - writeLabelOffset(op.sizeIfFixed() == 3 ? 2 : 4, instructionPc, target); + int pc = bytecodesBufWriter.skip(4); + addLabel(new DeferredLabel(pc, 4, jumpOrInstructionPc, nullOrTarget)); } } public void writeLookupSwitch(Label defaultTarget, List cases) { int instructionPc = curPc(); - writeBytecode(LOOKUPSWITCH); + bytecodesBufWriter.writeU1(LOOKUPSWITCH); int pad = 4 - (curPc() % 4); if (pad != 4) bytecodesBufWriter.skip(pad); // padding content can be anything - writeLabelOffset(4, instructionPc, defaultTarget); + writeLongLabelOffset(instructionPc, defaultTarget); bytecodesBufWriter.writeInt(cases.size()); cases = new ArrayList<>(cases); cases.sort(new Comparator<>() { @@ -565,103 +599,97 @@ public int compare(SwitchCase c1, SwitchCase c2) { }); for (var c : cases) { bytecodesBufWriter.writeInt(c.caseValue()); - writeLabelOffset(4, instructionPc, c.target()); + var target = c.target(); + writeLongLabelOffset(instructionPc, target); } } public void writeTableSwitch(int low, int high, Label defaultTarget, List cases) { int instructionPc = curPc(); - writeBytecode(TABLESWITCH); + bytecodesBufWriter.writeU1(TABLESWITCH); int pad = 4 - (curPc() % 4); if (pad != 4) bytecodesBufWriter.skip(pad); // padding content can be anything - writeLabelOffset(4, instructionPc, defaultTarget); - bytecodesBufWriter.writeInt(low); - bytecodesBufWriter.writeInt(high); + writeLongLabelOffset(instructionPc, defaultTarget); + bytecodesBufWriter.writeIntInt(low, high); var caseMap = new HashMap(cases.size()); for (var c : cases) { caseMap.put(c.caseValue(), c.target()); } for (long l = low; l<=high; l++) { - writeLabelOffset(4, instructionPc, caseMap.getOrDefault((int)l, defaultTarget)); + var target = caseMap.getOrDefault((int)l, defaultTarget); + writeLongLabelOffset(instructionPc, target); } } public void writeFieldAccess(Opcode opcode, FieldRefEntry ref) { - writeBytecode(opcode); - bytecodesBufWriter.writeIndex(ref); + bytecodesBufWriter.writeIndex(opcode.bytecode(), ref); } public void writeInvokeNormal(Opcode opcode, MemberRefEntry ref) { - writeBytecode(opcode); - bytecodesBufWriter.writeIndex(ref); + bytecodesBufWriter.writeIndex(opcode.bytecode(), ref); } public void writeInvokeInterface(Opcode opcode, InterfaceMethodRefEntry ref, int count) { - writeBytecode(opcode); - bytecodesBufWriter.writeIndex(ref); - bytecodesBufWriter.writeU1(count); - bytecodesBufWriter.writeU1(0); + bytecodesBufWriter.writeIndex(opcode.bytecode(), ref); + bytecodesBufWriter.writeU1U1(count, 0); } public void writeInvokeDynamic(InvokeDynamicEntry ref) { - writeBytecode(INVOKEDYNAMIC); - bytecodesBufWriter.writeIndex(ref); - bytecodesBufWriter.writeU2(0); + bytecodesBufWriter.writeU1U2U2(INVOKEDYNAMIC, bytecodesBufWriter.cpIndex(ref), 0); } public void writeNewObject(ClassEntry type) { - writeBytecode(NEW); - bytecodesBufWriter.writeIndex(type); + bytecodesBufWriter.writeIndex(NEW, type); } public void writeNewPrimitiveArray(int newArrayCode) { - writeBytecode(NEWARRAY); - bytecodesBufWriter.writeU1(newArrayCode); + bytecodesBufWriter.writeU1U1(NEWARRAY, newArrayCode); } public void writeNewReferenceArray(ClassEntry type) { - writeBytecode(ANEWARRAY); - bytecodesBufWriter.writeIndex(type); + bytecodesBufWriter.writeIndex(ANEWARRAY, type); } public void writeNewMultidimensionalArray(int dimensions, ClassEntry type) { - writeBytecode(MULTIANEWARRAY); - bytecodesBufWriter.writeIndex(type); + bytecodesBufWriter.writeIndex(MULTIANEWARRAY, type); bytecodesBufWriter.writeU1(dimensions); } public void writeTypeCheck(Opcode opcode, ClassEntry type) { - writeBytecode(opcode); - bytecodesBufWriter.writeIndex(type); + bytecodesBufWriter.writeIndex(opcode.bytecode(), type); } public void writeArgumentConstant(Opcode opcode, int value) { - writeBytecode(opcode); if (opcode.sizeIfFixed() == 3) { - bytecodesBufWriter.writeU2(value); + bytecodesBufWriter.writeU1U2(opcode.bytecode(), value); } else { - bytecodesBufWriter.writeU1(value); + bytecodesBufWriter.writeU1U1(opcode.bytecode(), value); } } - public void writeLoadConstant(Opcode opcode, LoadableConstantEntry value) { - // Make sure Long and Double have LDC2_W and - // rewrite to _W if index is > 256 - int index = AbstractPoolEntry.maybeClone(constantPool, value).index(); - Opcode op = opcode; - if (value instanceof LongEntry || value instanceof DoubleEntry) { - op = LDC2_W; - } else if (index >= 256) - op = LDC_W; + // value may not be writable to this constant pool + public void writeAdaptLoadConstant(Opcode opcode, LoadableConstantEntry value) { + var pe = AbstractPoolEntry.maybeClone(constantPool, value); + int index = pe.index(); + if (pe != value && opcode != Opcode.LDC2_W) { + // rewrite ldc/ldc_w if external entry; ldc2_w never needs rewrites + opcode = index <= 0xFF ? Opcode.LDC : Opcode.LDC_W; + } - writeBytecode(op); - if (op.sizeIfFixed() == 3) { - bytecodesBufWriter.writeU2(index); + writeDirectLoadConstant(opcode, pe); + } + + // the loadable entry is writable to this constant pool + public void writeDirectLoadConstant(Opcode opcode, LoadableConstantEntry pe) { + assert !opcode.isWide() && canWriteDirect(pe.constantPool()); + int index = pe.index(); + if (opcode.sizeIfFixed() == 3) { + bytecodesBufWriter.writeU1U2(opcode.bytecode(), index); } else { - bytecodesBufWriter.writeU1(index); + bytecodesBufWriter.writeU1U1(opcode.bytecode(), index); } } @@ -677,7 +705,11 @@ public int labelToBci(Label label) { if (context == this) { return lab.getBCI(); } - else if (context == mruParent) { + return labelToBci(context, lab); + } + + private int labelToBci(LabelContext context, LabelImpl lab) { + if (context == mruParent) { return mruParentTable[lab.getBCI()] - 1; } else if (context instanceof CodeAttribute parent) { @@ -717,14 +749,18 @@ public void setLabelTarget(Label label) { @Override public void setLabelTarget(Label label, int bci) { LabelImpl lab = (LabelImpl) label; - LabelContext context = lab.labelContext(); - - if (context == this) { + if (lab.labelContext() == this) { if (lab.getBCI() != -1) throw new IllegalArgumentException("Setting label target for already-set label"); lab.setBCI(bci); + } else { + setLabelTarget(lab, bci); } - else if (context == mruParent) { + } + + private void setLabelTarget(LabelImpl lab, int bci) { + LabelContext context = lab.labelContext(); + if (context == mruParent) { mruParentTable[lab.getBCI()] = bci + 1; } else if (context instanceof CodeAttribute parent) { @@ -739,7 +775,7 @@ public int[] apply(CodeAttribute x) { mruParent = parent; mruParentTable = table; - mruParentTable[lab.getBCI()] = bci + 1; + table[lab.getBCI()] = bci + 1; } else if (context instanceof BufferedCodeBuilder) { // Hijack the label @@ -751,7 +787,19 @@ else if (context instanceof BufferedCodeBuilder) { } public void addCharacterRange(CharacterRange element) { - characterRanges.add(element); + if (characterRangesCount >= characterRanges.length) { + int newCapacity = characterRangesCount + 8; + this.characterRanges = Arrays.copyOf(characterRanges, newCapacity); + } + characterRanges[characterRangesCount++] = element; + } + + public void addLabel(DeferredLabel label) { + if (deferredLabelsCount >= deferredLabels.length) { + int newCapacity = deferredLabelsCount + 8; + this.deferredLabels = Arrays.copyOf(deferredLabels, newCapacity); + } + deferredLabels[deferredLabelsCount++] = label; } public void addHandler(ExceptionCatch element) { @@ -763,11 +811,19 @@ public void addHandler(ExceptionCatch element) { } public void addLocalVariable(LocalVariable element) { - localVariables.add(element); + if (localVariablesCount >= localVariables.length) { + int newCapacity = localVariablesCount + 8; + this.localVariables = Arrays.copyOf(localVariables, newCapacity); + } + localVariables[localVariablesCount++] = element; } public void addLocalVariableType(LocalVariableType element) { - localVariableTypes.add(element); + if (localVariableTypesCount >= localVariableTypes.length) { + int newCapacity = localVariableTypesCount + 8; + this.localVariableTypes = Arrays.copyOf(localVariableTypes, newCapacity); + } + localVariableTypes[localVariableTypesCount++] = element; } @Override @@ -788,28 +844,54 @@ public LabelOverflowException() { // Fast overrides to avoid intermediate instructions // These are helpful for direct class building + @Override + public CodeBuilder return_() { + bytecodesBufWriter.writeU1(RETURN); + return this; + } + @Override public CodeBuilder return_(TypeKind tk) { - writeBytecode(BytecodeHelpers.returnOpcode(tk)); + bytecodesBufWriter.writeU1(returnBytecode(tk)); return this; } @Override public CodeBuilder storeLocal(TypeKind tk, int slot) { - writeLocalVar(BytecodeHelpers.storeOpcode(tk, slot), slot); + return switch (tk) { + case INT, SHORT, BYTE, CHAR, BOOLEAN + -> istore(slot); + case LONG -> lstore(slot); + case DOUBLE -> dstore(slot); + case FLOAT -> fstore(slot); + case REFERENCE -> astore(slot); + case VOID -> throw new IllegalArgumentException("void"); + }; + } + + @Override + public CodeBuilder labelBinding(Label label) { + setLabelTarget(label, curPc()); return this; } @Override public CodeBuilder loadLocal(TypeKind tk, int slot) { - writeLocalVar(BytecodeHelpers.loadOpcode(tk, slot), slot); - return this; + return switch (tk) { + case INT, SHORT, BYTE, CHAR, BOOLEAN + -> iload(slot); + case LONG -> lload(slot); + case DOUBLE -> dload(slot); + case FLOAT -> fload(slot); + case REFERENCE -> aload(slot); + case VOID -> throw new IllegalArgumentException("void"); + }; } @Override public CodeBuilder invoke(Opcode opcode, MemberRefEntry ref) { - if (opcode == INVOKEINTERFACE) { - int slots = Util.parameterSlots(Util.methodTypeSymbol(ref.nameAndType())) + 1; + if (opcode == Opcode.INVOKEINTERFACE) { + int slots = Util.parameterSlots(Util.methodTypeSymbol(ref.type())) + 1; writeInvokeInterface(opcode, (InterfaceMethodRefEntry) ref, slots); } else { writeInvokeNormal(opcode, ref); @@ -817,21 +899,45 @@ public CodeBuilder invoke(Opcode opcode, MemberRefEntry ref) { return this; } + @Override + public CodeBuilder invokespecial(ClassDesc owner, String name, MethodTypeDesc type) { + bytecodesBufWriter.writeIndex(INVOKESPECIAL, constantPool().methodRefEntry(owner, name, type)); + return this; + } + + @Override + public CodeBuilder invokestatic(ClassDesc owner, String name, MethodTypeDesc type) { + bytecodesBufWriter.writeIndex(INVOKESTATIC, constantPool().methodRefEntry(owner, name, type)); + return this; + } + + @Override + public CodeBuilder invokevirtual(ClassDesc owner, String name, MethodTypeDesc type) { + bytecodesBufWriter.writeIndex(INVOKEVIRTUAL, constantPool().methodRefEntry(owner, name, type)); + return this; + } + + @Override + public CodeBuilder getfield(ClassDesc owner, String name, ClassDesc type) { + bytecodesBufWriter.writeIndex(GETFIELD, constantPool().fieldRefEntry(owner, name, type)); + return this; + } + @Override public CodeBuilder fieldAccess(Opcode opcode, FieldRefEntry ref) { - writeFieldAccess(opcode, ref); + bytecodesBufWriter.writeIndex(opcode.bytecode(), ref); return this; } @Override public CodeBuilder arrayLoad(TypeKind tk) { - writeBytecode(BytecodeHelpers.arrayLoadOpcode(tk)); + bytecodesBufWriter.writeU1(BytecodeHelpers.arrayLoadBytecode(tk)); return this; } @Override public CodeBuilder arrayStore(TypeKind tk) { - writeBytecode(BytecodeHelpers.arrayStoreOpcode(tk)); + bytecodesBufWriter.writeU1(BytecodeHelpers.arrayStoreBytecode(tk)); return this; } @@ -843,19 +949,23 @@ public CodeBuilder branch(Opcode op, Label target) { @Override public CodeBuilder nop() { - writeBytecode(NOP); + bytecodesBufWriter.writeU1(NOP); return this; } @Override public CodeBuilder aconst_null() { - writeBytecode(ACONST_NULL); + bytecodesBufWriter.writeU1(ACONST_NULL); return this; } @Override public CodeBuilder aload(int slot) { - writeLocalVar(BytecodeHelpers.aload(slot), slot); + if (slot >= 0 && slot <= 3) { + bytecodesBufWriter.writeU1(ALOAD_0 + slot); + } else { + writeLocalVar(ALOAD, slot); + } return this; } @@ -867,350 +977,496 @@ public CodeBuilder anewarray(ClassEntry entry) { @Override public CodeBuilder arraylength() { - writeBytecode(ARRAYLENGTH); + bytecodesBufWriter.writeU1(ARRAYLENGTH); + return this; + } + + @Override + public CodeBuilder areturn() { + bytecodesBufWriter.writeU1(ARETURN); return this; } @Override public CodeBuilder astore(int slot) { - writeLocalVar(BytecodeHelpers.astore(slot), slot); + if (slot >= 0 && slot <= 3) { + bytecodesBufWriter.writeU1(ASTORE_0 + slot); + } else { + writeLocalVar(ASTORE, slot); + } return this; } @Override public CodeBuilder athrow() { - writeBytecode(ATHROW); + bytecodesBufWriter.writeU1(ATHROW); return this; } @Override public CodeBuilder bipush(int b) { BytecodeHelpers.validateBipush(b); - writeArgumentConstant(BIPUSH, b); + bytecodesBufWriter.writeU1U1(BIPUSH, b); return this; } @Override public CodeBuilder checkcast(ClassEntry type) { - writeTypeCheck(CHECKCAST, type); + bytecodesBufWriter.writeIndex(CHECKCAST, type); return this; } @Override public CodeBuilder d2f() { - writeBytecode(D2F); + bytecodesBufWriter.writeU1(D2F); return this; } @Override public CodeBuilder d2i() { - writeBytecode(D2I); + bytecodesBufWriter.writeU1(D2I); return this; } @Override public CodeBuilder d2l() { - writeBytecode(D2L); + bytecodesBufWriter.writeU1(D2L); return this; } @Override public CodeBuilder dadd() { - writeBytecode(DADD); + bytecodesBufWriter.writeU1(DADD); return this; } @Override public CodeBuilder dcmpg() { - writeBytecode(DCMPG); + bytecodesBufWriter.writeU1(DCMPG); return this; } @Override public CodeBuilder dcmpl() { - writeBytecode(DCMPL); + bytecodesBufWriter.writeU1(DCMPL); return this; } @Override public CodeBuilder dconst_0() { - writeBytecode(DCONST_0); + bytecodesBufWriter.writeU1(DCONST_0); return this; } @Override public CodeBuilder dconst_1() { - writeBytecode(DCONST_1); + bytecodesBufWriter.writeU1(DCONST_1); return this; } @Override public CodeBuilder ddiv() { - writeBytecode(DDIV); + bytecodesBufWriter.writeU1(DDIV); return this; } @Override public CodeBuilder dload(int slot) { - writeLocalVar(BytecodeHelpers.dload(slot), slot); + if (slot >= 0 && slot <= 3) { + bytecodesBufWriter.writeU1(DLOAD_0 + slot); + } else { + writeLocalVar(DLOAD, slot); + } return this; } @Override public CodeBuilder dmul() { - writeBytecode(DMUL); + bytecodesBufWriter.writeU1(DMUL); return this; } @Override public CodeBuilder dneg() { - writeBytecode(DNEG); + bytecodesBufWriter.writeU1(DNEG); return this; } @Override public CodeBuilder drem() { - writeBytecode(DREM); + bytecodesBufWriter.writeU1(DREM); + return this; + } + + @Override + public CodeBuilder dreturn() { + bytecodesBufWriter.writeU1(DRETURN); return this; } @Override public CodeBuilder dstore(int slot) { - writeLocalVar(BytecodeHelpers.dstore(slot), slot); + if (slot >= 0 && slot <= 3) { + bytecodesBufWriter.writeU1(DSTORE_0 + slot); + } else { + writeLocalVar(DSTORE, slot); + } return this; } @Override public CodeBuilder dsub() { - writeBytecode(DSUB); + bytecodesBufWriter.writeU1(DSUB); return this; } @Override public CodeBuilder dup() { - writeBytecode(DUP); + bytecodesBufWriter.writeU1(DUP); return this; } @Override public CodeBuilder dup2() { - writeBytecode(DUP2); + bytecodesBufWriter.writeU1(DUP2); return this; } @Override public CodeBuilder dup2_x1() { - writeBytecode(DUP2_X1); + bytecodesBufWriter.writeU1(DUP2_X1); return this; } @Override public CodeBuilder dup2_x2() { - writeBytecode(DUP2_X2); + bytecodesBufWriter.writeU1(DUP2_X2); return this; } @Override public CodeBuilder dup_x1() { - writeBytecode(DUP_X1); + bytecodesBufWriter.writeU1(DUP_X1); return this; } @Override public CodeBuilder dup_x2() { - writeBytecode(DUP_X2); + bytecodesBufWriter.writeU1(DUP_X2); return this; } @Override public CodeBuilder f2d() { - writeBytecode(F2D); + bytecodesBufWriter.writeU1(F2D); return this; } @Override public CodeBuilder f2i() { - writeBytecode(F2I); + bytecodesBufWriter.writeU1(F2I); return this; } @Override public CodeBuilder f2l() { - writeBytecode(F2L); + bytecodesBufWriter.writeU1(F2L); return this; } @Override public CodeBuilder fadd() { - writeBytecode(FADD); + bytecodesBufWriter.writeU1(FADD); return this; } @Override public CodeBuilder fcmpg() { - writeBytecode(FCMPG); + bytecodesBufWriter.writeU1(FCMPG); return this; } @Override public CodeBuilder fcmpl() { - writeBytecode(FCMPL); + bytecodesBufWriter.writeU1(FCMPL); return this; } @Override public CodeBuilder fconst_0() { - writeBytecode(FCONST_0); + bytecodesBufWriter.writeU1(FCONST_0); return this; } @Override public CodeBuilder fconst_1() { - writeBytecode(FCONST_1); + bytecodesBufWriter.writeU1(FCONST_1); return this; } @Override public CodeBuilder fconst_2() { - writeBytecode(FCONST_2); + bytecodesBufWriter.writeU1(FCONST_2); return this; } @Override public CodeBuilder fdiv() { - writeBytecode(FDIV); + bytecodesBufWriter.writeU1(FDIV); return this; } @Override public CodeBuilder fload(int slot) { - writeLocalVar(BytecodeHelpers.fload(slot), slot); + if (slot >= 0 && slot <= 3) { + bytecodesBufWriter.writeU1(FLOAD_0 + slot); + } else { + writeLocalVar(FLOAD, slot); + } return this; } @Override public CodeBuilder fmul() { - writeBytecode(FMUL); + bytecodesBufWriter.writeU1(FMUL); return this; } @Override public CodeBuilder fneg() { - writeBytecode(FNEG); + bytecodesBufWriter.writeU1(FNEG); return this; } @Override public CodeBuilder frem() { - writeBytecode(FREM); + bytecodesBufWriter.writeU1(FREM); + return this; + } + + @Override + public CodeBuilder freturn() { + bytecodesBufWriter.writeU1(FRETURN); return this; } @Override public CodeBuilder fstore(int slot) { - writeLocalVar(BytecodeHelpers.fstore(slot), slot); + if (slot >= 0 && slot <= 3) { + bytecodesBufWriter.writeU1(FSTORE_0 + slot); + } else { + writeLocalVar(FSTORE, slot); + } return this; } @Override public CodeBuilder fsub() { - writeBytecode(FSUB); + bytecodesBufWriter.writeU1(FSUB); + return this; + } + + @Override + public CodeBuilder getstatic(ClassDesc owner, String name, ClassDesc type) { + bytecodesBufWriter.writeIndex(GETSTATIC, constantPool().fieldRefEntry(owner, name, type)); + return this; + } + + @Override + public CodeBuilder goto_(Label target) { + writeShortJump(GOTO, target); return this; } @Override public CodeBuilder i2b() { - writeBytecode(I2B); + bytecodesBufWriter.writeU1(I2B); return this; } @Override public CodeBuilder i2c() { - writeBytecode(I2C); + bytecodesBufWriter.writeU1(I2C); return this; } @Override public CodeBuilder i2d() { - writeBytecode(I2D); + bytecodesBufWriter.writeU1(I2D); return this; } @Override public CodeBuilder i2f() { - writeBytecode(I2F); + bytecodesBufWriter.writeU1(I2F); return this; } @Override public CodeBuilder i2l() { - writeBytecode(I2L); + bytecodesBufWriter.writeU1(I2L); return this; } @Override public CodeBuilder i2s() { - writeBytecode(I2S); + bytecodesBufWriter.writeU1(I2S); return this; } @Override public CodeBuilder iadd() { - writeBytecode(IADD); + bytecodesBufWriter.writeU1(IADD); return this; } @Override public CodeBuilder iand() { - writeBytecode(IAND); + bytecodesBufWriter.writeU1(IAND); return this; } @Override public CodeBuilder iconst_0() { - writeBytecode(ICONST_0); + bytecodesBufWriter.writeU1(ICONST_0); return this; } @Override public CodeBuilder iconst_1() { - writeBytecode(ICONST_1); + bytecodesBufWriter.writeU1(ICONST_1); return this; } @Override public CodeBuilder iconst_2() { - writeBytecode(ICONST_2); + bytecodesBufWriter.writeU1(ICONST_2); return this; } @Override public CodeBuilder iconst_3() { - writeBytecode(ICONST_3); + bytecodesBufWriter.writeU1(ICONST_3); return this; } @Override public CodeBuilder iconst_4() { - writeBytecode(ICONST_4); + bytecodesBufWriter.writeU1(ICONST_4); return this; } @Override public CodeBuilder iconst_5() { - writeBytecode(ICONST_5); + bytecodesBufWriter.writeU1(ICONST_5); return this; } @Override public CodeBuilder iconst_m1() { - writeBytecode(ICONST_M1); + bytecodesBufWriter.writeU1(ICONST_M1); return this; } @Override public CodeBuilder idiv() { - writeBytecode(IDIV); + bytecodesBufWriter.writeU1(IDIV); + return this; + } + + @Override + public CodeBuilder if_acmpeq(Label target) { + writeShortJump(IF_ACMPEQ, target); + return this; + } + + @Override + public CodeBuilder if_acmpne(Label target) { + writeShortJump(IF_ACMPNE, target); + return this; + } + + @Override + public CodeBuilder if_icmpeq(Label target) { + writeShortJump(IF_ICMPEQ, target); + return this; + } + + @Override + public CodeBuilder if_icmpge(Label target) { + writeShortJump(IF_ICMPGE, target); + return this; + } + + @Override + public CodeBuilder if_icmpgt(Label target) { + writeShortJump(IF_ICMPGT, target); + return this; + } + + @Override + public CodeBuilder if_icmple(Label target) { + writeShortJump(IF_ICMPLE, target); + return this; + } + + @Override + public CodeBuilder if_icmplt(Label target) { + writeShortJump(IF_ICMPLT, target); + return this; + } + + @Override + public CodeBuilder if_icmpne(Label target) { + writeShortJump(IF_ICMPNE, target); + return this; + } + + @Override + public CodeBuilder ifnonnull(Label target) { + writeShortJump(IFNONNULL, target); + return this; + } + + @Override + public CodeBuilder ifnull(Label target) { + writeShortJump(IFNULL, target); + return this; + } + + @Override + public CodeBuilder ifeq(Label target) { + writeShortJump(IFEQ, target); + return this; + } + + @Override + public CodeBuilder ifge(Label target) { + writeShortJump(IFGE, target); + return this; + } + + @Override + public CodeBuilder ifgt(Label target) { + writeShortJump(IFGT, target); + return this; + } + + @Override + public CodeBuilder ifle(Label target) { + writeShortJump(IFLE, target); + return this; + } + + @Override + public CodeBuilder iflt(Label target) { + writeShortJump(IFLT, target); + return this; + } + + @Override + public CodeBuilder ifne(Label target) { + writeShortJump(IFNE, target); return this; } @@ -1222,25 +1478,29 @@ public CodeBuilder iinc(int slot, int val) { @Override public CodeBuilder iload(int slot) { - writeLocalVar(BytecodeHelpers.iload(slot), slot); + if (slot >= 0 && slot <= 3) { + bytecodesBufWriter.writeU1(ILOAD_0 + slot); + } else { + writeLocalVar(ILOAD, slot); + } return this; } @Override public CodeBuilder imul() { - writeBytecode(IMUL); + bytecodesBufWriter.writeU1(IMUL); return this; } @Override public CodeBuilder ineg() { - writeBytecode(INEG); + bytecodesBufWriter.writeU1(INEG); return this; } @Override public CodeBuilder instanceOf(ClassEntry target) { - writeTypeCheck(INSTANCEOF, target); + bytecodesBufWriter.writeIndex(INSTANCEOF, target); return this; } @@ -1252,85 +1512,95 @@ public CodeBuilder invokedynamic(InvokeDynamicEntry ref) { @Override public CodeBuilder invokeinterface(InterfaceMethodRefEntry ref) { - writeInvokeInterface(INVOKEINTERFACE, ref, Util.parameterSlots(ref.typeSymbol()) + 1); + writeInvokeInterface(Opcode.INVOKEINTERFACE, ref, Util.parameterSlots(ref.typeSymbol()) + 1); return this; } @Override public CodeBuilder invokespecial(InterfaceMethodRefEntry ref) { - writeInvokeNormal(INVOKESPECIAL, ref); + bytecodesBufWriter.writeIndex(INVOKESPECIAL, ref); return this; } @Override public CodeBuilder invokespecial(MethodRefEntry ref) { - writeInvokeNormal(INVOKESPECIAL, ref); + bytecodesBufWriter.writeIndex(INVOKESPECIAL, ref); return this; } @Override public CodeBuilder invokestatic(InterfaceMethodRefEntry ref) { - writeInvokeNormal(INVOKESTATIC, ref); + bytecodesBufWriter.writeIndex(INVOKESTATIC, ref); return this; } @Override public CodeBuilder invokestatic(MethodRefEntry ref) { - writeInvokeNormal(INVOKESTATIC, ref); + bytecodesBufWriter.writeIndex(INVOKESTATIC, ref); return this; } @Override public CodeBuilder invokevirtual(MethodRefEntry ref) { - writeInvokeNormal(INVOKEVIRTUAL, ref); + bytecodesBufWriter.writeIndex(INVOKEVIRTUAL, ref); return this; } @Override public CodeBuilder ior() { - writeBytecode(IOR); + bytecodesBufWriter.writeU1(IOR); return this; } @Override public CodeBuilder irem() { - writeBytecode(IREM); + bytecodesBufWriter.writeU1(IREM); + return this; + } + + @Override + public CodeBuilder ireturn() { + bytecodesBufWriter.writeU1(IRETURN); return this; } @Override public CodeBuilder ishl() { - writeBytecode(ISHL); + bytecodesBufWriter.writeU1(ISHL); return this; } @Override public CodeBuilder ishr() { - writeBytecode(ISHR); + bytecodesBufWriter.writeU1(ISHR); return this; } @Override public CodeBuilder istore(int slot) { - writeLocalVar(BytecodeHelpers.istore(slot), slot); + if (slot >= 0 && slot <= 3) { + bytecodesBufWriter.writeU1(ISTORE_0 + slot); + } else { + writeLocalVar(ISTORE, slot); + } return this; } @Override public CodeBuilder isub() { - writeBytecode(ISUB); + bytecodesBufWriter.writeU1(ISUB); return this; } @Override public CodeBuilder iushr() { - writeBytecode(IUSHR); + bytecodesBufWriter.writeU1(IUSHR); return this; } @Override public CodeBuilder ixor() { - writeBytecode(IXOR); + bytecodesBufWriter.writeU1(IXOR); return this; } @@ -1342,139 +1612,154 @@ public CodeBuilder lookupswitch(Label defaultTarget, List cases) { @Override public CodeBuilder l2d() { - writeBytecode(L2D); + bytecodesBufWriter.writeU1(L2D); return this; } @Override public CodeBuilder l2f() { - writeBytecode(L2F); + bytecodesBufWriter.writeU1(L2F); return this; } @Override public CodeBuilder l2i() { - writeBytecode(L2I); + bytecodesBufWriter.writeU1(L2I); return this; } @Override public CodeBuilder ladd() { - writeBytecode(LADD); + bytecodesBufWriter.writeU1(LADD); return this; } @Override public CodeBuilder land() { - writeBytecode(LAND); + bytecodesBufWriter.writeU1(LAND); return this; } @Override public CodeBuilder lcmp() { - writeBytecode(LCMP); + bytecodesBufWriter.writeU1(LCMP); return this; } @Override public CodeBuilder lconst_0() { - writeBytecode(LCONST_0); + bytecodesBufWriter.writeU1(LCONST_0); return this; } @Override public CodeBuilder lconst_1() { - writeBytecode(LCONST_1); + bytecodesBufWriter.writeU1(LCONST_1); return this; } @Override public CodeBuilder ldc(LoadableConstantEntry entry) { - writeLoadConstant(BytecodeHelpers.ldcOpcode(entry), entry); + var direct = AbstractPoolEntry.maybeClone(constantPool, entry); + writeDirectLoadConstant(BytecodeHelpers.ldcOpcode(direct), direct); return this; } @Override public CodeBuilder ldiv() { - writeBytecode(LDIV); + bytecodesBufWriter.writeU1(LDIV); return this; } @Override public CodeBuilder lload(int slot) { - writeLocalVar(BytecodeHelpers.lload(slot), slot); + if (slot >= 0 && slot <= 3) { + bytecodesBufWriter.writeU1(LLOAD_0 + slot); + } else { + writeLocalVar(LLOAD, slot); + } return this; } @Override public CodeBuilder lmul() { - writeBytecode(LMUL); + bytecodesBufWriter.writeU1(LMUL); return this; } @Override public CodeBuilder lneg() { - writeBytecode(LNEG); + bytecodesBufWriter.writeU1(LNEG); return this; } @Override public CodeBuilder lor() { - writeBytecode(LOR); + bytecodesBufWriter.writeU1(LOR); return this; } @Override public CodeBuilder lrem() { - writeBytecode(LREM); + bytecodesBufWriter.writeU1(LREM); + return this; + } + + @Override + public CodeBuilder lreturn() { + bytecodesBufWriter.writeU1(LRETURN); return this; } @Override public CodeBuilder lshl() { - writeBytecode(LSHL); + bytecodesBufWriter.writeU1(LSHL); return this; } @Override public CodeBuilder lshr() { - writeBytecode(LSHR); + bytecodesBufWriter.writeU1(LSHR); return this; } @Override public CodeBuilder lstore(int slot) { - writeLocalVar(BytecodeHelpers.lstore(slot), slot); + if (slot >= 0 && slot <= 3) { + bytecodesBufWriter.writeU1(LSTORE_0 + slot); + } else { + writeLocalVar(LSTORE, slot); + } return this; } @Override public CodeBuilder lsub() { - writeBytecode(LSUB); + bytecodesBufWriter.writeU1(LSUB); return this; } @Override public CodeBuilder lushr() { - writeBytecode(LUSHR); + bytecodesBufWriter.writeU1(LUSHR); return this; } @Override public CodeBuilder lxor() { - writeBytecode(LXOR); + bytecodesBufWriter.writeU1(LXOR); return this; } @Override public CodeBuilder monitorenter() { - writeBytecode(MONITORENTER); + bytecodesBufWriter.writeU1(MONITORENTER); return this; } @Override public CodeBuilder monitorexit() { - writeBytecode(MONITOREXIT); + bytecodesBufWriter.writeU1(MONITOREXIT); return this; } @@ -1501,26 +1786,26 @@ public CodeBuilder newarray(TypeKind typeKind) { @Override public CodeBuilder pop() { - writeBytecode(POP); + bytecodesBufWriter.writeU1(POP); return this; } @Override public CodeBuilder pop2() { - writeBytecode(POP2); + bytecodesBufWriter.writeU1(POP2); return this; } @Override public CodeBuilder sipush(int s) { BytecodeHelpers.validateSipush(s); - writeArgumentConstant(SIPUSH, s); + bytecodesBufWriter.writeU1U2(SIPUSH, s); return this; } @Override public CodeBuilder swap() { - writeBytecode(SWAP); + bytecodesBufWriter.writeU1(SWAP); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java index 15547924cf37f..1af3724766e06 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java @@ -25,13 +25,14 @@ package jdk.internal.classfile.impl; -import java.util.function.Consumer; - import java.lang.classfile.CustomAttribute; import java.lang.classfile.FieldBuilder; import java.lang.classfile.FieldElement; import java.lang.classfile.FieldModel; import java.lang.classfile.constantpool.Utf8Entry; +import java.util.function.Consumer; + +import static java.util.Objects.requireNonNull; public final class DirectFieldBuilder extends AbstractDirectBuilder @@ -48,8 +49,8 @@ public DirectFieldBuilder(SplitConstantPool constantPool, FieldModel original) { super(constantPool, context); setOriginal(original); - this.name = name; - this.desc = type; + this.name = requireNonNull(name); + this.desc = requireNonNull(type); this.flags = flags; } @@ -58,7 +59,7 @@ public FieldBuilder with(FieldElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute) element); + writeAttribute((CustomAttribute) requireNonNull(element)); } return this; } @@ -80,9 +81,7 @@ void setFlags(int flags) { @Override public void writeTo(BufWriterImpl buf) { - buf.writeU2(flags); - buf.writeIndex(name); - buf.writeIndex(desc); + buf.writeU2U2U2(flags, buf.cpIndex(name), buf.cpIndex(desc)); attributes.writeTo(buf); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java index ec4e148baf30d..938d6c088b7fb 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java @@ -25,18 +25,12 @@ package jdk.internal.classfile.impl; +import java.lang.classfile.*; +import java.lang.classfile.constantpool.Utf8Entry; import java.lang.constant.MethodTypeDesc; import java.util.function.Consumer; -import java.lang.classfile.ClassFile; -import java.lang.classfile.CodeBuilder; -import java.lang.classfile.CodeModel; -import java.lang.classfile.CodeTransform; -import java.lang.classfile.CustomAttribute; -import java.lang.classfile.MethodBuilder; -import java.lang.classfile.MethodElement; -import java.lang.classfile.MethodModel; -import java.lang.classfile.constantpool.Utf8Entry; +import static java.util.Objects.requireNonNull; public final class DirectMethodBuilder extends AbstractDirectBuilder @@ -55,8 +49,8 @@ public DirectMethodBuilder(SplitConstantPool constantPool, MethodModel original) { super(constantPool, context); setOriginal(original); - this.name = nameInfo; - this.desc = typeInfo; + this.name = requireNonNull(nameInfo); + this.desc = requireNonNull(typeInfo); this.flags = flags; } @@ -114,7 +108,7 @@ public MethodBuilder with(MethodElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute) element); + writeAttribute((CustomAttribute) requireNonNull(element)); } return this; } @@ -148,9 +142,7 @@ public DirectMethodBuilder run(Consumer handler) { @Override public void writeTo(BufWriterImpl buf) { - buf.writeU2(flags); - buf.writeIndex(name); - buf.writeIndex(desc); + buf.writeU2U2U2(flags, buf.cpIndex(name), buf.cpIndex(desc)); attributes.writeTo(buf); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/EntryMap.java b/src/java.base/share/classes/jdk/internal/classfile/impl/EntryMap.java index d5ebbbebe7ada..be350cb581444 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/EntryMap.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/EntryMap.java @@ -113,6 +113,7 @@ public void put(int hash, int index) { throw new IllegalArgumentException("hash must be nonzero"); int ptr = (hash & mask1) << 1; + var data = this.data; int k = data[ptr]; if (k == 0) { data[ptr] = hash; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java index 30bb8136e45ab..a322c08a55a8a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java @@ -24,14 +24,18 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.AccessFlags; +import java.lang.classfile.Attribute; +import java.lang.classfile.ClassModel; +import java.lang.classfile.ClassReader; +import java.lang.classfile.FieldElement; +import java.lang.classfile.FieldModel; +import java.lang.classfile.constantpool.Utf8Entry; import java.lang.reflect.AccessFlag; import java.util.List; import java.util.Optional; import java.util.function.Consumer; -import java.lang.classfile.*; -import java.lang.classfile.constantpool.Utf8Entry; - public final class FieldImpl extends AbstractElement implements FieldModel, Util.Writable { @@ -84,9 +88,9 @@ public void writeTo(BufWriterImpl buf) { reader.copyBytesTo(buf, startPos, endPos - startPos); } else { - buf.writeU2(flags().flagsMask()); - buf.writeIndex(fieldName()); - buf.writeIndex(fieldType()); + buf.writeU2U2U2(flags().flagsMask(), + buf.cpIndex(fieldName()), + buf.cpIndex(fieldType())); Util.writeAttributes(buf, attributes()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java index 242ec02c72371..72310b6498234 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java @@ -24,12 +24,11 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.Interfaces; +import java.lang.classfile.constantpool.ClassEntry; import java.util.List; import java.util.stream.Collectors; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.Interfaces; - public final class InterfacesImpl extends AbstractElement implements Interfaces { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java index 2aaf5f033c0b6..aac0fafaef146 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java @@ -24,8 +24,6 @@ */ package jdk.internal.classfile.impl; -import java.util.Objects; - import java.lang.classfile.Label; import java.lang.classfile.instruction.LabelTarget; @@ -52,7 +50,7 @@ public final class LabelImpl private int bci; public LabelImpl(LabelContext labelContext, int bci) { - this.labelContext = Objects.requireNonNull(labelContext); + this.labelContext = labelContext; this.bci = bci; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java index 8467152504ee5..10341f79135c5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java @@ -24,10 +24,9 @@ */ package jdk.internal.classfile.impl; -import java.lang.constant.MethodTypeDesc; import java.lang.classfile.*; import java.lang.classfile.constantpool.Utf8Entry; - +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.AccessFlag; import java.util.List; import java.util.Optional; @@ -103,9 +102,9 @@ public void writeTo(BufWriterImpl buf) { reader.copyBytesTo(buf, startPos, endPos - startPos); } else { - buf.writeU2(flags().flagsMask()); - buf.writeIndex(methodName()); - buf.writeIndex(methodType()); + buf.writeU2U2U2(flags().flagsMask(), + buf.cpIndex(methodName()), + buf.cpIndex(methodType())); Util.writeAttributes(buf, attributes()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodInfo.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodInfo.java index ce51144770676..2ecce31cb9114 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodInfo.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodInfo.java @@ -24,8 +24,8 @@ */ package jdk.internal.classfile.impl; -import java.lang.constant.MethodTypeDesc; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.MethodTypeDesc; import static java.lang.classfile.ClassFile.ACC_STATIC; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java index 873b32e4ad649..505bbfd6fea23 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java @@ -25,16 +25,22 @@ package jdk.internal.classfile.impl; -import java.lang.classfile.attribute.*; +import java.lang.classfile.attribute.ModuleAttribute; import java.lang.classfile.attribute.ModuleAttribute.ModuleAttributeBuilder; +import java.lang.classfile.attribute.ModuleExportInfo; +import java.lang.classfile.attribute.ModuleOpenInfo; +import java.lang.classfile.attribute.ModuleProvideInfo; +import java.lang.classfile.attribute.ModuleRequireInfo; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ModuleEntry; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.ClassDesc; import java.lang.constant.ModuleDesc; import java.lang.constant.PackageDesc; - -import java.lang.constant.ClassDesc; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.Objects; +import java.util.Set; public final class ModuleAttributeBuilderImpl implements ModuleAttributeBuilder { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java index 2403ae150e9dd..659f41f9699ae 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java @@ -299,7 +299,6 @@ public static int align(int n) { private int nextBci; private int bci; private int opcode; - private boolean isWide; public static CodeRange of(byte[] array) { return new CodeRange(array, array.length); @@ -341,14 +340,14 @@ public void reset(int nextBci) { * be valid and can be accessed unchecked. */ public int opcode() { - return opcode; + return opcode & 0xFF; } /** * Returns whether the current functional opcode is in wide. */ public boolean isWide() { - return isWide; + return (opcode & (WIDE << 8)) != 0; } /** @@ -411,7 +410,7 @@ public int destW() { // *load, *store, iinc public int getIndex() { - return isWide ? getU2Unchecked(bci + 2) : getIndexU1(); + return isWide() ? getU2Unchecked(bci + 2) : getIndexU1(); } // ldc @@ -443,12 +442,11 @@ public boolean next() { int len = LENGTHS[code & 0xFF]; // & 0xFF eliminates bound check this.bci = bci; opcode = code; - isWide = false; if (len <= 0) { len = checkSpecialInstruction(bci, end, code); // sets opcode } - if (len <= 0 || (nextBci += len) > end) { + if ((nextBci += len) > end) { opcode = ILLEGAL; } @@ -457,37 +455,34 @@ public boolean next() { // Put rarely used code in another method to reduce code size private int checkSpecialInstruction(int bci, int end, int code) { + int len = -1; if (code == WIDE) { - if (bci + 1 >= end) { - return -1; + if (bci + 1 < end) { + opcode = (WIDE << 8) | (code = getIndexU1()); + // Validated in UtilTest.testOpcodeLengthTable + len = LENGTHS[code] * 2; } - opcode = code = getIndexU1(); - isWide = true; - // Validated in UtilTest.testOpcodeLengthTable - return LENGTHS[code] * 2; - } - if (code == TABLESWITCH) { + } else if (code == TABLESWITCH) { int alignedBci = align(bci + 1); - if (alignedBci + 3 * 4 >= end) { - return -1; + if (alignedBci + 3 * 4 < end) { + int lo = getIntUnchecked(alignedBci + 1 * 4); + int hi = getIntUnchecked(alignedBci + 2 * 4); + long l = alignedBci - bci + (3L + (long) hi - lo + 1L) * 4L; + len = l > 0 && ((int) l == l) ? (int) l : -1; } - int lo = getIntUnchecked(alignedBci + 1 * 4); - int hi = getIntUnchecked(alignedBci + 2 * 4); - long l = alignedBci - bci + (3L + (long) hi - lo + 1L) * 4L; - return l > 0 && ((int) l == l) ? (int) l : -1; - } - if (code == LOOKUPSWITCH) { + } else if (code == LOOKUPSWITCH) { int alignedBci = align(bci + 1); - if (alignedBci + 2 * 4 >= end) { - return -1; - } - int npairs = getIntUnchecked(alignedBci + 4); - if (npairs < 0) { - return -1; + if (alignedBci + 2 * 4 < end) { + int npairs = getIntUnchecked(alignedBci + 4); + if (npairs >= 0) { + long l = alignedBci - bci + (2L + 2L * npairs) * 4L; + len = l > 0 && ((int) l == l) ? (int) l : -1; + } } - long l = alignedBci - bci + (2L + 2L * npairs) * 4L; - return l > 0 && ((int) l == l) ? (int) l : -1; } - return -1; + if (len <= 0) { + opcode = ILLEGAL; + } + return len; } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java index 77f6933a0c214..5486b58f04e3c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java @@ -24,15 +24,20 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.ClassSignature; +import java.lang.classfile.MethodSignature; +import java.lang.classfile.Signature; +import java.lang.classfile.Signature.ArrayTypeSig; +import java.lang.classfile.Signature.ClassTypeSig; +import java.lang.classfile.Signature.RefTypeSig; +import java.lang.classfile.Signature.ThrowableSig; +import java.lang.classfile.Signature.TypeArg; +import java.lang.classfile.Signature.TypeParam; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.Collections; -import java.lang.classfile.ClassSignature; -import java.lang.classfile.MethodSignature; -import java.lang.classfile.Signature; -import java.lang.classfile.Signature.*; public final class SignaturesImpl { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index 2193eb761081d..0e26a8941e0a1 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -24,21 +24,18 @@ */ package jdk.internal.classfile.impl; -import java.lang.constant.ClassDesc; -import java.lang.constant.MethodTypeDesc; -import java.util.Arrays; -import java.util.List; - import java.lang.classfile.Attributes; -import java.lang.classfile.ClassReader; import java.lang.classfile.BootstrapMethodEntry; +import java.lang.classfile.ClassReader; import java.lang.classfile.attribute.BootstrapMethodsAttribute; import java.lang.classfile.constantpool.*; -import java.util.Objects; - -import jdk.internal.constant.ConstantUtils; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.util.Arrays; +import java.util.List; import static java.lang.classfile.constantpool.PoolEntry.*; +import static java.util.Objects.requireNonNull; public final class SplitConstantPool implements ConstantPoolBuilder { @@ -87,20 +84,27 @@ public int bootstrapMethodCount() { @Override public PoolEntry entryByIndex(int index) { if (index <= 0 || index >= size()) { - throw new ConstantPoolException("Bad CP index: " + index); + throw badCP(index); } PoolEntry pe = (index < parentSize) ? parent.entryByIndex(index) : myEntries[index - parentSize]; if (pe == null) { - throw new ConstantPoolException("Unusable CP index: " + index); + throw unusableCP(index); } return pe; } + private static ConstantPoolException badCP(int index) { + return new ConstantPoolException("Bad CP index: " + index); + } + + private static ConstantPoolException unusableCP(int index) { + return new ConstantPoolException("Unusable CP index: " + index); + } + @Override public T entryByIndex(int index, Class cls) { - Objects.requireNonNull(cls); return ClassReaderImpl.checkType(entryByIndex(index), index, cls); } @@ -116,6 +120,7 @@ public BootstrapMethodEntryImpl bootstrapMethodEntry(int index) { @Override public boolean canWriteDirect(ConstantPool other) { + requireNonNull(other); return this == other || parent == other; } @@ -165,8 +170,10 @@ void writeTo(BufWriterImpl buf) { } private EntryMap map() { + int parentSize = this.parentSize; + var map = this.map; if (map == null) { - map = new EntryMap(Math.max(size, 1024), .75f); + this.map = map = new EntryMap(Math.max(size, 1024), .75f); // Doing a full scan here yields fall-off-the-cliff performance results, // especially if we only need a few entries that are already @@ -203,8 +210,10 @@ private void fullScan() { } private EntryMap bsmMap() { + int bsmSize = this.bsmSize; + var bsmMap = this.bsmMap; if (bsmMap == null) { - bsmMap = new EntryMap(Math.max(bsmSize, 16), .75f); + this.bsmMap = bsmMap = new EntryMap(Math.max(bsmSize, 16), .75f); for (int i=0; i { var cpe = cp.entryByIndex(bcs.getIndexU2()); var nameAndType = opcode == INVOKEDYNAMIC ? ((DynamicConstantPoolEntry)cpe).nameAndType() : ((MemberRefEntry)cpe).nameAndType(); - var mtd = Util.methodTypeSymbol(nameAndType); + var mtd = Util.methodTypeSymbol(nameAndType.type()); var delta = Util.slotSize(mtd.returnType()) - Util.parameterSlots(mtd); if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) { delta--; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index 884f7b8bbc8fa..f8e58ed2242ab 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -30,7 +30,10 @@ import java.lang.classfile.Label; import java.lang.classfile.MethodModel; import java.lang.classfile.attribute.StackMapFrameInfo; -import java.lang.classfile.attribute.StackMapFrameInfo.*; +import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInfo; +import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo; +import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo; +import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo; import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; @@ -40,15 +43,16 @@ import java.util.List; import java.util.Objects; -import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.ClassFile.ACC_STATIC; import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*; +import static java.util.Objects.requireNonNull; public class StackMapDecoder { private static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, SAME_EXTENDED = 251; - private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = new StackMapFrameInfo[0]; + private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {}; private final ClassReader classReader; private final int pos; @@ -135,8 +139,7 @@ private static void writeFrame(BufWriterImpl out, int offsetDelta, List l1, List - {} + bw.writeU1(tag); case ITEM_OBJECT -> - bw.writeIndex(((ObjectVerificationTypeInfo)vti).className()); + bw.writeU1U2(tag, bw.cpIndex(((ObjectVerificationTypeInfo)vti).className())); case ITEM_UNINITIALIZED -> - bw.writeU2(bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget())); + bw.writeU1U2(tag, bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget())); default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag()); } } @@ -249,6 +249,9 @@ private VerificationTypeInfo readVerificationTypeInfo() { public static record ObjectVerificationTypeInfoImpl( ClassEntry className) implements ObjectVerificationTypeInfo { + public ObjectVerificationTypeInfoImpl { + requireNonNull(className); + } @Override public int tag() { return ITEM_OBJECT; } @@ -274,6 +277,9 @@ public String toString() { } public static record UninitializedVerificationTypeInfoImpl(Label newTarget) implements UninitializedVerificationTypeInfo { + public UninitializedVerificationTypeInfoImpl { + requireNonNull(newTarget); + } @Override public int tag() { return ITEM_UNINITIALIZED; } @@ -296,6 +302,7 @@ public static record StackMapFrameImpl(int frameType, List stack) implements StackMapFrameInfo { public StackMapFrameImpl { + requireNonNull(target); locals = List.copyOf(locals); stack = List.copyOf(stack); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index ae9835206831e..d4bff1bfe8045 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding 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 @@ -27,7 +28,6 @@ import java.lang.classfile.Attribute; import java.lang.classfile.Attributes; -import java.lang.classfile.BufWriter; import java.lang.classfile.Label; import java.lang.classfile.attribute.StackMapTableAttribute; import java.lang.classfile.constantpool.ClassEntry; @@ -39,11 +39,11 @@ import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; import java.util.Arrays; -import java.util.BitSet; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -import jdk.internal.constant.ReferenceClassDescImpl; + +import jdk.internal.constant.ClassOrInterfaceDescImpl; import jdk.internal.util.Preconditions; import static java.lang.classfile.ClassFile.*; @@ -58,8 +58,8 @@ *

    * The {@linkplain #generate() frames computation} consists of following steps: *

      - *
    1. {@linkplain #detectFrameOffsets() Detection} of mandatory stack map frames offsets:
        - *
      • Mandatory stack map frame offsets include all jump and switch instructions targets, + *
      • {@linkplain #detectFrames() Detection} of mandatory stack map frames:
          + *
        • Mandatory stack map frame include all jump and switch instructions targets, * offsets immediately following {@linkplain #noControlFlow(int) "no control flow"} * and all exception table handlers. *
        • Detection is performed in a single fast pass through the bytecode, @@ -163,6 +163,7 @@ static StackMapGenerator of(DirectCodeBuilder dcb, BufWriterImpl buf) { private static final int FLAG_THIS_UNINIT = 0x01; private static final int FRAME_DEFAULT_CAPACITY = 10; private static final int T_BOOLEAN = 4, T_LONG = 11; + private static final Frame[] EMPTY_FRAME_ARRAY = {}; private static final int ITEM_TOP = 0, ITEM_INTEGER = 1, @@ -198,7 +199,8 @@ static record RawExceptionCatch(int start, int end, int handler, Type catchType) private final ClassHierarchyImpl classHierarchy; private final boolean patchDeadCode; private final boolean filterDeadLabels; - private List frames; + private Frame[] frames = EMPTY_FRAME_ARRAY; + private int framesCount = 0; private final Frame currentFrame; private int maxStack, maxLocals; @@ -262,10 +264,10 @@ public int maxStack() { private Frame getFrame(int offset) { //binary search over frames ordered by offset int low = 0; - int high = frames.size() - 1; + int high = framesCount - 1; while (low <= high) { int mid = (low + high) >>> 1; - var f = frames.get(mid); + var f = frames[mid]; if (f.offset < offset) low = mid + 1; else if (f.offset > offset) @@ -283,8 +285,8 @@ private void checkJumpTarget(Frame frame, int target) { private int exMin, exMax; private boolean isAnyFrameDirty() { - for (var f : frames) { - if (f.dirty) return true; + for (int i = 0; i < framesCount; i++) { + if (frames[i].dirty) return true; } return false; } @@ -292,27 +294,10 @@ private boolean isAnyFrameDirty() { private void generate() { exMin = bytecode.length(); exMax = -1; - for (var exhandler : handlers) { - int start_pc = labelContext.labelToBci(exhandler.tryStart()); - int end_pc = labelContext.labelToBci(exhandler.tryEnd()); - int handler_pc = labelContext.labelToBci(exhandler.handler()); - if (start_pc >= 0 && end_pc >= 0 && end_pc > start_pc && handler_pc >= 0) { - if (start_pc < exMin) exMin = start_pc; - if (end_pc > exMax) exMax = end_pc; - var catchType = exhandler.catchType(); - rawHandlers.add(new RawExceptionCatch(start_pc, end_pc, handler_pc, - catchType.isPresent() ? cpIndexToType(catchType.get().index(), cp) - : Type.THROWABLE_TYPE)); - } - } - BitSet frameOffsets = detectFrameOffsets(); - int framesCount = frameOffsets.cardinality(); - frames = new ArrayList<>(framesCount); - int offset = -1; - for (int i = 0; i < framesCount; i++) { - offset = frameOffsets.nextSetBit(offset + 1); - frames.add(new Frame(offset, classHierarchy)); + if (!handlers.isEmpty()) { + generateHandlers(); } + detectFrames(); do { processMethod(); } while (isAnyFrameDirty()); @@ -321,27 +306,50 @@ private void generate() { //dead code patching for (int i = 0; i < framesCount; i++) { - var frame = frames.get(i); + var frame = frames[i]; if (frame.flags == -1) { - if (!patchDeadCode) throw generatorError("Unable to generate stack map frame for dead code", frame.offset); - //patch frame - frame.pushStack(Type.THROWABLE_TYPE); - if (maxStack < 1) maxStack = 1; - int end = (i < framesCount - 1 ? frames.get(i + 1).offset : bytecode.length()) - 1; - //patch bytecode - var arr = bytecode.array(); - Arrays.fill(arr, frame.offset, end, (byte) NOP); - arr[end] = (byte) ATHROW; - //patch handlers - removeRangeFromExcTable(frame.offset, end + 1); + deadCodePatching(frame, i); + } + } + } + + private void generateHandlers() { + var labelContext = this.labelContext; + for (int i = 0; i < handlers.size(); i++) { + var exhandler = handlers.get(i); + int start_pc = labelContext.labelToBci(exhandler.tryStart()); + int end_pc = labelContext.labelToBci(exhandler.tryEnd()); + int handler_pc = labelContext.labelToBci(exhandler.handler()); + if (start_pc >= 0 && end_pc >= 0 && end_pc > start_pc && handler_pc >= 0) { + if (start_pc < exMin) exMin = start_pc; + if (end_pc > exMax) exMax = end_pc; + var catchType = exhandler.catchType(); + rawHandlers.add(new RawExceptionCatch(start_pc, end_pc, handler_pc, + catchType.isPresent() ? cpIndexToType(catchType.get().index(), cp) + : Type.THROWABLE_TYPE)); } } } + private void deadCodePatching(Frame frame, int i) { + if (!patchDeadCode) throw generatorError("Unable to generate stack map frame for dead code", frame.offset); + //patch frame + frame.pushStack(Type.THROWABLE_TYPE); + if (maxStack < 1) maxStack = 1; + int end = (i < framesCount - 1 ? frames[i + 1].offset : bytecode.length()) - 1; + //patch bytecode + var arr = bytecode.array(); + Arrays.fill(arr, frame.offset, end, (byte) NOP); + arr[end] = (byte) ATHROW; + //patch handlers + removeRangeFromExcTable(frame.offset, end + 1); + } + private void removeRangeFromExcTable(int rangeStart, int rangeEnd) { var it = handlers.listIterator(); while (it.hasNext()) { var e = it.next(); + var labelContext = this.labelContext; int handlerStart = labelContext.labelToBci(e.tryStart()); int handlerEnd = labelContext.labelToBci(e.tryEnd()); if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) { @@ -380,16 +388,18 @@ private void removeRangeFromExcTable(int rangeStart, int rangeEnd) { * @return StackMapTableAttribute or null if stack map is empty */ public Attribute stackMapTableAttribute() { - return frames.isEmpty() ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) { + return framesCount == 0 ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) { @Override public void writeBody(BufWriterImpl b) { - b.writeU2(frames.size()); - Frame prevFrame = new Frame(classHierarchy); - prevFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType); + var gen = StackMapGenerator.this; + b.writeU2(gen.framesCount); + Frame prevFrame = gen.new Frame(gen.classHierarchy); + prevFrame.setLocalsFromArg(gen.methodName, gen.methodDesc, gen.isStatic, gen.thisType); prevFrame.trimAndCompress(); - for (var fr : frames) { + for (int i = 0; i < gen.framesCount; i++) { + var fr = gen.frames[i]; fr.trimAndCompress(); - fr.writeTo(b, prevFrame, cp); + fr.writeTo(b, prevFrame, gen.cp); prevFrame = fr; } } @@ -412,19 +422,19 @@ private void processMethod() { boolean ncf = false; while (bcs.next()) { currentFrame.offset = bcs.bci(); - if (stackmapIndex < frames.size()) { - int thisOffset = frames.get(stackmapIndex).offset; + if (stackmapIndex < framesCount) { + int thisOffset = frames[stackmapIndex].offset; if (ncf && thisOffset > bcs.bci()) { throw generatorError("Expecting a stack map frame"); } if (thisOffset == bcs.bci()) { - Frame nextFrame = frames.get(stackmapIndex++); + Frame nextFrame = frames[stackmapIndex++]; if (!ncf) { currentFrame.checkAssignableTo(nextFrame); } while (!nextFrame.dirty) { //skip unmatched frames - if (stackmapIndex == frames.size()) return; //skip the rest of this round - nextFrame = frames.get(stackmapIndex++); + if (stackmapIndex == framesCount) return; //skip the rest of this round + nextFrame = frames[stackmapIndex++]; } bcs.reset(nextFrame.offset); //skip code up-to the next frame bcs.next(); @@ -452,6 +462,7 @@ private boolean processBlock(RawBytecodeHelper bcs) { processExceptionHandlerTargets(bci, this_uninit); verified_exc_handlers = true; } + var currentFrame = this.currentFrame; switch (opcode) { case NOP -> {} case RETURN -> { @@ -492,27 +503,27 @@ private boolean processBlock(RawBytecodeHelper bcs) { case ALOAD_0, ALOAD_1, ALOAD_2, ALOAD_3 -> currentFrame.pushStack(currentFrame.getLocal(opcode - ALOAD_0)); case IALOAD, BALOAD, CALOAD, SALOAD -> - currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack2PushStack(Type.INTEGER_TYPE); case LALOAD -> - currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case FALOAD -> - currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack2PushStack(Type.FLOAT_TYPE); case DALOAD -> - currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case AALOAD -> - currentFrame.pushStack((type1 = currentFrame.decStack(1).popStack()) == Type.NULL_TYPE ? Type.NULL_TYPE : type1.getComponent()); + currentFrame.pushStack((type1 = currentFrame.decStack().popStack()) == Type.NULL_TYPE ? Type.NULL_TYPE : type1.getComponent()); case ISTORE -> - currentFrame.decStack(1).setLocal(bcs.getIndex(), Type.INTEGER_TYPE); + currentFrame.decStack().setLocal(bcs.getIndex(), Type.INTEGER_TYPE); case ISTORE_0, ISTORE_1, ISTORE_2, ISTORE_3 -> - currentFrame.decStack(1).setLocal(opcode - ISTORE_0, Type.INTEGER_TYPE); + currentFrame.decStack().setLocal(opcode - ISTORE_0, Type.INTEGER_TYPE); case LSTORE -> currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.LONG_TYPE, Type.LONG2_TYPE); case LSTORE_0, LSTORE_1, LSTORE_2, LSTORE_3 -> currentFrame.decStack(2).setLocal2(opcode - LSTORE_0, Type.LONG_TYPE, Type.LONG2_TYPE); case FSTORE -> - currentFrame.decStack(1).setLocal(bcs.getIndex(), Type.FLOAT_TYPE); + currentFrame.decStack().setLocal(bcs.getIndex(), Type.FLOAT_TYPE); case FSTORE_0, FSTORE_1, FSTORE_2, FSTORE_3 -> - currentFrame.decStack(1).setLocal(opcode - FSTORE_0, Type.FLOAT_TYPE); + currentFrame.decStack().setLocal(opcode - FSTORE_0, Type.FLOAT_TYPE); case DSTORE -> currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case DSTORE_0, DSTORE_1, DSTORE_2, DSTORE_3 -> @@ -526,98 +537,75 @@ private boolean processBlock(RawBytecodeHelper bcs) { case IASTORE, BASTORE, CASTORE, SASTORE, FASTORE, AASTORE -> currentFrame.decStack(3); case POP, MONITORENTER, MONITOREXIT -> - currentFrame.decStack(1); + currentFrame.decStack(); case POP2 -> currentFrame.decStack(2); case DUP -> - currentFrame.pushStack(type1 = currentFrame.popStack()).pushStack(type1); - case DUP_X1 -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - currentFrame.pushStack(type1).pushStack(type2).pushStack(type1); - } - case DUP_X2 -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - type3 = currentFrame.popStack(); - currentFrame.pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1); - } - case DUP2 -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - currentFrame.pushStack(type2).pushStack(type1).pushStack(type2).pushStack(type1); - } - case DUP2_X1 -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - type3 = currentFrame.popStack(); - currentFrame.pushStack(type2).pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1); - } - case DUP2_X2 -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - type3 = currentFrame.popStack(); - type4 = currentFrame.popStack(); - currentFrame.pushStack(type2).pushStack(type1).pushStack(type4).pushStack(type3).pushStack(type2).pushStack(type1); - } - case SWAP -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - currentFrame.pushStack(type1); - currentFrame.pushStack(type2); - } + currentFrame.dup(); + case DUP_X1 -> + currentFrame.dup_x1(); + case DUP_X2 -> + currentFrame.dup_x2(); + case DUP2 -> + currentFrame.dup2(); + case DUP2_X1 -> + currentFrame.dup2_x1(); + case DUP2_X2 -> + currentFrame.dup2_x2(); + case SWAP -> + currentFrame.swap(); case IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IOR, IXOR, IAND -> - currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack2PushStack(Type.INTEGER_TYPE); case INEG, ARRAYLENGTH, INSTANCEOF -> - currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack1PushStack(Type.INTEGER_TYPE); case LADD, LSUB, LMUL, LDIV, LREM, LAND, LOR, LXOR -> - currentFrame.decStack(4).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack4PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case LNEG -> - currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case LSHL, LSHR, LUSHR -> - currentFrame.decStack(3).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack3PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case FADD, FSUB, FMUL, FDIV, FREM -> - currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack2PushStack(Type.FLOAT_TYPE); case FNEG -> - currentFrame.decStack(1).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack1PushStack(Type.FLOAT_TYPE); case DADD, DSUB, DMUL, DDIV, DREM -> - currentFrame.decStack(4).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack4PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case DNEG -> - currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case IINC -> currentFrame.checkLocal(bcs.getIndex()); case I2L -> - currentFrame.decStack(1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case L2I -> - currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack2PushStack(Type.INTEGER_TYPE); case I2F -> - currentFrame.decStack(1).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack1PushStack(Type.FLOAT_TYPE); case I2D -> - currentFrame.decStack(1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case L2F -> - currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack2PushStack(Type.FLOAT_TYPE); case L2D -> - currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case F2I -> - currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack1PushStack(Type.INTEGER_TYPE); case F2L -> - currentFrame.decStack(1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case F2D -> - currentFrame.decStack(1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case D2L -> - currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case D2F -> - currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack2PushStack(Type.FLOAT_TYPE); case I2B, I2C, I2S -> - currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack1PushStack(Type.INTEGER_TYPE); case LCMP, DCMPL, DCMPG -> - currentFrame.decStack(4).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack4PushStack(Type.INTEGER_TYPE); case FCMPL, FCMPG, D2I -> - currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack2PushStack(Type.INTEGER_TYPE); case IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE -> checkJumpTarget(currentFrame.decStack(2), bcs.dest()); case IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL -> - checkJumpTarget(currentFrame.decStack(1), bcs.dest()); + checkJumpTarget(currentFrame.decStack(), bcs.dest()); case GOTO -> { checkJumpTarget(currentFrame, bcs.dest()); ncf = true; @@ -635,7 +623,7 @@ private boolean processBlock(RawBytecodeHelper bcs) { ncf = true; } case IRETURN, FRETURN, ARETURN, ATHROW -> { - currentFrame.decStack(1); + currentFrame.decStack(); ncf = true; } case GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD -> @@ -645,17 +633,16 @@ private boolean processBlock(RawBytecodeHelper bcs) { case NEW -> currentFrame.pushStack(Type.uninitializedType(bci)); case NEWARRAY -> - currentFrame.decStack(1).pushStack(getNewarrayType(bcs.getIndex())); + currentFrame.decStack1PushStack(getNewarrayType(bcs.getIndex())); case ANEWARRAY -> processAnewarray(bcs.getIndexU2()); case CHECKCAST -> - currentFrame.decStack(1).pushStack(cpIndexToType(bcs.getIndexU2(), cp)); + currentFrame.decStack1PushStack(cpIndexToType(bcs.getIndexU2(), cp)); case MULTIANEWARRAY -> { type1 = cpIndexToType(bcs.getIndexU2(), cp); - int dim = bcs.getU1Unchecked(bcs.bci() + 3); - for (int i = 0; i < dim; i++) { - currentFrame.popStack(); - } + currentFrame.decStack( + bcs.getU1Unchecked(bcs.bci() + 3) /* dim */ + ); currentFrame.pushStack(type1); } case JSR, JSR_W, RET -> @@ -670,6 +657,7 @@ private boolean processBlock(RawBytecodeHelper bcs) { } private void processExceptionHandlerTargets(int bci, boolean this_uninit) { + var currentFrame = this.currentFrame; for (var ex : rawHandlers) { if (bci == ex.start || (currentFrame.localsChanged && bci > ex.start && bci < ex.end)) { int flags = currentFrame.flags; @@ -682,7 +670,10 @@ private void processExceptionHandlerTargets(int bci, boolean this_uninit) { } private void processLdc(int index) { - switch (cp.entryByIndex(index).tag()) { + var e = cp.entryByIndex(index); + byte tag = e.tag(); + var currentFrame = this.currentFrame; + switch (tag) { case TAG_UTF8 -> currentFrame.pushStack(Type.OBJECT_TYPE); case TAG_STRING -> @@ -702,9 +693,9 @@ private void processLdc(int index) { case TAG_METHOD_TYPE -> currentFrame.pushStack(Type.METHOD_TYPE); case TAG_DYNAMIC -> - currentFrame.pushStack(cp.entryByIndex(index, ConstantDynamicEntry.class).asSymbol().constantType()); + currentFrame.pushStack(ClassReaderImpl.checkType(e, index, ConstantDynamicEntry.class).asSymbol().constantType()); default -> - throw generatorError("CP entry #%d %s is not loadable constant".formatted(index, cp.entryByIndex(index).tag())); + throw generatorError("CP entry #%d %s is not loadable constant".formatted(index, tag)); } } @@ -713,7 +704,7 @@ private void processSwitch(RawBytecodeHelper bcs) { int alignedBci = RawBytecodeHelper.align(bci + 1); int defaultOffset = bcs.getIntUnchecked(alignedBci); int keys, delta; - currentFrame.popStack(); + currentFrame.decStack(); if (bcs.opcode() == TABLESWITCH) { int low = bcs.getIntUnchecked(alignedBci + 4); int high = bcs.getIntUnchecked(alignedBci + 2 * 4); @@ -748,22 +739,19 @@ private void processSwitch(RawBytecodeHelper bcs) { } private void processFieldInstructions(RawBytecodeHelper bcs) { - var desc = Util.fieldTypeSymbol(cp.entryByIndex(bcs.getIndexU2(), MemberRefEntry.class).nameAndType()); + var desc = Util.fieldTypeSymbol(cp.entryByIndex(bcs.getIndexU2(), MemberRefEntry.class).type()); + var currentFrame = this.currentFrame; switch (bcs.opcode()) { case GETSTATIC -> currentFrame.pushStack(desc); case PUTSTATIC -> { - currentFrame.popStack(); - if (Util.isDoubleSlot(desc)) currentFrame.popStack(); + currentFrame.decStack(Util.isDoubleSlot(desc) ? 2 : 1); } case GETFIELD -> { - currentFrame.popStack(); - currentFrame.pushStack(desc); + currentFrame.dec1PushStack(desc); } case PUTFIELD -> { - currentFrame.popStack(); - currentFrame.popStack(); - if (Util.isDoubleSlot(desc)) currentFrame.popStack(); + currentFrame.decStack(Util.isDoubleSlot(desc) ? 3 : 2); } default -> throw new AssertionError("Should not reach here"); } @@ -775,12 +763,12 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl var nameAndType = opcode == INVOKEDYNAMIC ? cp.entryByIndex(index, InvokeDynamicEntry.class).nameAndType() : cp.entryByIndex(index, MemberRefEntry.class).nameAndType(); - String invokeMethodName = nameAndType.name().stringValue(); - var mDesc = Util.methodTypeSymbol(nameAndType); + var mDesc = Util.methodTypeSymbol(nameAndType.type()); int bci = bcs.bci(); + var currentFrame = this.currentFrame; currentFrame.decStack(Util.parameterSlots(mDesc)); if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) { - if (OBJECT_INITIALIZER_NAME.equals(invokeMethodName)) { + if (nameAndType.name().equalsString(OBJECT_INITIALIZER_NAME)) { Type type = currentFrame.popStack(); if (type == Type.UNITIALIZED_THIS_TYPE) { if (inTryBlock) { @@ -789,9 +777,7 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl currentFrame.initializeObject(type, thisType); thisUninit = true; } else if (type.tag == ITEM_UNINITIALIZED) { - int new_offset = type.bci; - int new_class_index = bcs.getU2(new_offset + 1); - Type new_class_type = cpIndexToType(new_class_index, cp); + Type new_class_type = cpIndexToType(bcs.getU2(type.bci + 1), cp); if (inTryBlock) { processExceptionHandlerTargets(bci, thisUninit); } @@ -800,7 +786,7 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl throw generatorError("Bad operand type when invoking "); } } else { - currentFrame.popStack(); + currentFrame.decStack(); } } currentFrame.pushStack(mDesc.returnType()); @@ -813,10 +799,17 @@ private Type getNewarrayType(int index) { } private void processAnewarray(int index) { - currentFrame.popStack(); + currentFrame.decStack(); currentFrame.pushStack(cpIndexToType(index, cp).toArray()); } + /** + * {@return the generator error with stack underflow} + */ + private IllegalArgumentException stackUnderflow() { + return generatorError("Operand stack underflow"); + } + /** * {@return the generator error with attached details} * @param msg error message @@ -841,18 +834,10 @@ private IllegalArgumentException generatorError(String msg, int offset) { } /** - * Performs detection of mandatory stack map frames offsets - * in a single bytecode traversing pass - * @return java.lang.BitSet of detected frames offsets + * Performs detection of mandatory stack map frames in a single bytecode traversing pass + * @return detected frames */ - private BitSet detectFrameOffsets() { - var offsets = new BitSet() { - @Override - public void set(int i) { - Preconditions.checkIndex(i, bytecode.length(), RawBytecodeHelper.IAE_FORMATTER); - super.set(i); - } - }; + private void detectFrames() { var bcs = bytecode.start(); boolean no_control_flow = false; int opcode, bci = 0; @@ -860,22 +845,22 @@ public void set(int i) { opcode = bcs.opcode(); bci = bcs.bci(); if (no_control_flow) { - offsets.set(bci); + addFrame(bci); } no_control_flow = switch (opcode) { case GOTO -> { - offsets.set(bcs.dest()); + addFrame(bcs.dest()); yield true; } case GOTO_W -> { - offsets.set(bcs.destW()); + addFrame(bcs.destW()); yield true; } case IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ACMPEQ, IF_ACMPNE , IFNULL , IFNONNULL -> { - offsets.set(bcs.dest()); + addFrame(bcs.dest()); yield false; } case TABLESWITCH, LOOKUPSWITCH -> { @@ -891,9 +876,9 @@ public void set(int i) { keys = bcs.getIntUnchecked(aligned_bci + 4); delta = 2; } - offsets.set(bci + default_ofset); + addFrame(bci + default_ofset); for (int i = 0; i < keys; i++) { - offsets.set(bci + bcs.getIntUnchecked(aligned_bci + (3 + i * delta) * 4)); + addFrame(bci + bcs.getIntUnchecked(aligned_bci + (3 + i * delta) * 4)); } yield true; } @@ -904,13 +889,37 @@ public void set(int i) { } catch (IllegalArgumentException iae) { throw generatorError("Detected branch target out of bytecode range", bci); } - for (var exhandler : rawHandlers) try { - offsets.set(exhandler.handler()); + + for (int i = 0; i < rawHandlers.size(); i++) try { + addFrame(rawHandlers.get(i).handler()); } catch (IllegalArgumentException iae) { if (!filterDeadLabels) throw generatorError("Detected exception handler out of bytecode range"); } - return offsets; + } + + private void addFrame(int offset) { + Preconditions.checkIndex(offset, bytecode.length(), RawBytecodeHelper.IAE_FORMATTER); + var frames = this.frames; + int i = 0, framesCount = this.framesCount; + for (; i < framesCount; i++) { + var frameOffset = frames[i].offset; + if (frameOffset == offset) { + return; + } + if (frameOffset > offset) { + break; + } + } + if (framesCount >= frames.length) { + int newCapacity = framesCount + 8; + this.frames = frames = framesCount == 0 ? new Frame[newCapacity] : Arrays.copyOf(frames, newCapacity); + } + if (i != framesCount) { + System.arraycopy(frames, i, frames, i + 1, framesCount - i); + } + frames[i] = new Frame(offset, classHierarchy); + this.framesCount = framesCount + 1; } private final class Frame { @@ -949,44 +958,214 @@ public String toString() { return (dirty ? "frame* @" : "frame @") + offset + " with locals " + (locals == null ? "[]" : Arrays.asList(locals).subList(0, localsSize)) + " and stack " + (stack == null ? "[]" : Arrays.asList(stack).subList(0, stackSize)); } + Frame dup() { + int stackSize = this.stackSize; + if (stackSize < 1) throw stackUnderflow(); + checkStack(stackSize + 1); + stack[stackSize] = stack[stackSize - 1]; + this.stackSize = stackSize + 1; + return this; + } + + Frame dup_x1() { + int stackSize = this.stackSize; + if (stackSize < 2) throw stackUnderflow(); + checkStack(stackSize + 1); + var stack = this.stack; + Type type0 = stack[stackSize - 2]; + Type type1 = stack[stackSize - 1]; + stack[stackSize - 2] = type1; + stack[stackSize - 1] = type0; + stack[stackSize ] = type1; + this.stackSize = stackSize + 1; + return this; + } + + Frame dup_x2() { + int stackSize = this.stackSize; + if (stackSize < 3) throw stackUnderflow(); + checkStack(stackSize + 1); + var stack = this.stack; + Type type0 = stack[stackSize - 3]; + Type type1 = stack[stackSize - 2]; + Type type2 = stack[stackSize - 1]; + stack[stackSize - 3] = type2; + stack[stackSize - 2] = type0; + stack[stackSize - 1] = type1; + stack[stackSize ] = type2; + this.stackSize = stackSize + 1; + return this; + } + + Frame dup2() { + int stackSize = this.stackSize; + if (stackSize < 2) throw stackUnderflow(); + checkStack(stackSize + 2); + stack[stackSize ] = stack[stackSize - 2]; + stack[stackSize + 1] = stack[stackSize - 1]; + this.stackSize = stackSize + 2; + return this; + } + + Frame dup2_x1() { + int stackSize = this.stackSize; + if (stackSize < 3) throw stackUnderflow(); + checkStack(stackSize + 2); + var stack = this.stack; + Type type0 = stack[stackSize - 3]; + Type type1 = stack[stackSize - 2]; + Type type2 = stack[stackSize - 1]; + stack[stackSize - 3] = type1; + stack[stackSize - 2] = type2; + stack[stackSize - 1] = type0; + stack[stackSize ] = type1; + stack[stackSize + 1] = type2; + this.stackSize = stackSize + 2; + return this; + } + + Frame dup2_x2() { + int stackSize = this.stackSize; + if (stackSize < 4) throw stackUnderflow(); + checkStack(stackSize + 2); + var stack = this.stack; + Type type0 = stack[stackSize - 4]; + Type type1 = stack[stackSize - 3]; + Type type2 = stack[stackSize - 2]; + Type type3 = stack[stackSize - 1]; + stack[stackSize - 4] = type2; + stack[stackSize - 3] = type3; + stack[stackSize - 2] = type0; + stack[stackSize - 1] = type1; + stack[stackSize ] = type2; + stack[stackSize + 1] = type3; + this.stackSize = stackSize + 4; + return this; + } + + Frame swap() { + int stackSize = this.stackSize - 2; + if (stackSize < 0) throw stackUnderflow(); + var stack = this.stack; + Type type = stack[stackSize]; + stack[stackSize] = stack[stackSize + 1]; + stack[stackSize + 1] = type; + return this; + } + Frame pushStack(ClassDesc desc) { - return switch (desc.descriptorString().charAt(0)) { - case 'J' -> - pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); - case 'D' -> - pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); - case 'I', 'Z', 'B', 'C', 'S' -> - pushStack(Type.INTEGER_TYPE); - case 'F' -> - pushStack(Type.FLOAT_TYPE); - case 'V' -> - this; - default -> - pushStack(Type.referenceType(desc)); - }; + if (desc == CD_long) return pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + if (desc == CD_double) return pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + return desc == CD_void ? this + : pushStack( + desc.isPrimitive() + ? (desc == CD_float ? Type.FLOAT_TYPE : Type.INTEGER_TYPE) + : Type.referenceType(desc)); + } + + Frame dec1PushStack(ClassDesc desc) { + if (desc == CD_long) return decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + if (desc == CD_double) return decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + return desc == CD_void ? this + : decStack1PushStack( + desc.isPrimitive() + ? (desc == CD_float ? Type.FLOAT_TYPE : Type.INTEGER_TYPE) + : Type.referenceType(desc)); } Frame pushStack(Type type) { + int stackSize = this.stackSize; checkStack(stackSize); - stack[stackSize++] = type; + stack[stackSize] = type; + this.stackSize = stackSize + 1; return this; } Frame pushStack(Type type1, Type type2) { + int stackSize = this.stackSize; checkStack(stackSize + 1); - stack[stackSize++] = type1; - stack[stackSize++] = type2; + stack[stackSize] = type1; + stack[stackSize + 1] = type2; + this.stackSize = stackSize + 2; return this; } Type popStack() { - if (stackSize < 1) throw generatorError("Operand stack underflow"); - return stack[--stackSize]; + int stackSize = this.stackSize - 1; + if (stackSize < 0) throw stackUnderflow(); + this.stackSize = stackSize; + return stack[stackSize]; + } + + Frame decStack() { + if (--stackSize < 0) throw stackUnderflow(); + return this; } Frame decStack(int size) { stackSize -= size; - if (stackSize < 0) throw generatorError("Operand stack underflow"); + if (stackSize < 0) throw stackUnderflow(); + return this; + } + + Frame decStack1PushStack(Type type1, Type type2) { + int stackSize = this.stackSize - 1; + if (stackSize < 0) throw stackUnderflow(); + checkStack(stackSize + 2); + stack[stackSize ] = type1; + stack[stackSize + 1] = type2; + this.stackSize = stackSize + 2; + return this; + } + + Frame decStack1PushStack(Type type) { + int stackSize = this.stackSize - 1; + if (stackSize < 0) throw stackUnderflow(); + stack[stackSize] = type; + return this; + } + + Frame decStack2PushStack(Type type) { + int stackSize = this.stackSize - 2; + if (stackSize < 0) throw stackUnderflow(); + stack[stackSize] = type; + this.stackSize = stackSize + 1; + return this; + } + + Frame decStack2PushStack(Type type1, Type type2) { + int stackSize = this.stackSize - 2; + if (stackSize < 0) throw stackUnderflow(); + var stack = this.stack; + stack[stackSize ] = type1; + stack[stackSize + 1] = type2; + return this; + } + + Frame decStack3PushStack(Type type1, Type type2) { + int stackSize = this.stackSize - 3; + if (stackSize < 0) throw stackUnderflow(); + stack[stackSize ] = type1; + stack[stackSize + 1] = type2; + this.stackSize = stackSize + 2; + return this; + } + + Frame decStack4PushStack(Type type) { + int stackSize = this.stackSize - 4; + if (stackSize < 0) throw stackUnderflow(); + stack[stackSize] = type; + this.stackSize = stackSize + 1; + return this; + } + + Frame decStack4PushStack(Type type1, Type type2) { + int stackSize = this.stackSize - 4; + if (stackSize < 0) throw stackUnderflow(); + var stack = this.stack; + stack[stackSize ] = type1; + stack[stackSize + 1] = type2; + this.stackSize = stackSize + 2; return this; } @@ -1015,34 +1194,59 @@ void initializeObject(Type old_object, Type new_object) { Frame checkLocal(int index) { if (index >= frameMaxLocals) frameMaxLocals = index + 1; if (locals == null) { - locals = new Type[index + FRAME_DEFAULT_CAPACITY]; - Arrays.fill(locals, Type.TOP_TYPE); + initLocals(index); } else if (index >= locals.length) { - int current = locals.length; - locals = Arrays.copyOf(locals, index + FRAME_DEFAULT_CAPACITY); - Arrays.fill(locals, current, locals.length, Type.TOP_TYPE); + growLocals(index); } return this; } + private void initLocals(int index) { + locals = new Type[index + FRAME_DEFAULT_CAPACITY]; + Arrays.fill(locals, Type.TOP_TYPE); + } + + private void growLocals(int index) { + int current = locals.length; + locals = Arrays.copyOf(locals, index + FRAME_DEFAULT_CAPACITY); + Arrays.fill(locals, current, locals.length, Type.TOP_TYPE); + } + private void checkStack(int index) { if (index >= frameMaxStack) frameMaxStack = index + 1; if (stack == null) { - stack = new Type[index + FRAME_DEFAULT_CAPACITY]; - Arrays.fill(stack, Type.TOP_TYPE); + initStack(index); } else if (index >= stack.length) { - int current = stack.length; - stack = Arrays.copyOf(stack, index + FRAME_DEFAULT_CAPACITY); - Arrays.fill(stack, current, stack.length, Type.TOP_TYPE); + growStack(index); } } + private void initStack(int index) { + stack = new Type[index + FRAME_DEFAULT_CAPACITY]; + Arrays.fill(stack, Type.TOP_TYPE); + } + + private void growStack(int index) { + int current = stack.length; + stack = Arrays.copyOf(stack, index + FRAME_DEFAULT_CAPACITY); + Arrays.fill(stack, current, stack.length, Type.TOP_TYPE); + } + private void setLocalRawInternal(int index, Type type) { checkLocal(index); + var locals = this.locals; localsChanged |= !type.equals(locals[index]); locals[index] = type; } + private void setLocalRawInternal(int index, Type type1, Type type2) { + checkLocal(index + 1); + var locals = this.locals; + localsChanged |= !type1.equals(locals[index]) || !type2.equals(locals[index + 1]); + locals[index ] = type1; + locals[index + 1] = type2; + } + void setLocalsFromArg(String name, MethodTypeDesc methodDesc, boolean isStatic, Type thisKlass) { int localsSize = 0; // Pre-emptively create a locals array that encompass all parameter slots @@ -1069,7 +1273,7 @@ void setLocalsFromArg(String name, MethodTypeDesc methodDesc, boolean isStatic, locals[localsSize + 1] = Type.DOUBLE2_TYPE; localsSize += 2; } else { - if (desc instanceof ReferenceClassDescImpl) { + if (!desc.isPrimitive()) { type = Type.referenceType(desc); } else if (desc == CD_float) { type = Type.FLOAT_TYPE; @@ -1143,8 +1347,7 @@ void setLocal(int index, Type type) { Type old = getLocalRawInternal(index); if (old == Type.DOUBLE_TYPE || old == Type.LONG_TYPE) { setLocalRawInternal(index + 1, Type.TOP_TYPE); - } - if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) { + } else if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) { setLocalRawInternal(index - 1, Type.TOP_TYPE); } setLocalRawInternal(index, type); @@ -1162,8 +1365,7 @@ void setLocal2(int index, Type type1, Type type2) { if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) { setLocalRawInternal(index - 1, Type.TOP_TYPE); } - setLocalRawInternal(index, type1); - setLocalRawInternal(index + 1, type2); + setLocalRawInternal(index, type1, type2); if (index >= localsSize - 1) { localsSize = index + 2; } @@ -1184,7 +1386,10 @@ private static int trimAndCompress(Type[] types, int count) { int compressed = 0; for (int i = 0; i < count; i++) { if (!types[i].isCategory2_2nd()) { - types[compressed++] = types[i]; + if (compressed != i) { + types[compressed] = types[i]; + } + compressed++; } } return compressed; @@ -1200,7 +1405,9 @@ private static boolean equals(Type[] l1, Type[] l2, int commonSize) { return Arrays.equals(l1, 0, commonSize, l2, 0, commonSize); } - void writeTo(BufWriter out, Frame prevFrame, ConstantPoolBuilder cp) { + void writeTo(BufWriterImpl out, Frame prevFrame, ConstantPoolBuilder cp) { + int localsSize = this.localsSize; + int stackSize = this.stackSize; int offsetDelta = offset - prevFrame.offset - 1; if (stackSize == 0) { int commonLocalsSize = localsSize > prevFrame.localsSize ? prevFrame.localsSize : localsSize; @@ -1209,8 +1416,7 @@ void writeTo(BufWriter out, Frame prevFrame, ConstantPoolBuilder cp) { if (diffLocalsSize == 0 && offsetDelta < 64) { //same frame out.writeU1(offsetDelta); } else { //chop, same extended or append frame - out.writeU1(251 + diffLocalsSize); - out.writeU2(offsetDelta); + out.writeU1U2(251 + diffLocalsSize, offsetDelta); for (int i=commonLocalsSize; i - bw.writeU2(cp.classEntry(sym).index()); + bw.writeU1U2(tag, cp.classEntry(sym).index()); case ITEM_UNINITIALIZED -> - bw.writeU2(bci); + bw.writeU1U2(tag, bci); + default -> + bw.writeU1(tag); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SuperclassImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SuperclassImpl.java index 2e93c9b9d82ed..b30a1089f2643 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SuperclassImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SuperclassImpl.java @@ -24,8 +24,8 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.Superclass; +import java.lang.classfile.constantpool.ClassEntry; import static java.util.Objects.requireNonNull; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java index b2d5cd9f62c84..07aa3c8d8c88c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.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 @@ -24,10 +24,9 @@ */ package jdk.internal.classfile.impl; -import java.util.List; -import java.util.Objects; import java.lang.classfile.Label; import java.lang.classfile.TypeAnnotation.*; +import java.util.List; import static java.util.Objects.requireNonNull; @@ -37,7 +36,6 @@ private TargetInfoImpl() { } private static TargetType checkValid(TargetType targetType, int rangeFrom, int rangeTo) { - Objects.requireNonNull(targetType); if (targetType.targetTypeValue() < rangeFrom || targetType.targetTypeValue() > rangeTo) throw new IllegalArgumentException("Wrong target type specified " + targetType); return targetType; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java index 784e844b712f2..83faf9c8802db 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java @@ -24,32 +24,11 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.*; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.constantpool.ConstantDynamicEntry; -import java.lang.classfile.constantpool.ConstantPool; -import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.constantpool.DoubleEntry; -import java.lang.classfile.constantpool.FieldRefEntry; -import java.lang.classfile.constantpool.FloatEntry; -import java.lang.classfile.constantpool.IntegerEntry; -import java.lang.classfile.constantpool.InterfaceMethodRefEntry; -import java.lang.classfile.constantpool.InvokeDynamicEntry; -import java.lang.classfile.constantpool.LoadableConstantEntry; -import java.lang.classfile.constantpool.LongEntry; -import java.lang.classfile.constantpool.MemberRefEntry; -import java.lang.classfile.constantpool.MethodHandleEntry; -import java.lang.classfile.constantpool.MethodRefEntry; -import java.lang.classfile.constantpool.MethodTypeEntry; -import java.lang.classfile.constantpool.ModuleEntry; -import java.lang.classfile.constantpool.NameAndTypeEntry; -import java.lang.classfile.constantpool.PackageEntry; -import java.lang.classfile.constantpool.PoolEntry; -import java.lang.classfile.constantpool.StringEntry; -import java.lang.classfile.constantpool.Utf8Entry; - +import java.lang.classfile.BootstrapMethodEntry; +import java.lang.classfile.constantpool.*; import java.lang.constant.MethodTypeDesc; import java.util.List; +import java.util.Objects; public final class TemporaryConstantPool implements ConstantPoolBuilder { @@ -187,6 +166,7 @@ public int bootstrapMethodCount() { @Override public boolean canWriteDirect(ConstantPool constantPool) { + Objects.requireNonNull(constantPool); return false; } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java index 8478b1a51f035..23387fcb098d0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java @@ -24,29 +24,11 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.ClassFileBuilder; -import java.lang.classfile.ClassFileTransform; +import java.lang.classfile.*; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; -import java.lang.classfile.ClassBuilder; -import java.lang.classfile.ClassElement; -import java.lang.classfile.ClassTransform; -import java.lang.classfile.ClassFileElement; -import java.lang.classfile.CodeBuilder; -import java.lang.classfile.CodeElement; -import java.lang.classfile.CodeModel; -import java.lang.classfile.CodeTransform; -import java.lang.classfile.FieldBuilder; -import java.lang.classfile.FieldElement; -import java.lang.classfile.FieldModel; -import java.lang.classfile.FieldTransform; -import java.lang.classfile.MethodBuilder; -import java.lang.classfile.MethodElement; -import java.lang.classfile.MethodModel; -import java.lang.classfile.MethodTransform; - public final class TransformImpl { // ClassTransform diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 3119cfa0f4953..dfad66a897c27 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -24,74 +24,22 @@ */ package jdk.internal.classfile.impl; -import java.util.Collection; -import java.util.List; -import java.util.Optional; - -import java.lang.classfile.Annotation; -import java.lang.classfile.AnnotationValue; -import java.lang.classfile.Attribute; -import java.lang.classfile.AttributeMapper; -import java.lang.classfile.Attributes; -import java.lang.classfile.BootstrapMethodEntry; +import java.lang.classfile.*; +import java.lang.classfile.attribute.*; import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.TypeAnnotation; -import java.lang.classfile.attribute.AnnotationDefaultAttribute; -import java.lang.classfile.attribute.BootstrapMethodsAttribute; -import java.lang.classfile.attribute.CharacterRangeInfo; -import java.lang.classfile.attribute.CharacterRangeTableAttribute; -import java.lang.classfile.attribute.CompilationIDAttribute; -import java.lang.classfile.attribute.ConstantValueAttribute; -import java.lang.classfile.attribute.DeprecatedAttribute; -import java.lang.classfile.attribute.EnclosingMethodAttribute; -import java.lang.classfile.attribute.ExceptionsAttribute; -import java.lang.classfile.attribute.InnerClassInfo; -import java.lang.classfile.attribute.InnerClassesAttribute; -import java.lang.classfile.attribute.LineNumberInfo; -import java.lang.classfile.attribute.LineNumberTableAttribute; -import java.lang.classfile.attribute.LocalVariableInfo; -import java.lang.classfile.attribute.LocalVariableTableAttribute; -import java.lang.classfile.attribute.LocalVariableTypeInfo; -import java.lang.classfile.attribute.LocalVariableTypeTableAttribute; -import java.lang.classfile.attribute.MethodParameterInfo; -import java.lang.classfile.attribute.MethodParametersAttribute; -import java.lang.classfile.attribute.ModuleAttribute; -import java.lang.classfile.attribute.ModuleExportInfo; -import java.lang.classfile.attribute.ModuleHashInfo; -import java.lang.classfile.attribute.ModuleHashesAttribute; -import java.lang.classfile.attribute.ModuleMainClassAttribute; -import java.lang.classfile.attribute.ModuleOpenInfo; -import java.lang.classfile.attribute.ModulePackagesAttribute; -import java.lang.classfile.attribute.ModuleProvideInfo; -import java.lang.classfile.attribute.ModuleRequireInfo; -import java.lang.classfile.attribute.ModuleResolutionAttribute; -import java.lang.classfile.attribute.ModuleTargetAttribute; -import java.lang.classfile.attribute.NestHostAttribute; -import java.lang.classfile.attribute.NestMembersAttribute; -import java.lang.classfile.attribute.PermittedSubclassesAttribute; -import java.lang.classfile.attribute.RecordAttribute; -import java.lang.classfile.attribute.RecordComponentInfo; -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.SignatureAttribute; -import java.lang.classfile.attribute.SourceDebugExtensionAttribute; -import java.lang.classfile.attribute.SourceFileAttribute; -import java.lang.classfile.attribute.SourceIDAttribute; -import java.lang.classfile.attribute.StackMapTableAttribute; -import java.lang.classfile.attribute.StackMapFrameInfo; -import java.lang.classfile.attribute.SyntheticAttribute; import java.lang.classfile.constantpool.ConstantValueEntry; import java.lang.classfile.constantpool.ModuleEntry; import java.lang.classfile.constantpool.NameAndTypeEntry; import java.lang.classfile.constantpool.PackageEntry; import java.lang.classfile.constantpool.Utf8Entry; +import java.util.Collection; +import java.util.List; +import java.util.Optional; import jdk.internal.access.SharedSecrets; +import static java.util.Objects.requireNonNull; + public abstract sealed class UnboundAttribute> extends AbstractElement implements Attribute, Util.Writable { @@ -149,7 +97,7 @@ public static final class UnboundConstantValueAttribute public UnboundConstantValueAttribute(ConstantValueEntry entry) { super(Attributes.constantValue()); - this.entry = entry; + this.entry = requireNonNull(entry); } @Override @@ -182,7 +130,7 @@ public static final class UnboundSignatureAttribute public UnboundSignatureAttribute(Utf8Entry signature) { super(Attributes.signature()); - this.signature = signature; + this.signature = requireNonNull(signature); } @Override @@ -214,7 +162,7 @@ public static final class UnboundAnnotationDefaultAttribute public UnboundAnnotationDefaultAttribute(AnnotationValue annotationDefault) { super(Attributes.annotationDefault()); - this.annotationDefault = annotationDefault; + this.annotationDefault = requireNonNull(annotationDefault); } @Override @@ -229,7 +177,7 @@ public static final class UnboundSourceFileAttribute extends UnboundAttribute hashes) { super(Attributes.moduleHashes()); - this.algorithm = algorithm; + this.algorithm = requireNonNull(algorithm); this.hashes = List.copyOf(hashes); } @@ -451,7 +399,7 @@ public static final class UnboundNestHostAttribute public UnboundNestHostAttribute(ClassEntry hostEntry) { super(Attributes.nestHost()); - this.hostEntry = hostEntry; + this.hostEntry = requireNonNull(hostEntry); } @Override @@ -467,7 +415,7 @@ public static final class UnboundCompilationIDAttribute public UnboundCompilationIDAttribute(Utf8Entry idEntry) { super(Attributes.compilationId()); - this.idEntry = idEntry; + this.idEntry = requireNonNull(idEntry); } @Override @@ -483,7 +431,7 @@ public static final class UnboundSourceIDAttribute public UnboundSourceIDAttribute(Utf8Entry idEntry) { super(Attributes.sourceId()); - this.idEntry = idEntry; + this.idEntry = requireNonNull(idEntry); } @Override @@ -499,7 +447,7 @@ public static final class UnboundSourceDebugExtensionAttribute public UnboundSourceDebugExtensionAttribute(byte[] contents) { super(Attributes.sourceDebugExtension()); - this.contents = contents; + this.contents = requireNonNull(contents); } @Override @@ -611,7 +559,13 @@ public static final class UnboundRuntimeVisibleParameterAnnotationsAttribute public UnboundRuntimeVisibleParameterAnnotationsAttribute(List> elements) { super(Attributes.runtimeVisibleParameterAnnotations()); - this.elements = List.copyOf(elements); + // deep copy + var array = elements.toArray().clone(); + for (int i = 0; i < array.length; i++) { + array[i] = List.copyOf((List) array[i]); + } + + this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array); } @Override @@ -684,7 +638,13 @@ public record UnboundInnerClassInfo(ClassEntry innerClass, Optional outerClass, Optional innerName, int flagsMask) - implements InnerClassInfo {} + implements InnerClassInfo { + public UnboundInnerClassInfo { + requireNonNull(innerClass); + requireNonNull(outerClass); + requireNonNull(innerName); + } + } public record UnboundLineNumberInfo(int startPc, int lineNumber) implements LineNumberInfo { } @@ -693,64 +653,84 @@ public record UnboundLocalVariableInfo(int startPc, int length, Utf8Entry name, Utf8Entry type, int slot) - implements LocalVariableInfo { } + implements LocalVariableInfo { + public UnboundLocalVariableInfo { + requireNonNull(name); + requireNonNull(type); + } + } public record UnboundLocalVariableTypeInfo(int startPc, int length, Utf8Entry name, Utf8Entry signature, int slot) - implements LocalVariableTypeInfo { } + implements LocalVariableTypeInfo { + public UnboundLocalVariableTypeInfo { + requireNonNull(name); + requireNonNull(signature); + } + } public record UnboundMethodParameterInfo(Optional name, int flagsMask) - implements MethodParameterInfo {} + implements MethodParameterInfo { + public UnboundMethodParameterInfo { + requireNonNull(name); + } + } public record UnboundModuleExportInfo(PackageEntry exportedPackage, int exportsFlagsMask, List exportsTo) implements ModuleExportInfo { - public UnboundModuleExportInfo(PackageEntry exportedPackage, int exportsFlagsMask, - List exportsTo) { - this.exportedPackage = exportedPackage; - this.exportsFlagsMask = exportsFlagsMask; - this.exportsTo = List.copyOf(exportsTo); + public UnboundModuleExportInfo { + requireNonNull(exportedPackage); + exportsTo = List.copyOf(exportsTo); } } public record UnboundModuleHashInfo(ModuleEntry moduleName, - byte[] hash) implements ModuleHashInfo { } + byte[] hash) implements ModuleHashInfo { + public UnboundModuleHashInfo { + requireNonNull(moduleName); + requireNonNull(hash); + } + } public record UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask, List opensTo) implements ModuleOpenInfo { - public UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask, - List opensTo) { - this.openedPackage = openedPackage; - this.opensFlagsMask = opensFlagsMask; - this.opensTo = List.copyOf(opensTo); + public UnboundModuleOpenInfo { + requireNonNull(openedPackage); + opensTo = List.copyOf(opensTo); } } public record UnboundModuleProvideInfo(ClassEntry provides, List providesWith) implements ModuleProvideInfo { - public UnboundModuleProvideInfo(ClassEntry provides, List providesWith) { - this.provides = provides; - this.providesWith = List.copyOf(providesWith); + public UnboundModuleProvideInfo { + requireNonNull(provides); + providesWith = List.copyOf(providesWith); } } public record UnboundModuleRequiresInfo(ModuleEntry requires, int requiresFlagsMask, Optional requiresVersion) - implements ModuleRequireInfo {} + implements ModuleRequireInfo { + public UnboundModuleRequiresInfo { + requireNonNull(requires); + requireNonNull(requiresVersion); + } + } public record UnboundRecordComponentInfo(Utf8Entry name, Utf8Entry descriptor, List> attributes) implements RecordComponentInfo { - public UnboundRecordComponentInfo(Utf8Entry name, Utf8Entry descriptor, List> attributes) { - this.name = name; - this.descriptor = descriptor; - this.attributes = List.copyOf(attributes); + public UnboundRecordComponentInfo { + requireNonNull(name); + requireNonNull(descriptor); + attributes = List.copyOf(attributes); } } @@ -759,7 +739,9 @@ public record UnboundTypeAnnotation(TargetInfo targetInfo, Annotation annotation) implements TypeAnnotation { public UnboundTypeAnnotation { + requireNonNull(targetInfo); targetPath = List.copyOf(targetPath); + requireNonNull(annotation); } } @@ -786,7 +768,7 @@ public UnboundModuleAttribute(ModuleEntry moduleName, Collection provides) { super(Attributes.module()); - this.moduleName = moduleName; + this.moduleName = requireNonNull(moduleName); this.moduleFlags = moduleFlags; this.moduleVersion = moduleVersion; this.requires = List.copyOf(requires); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index e1e3f6fb3d2b4..1088724d8b4a3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -24,40 +24,29 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.CodeBuilder; -import java.lang.classfile.CustomAttribute; -import java.lang.classfile.FieldBuilder; -import java.lang.classfile.MethodBuilder; -import java.lang.classfile.PseudoInstruction; +import java.lang.classfile.*; +import java.lang.classfile.attribute.CodeAttribute; +import java.lang.classfile.components.ClassPrinter; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ModuleEntry; import java.lang.classfile.constantpool.PoolEntry; import java.lang.classfile.constantpool.Utf8Entry; import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; +import java.lang.constant.ModuleDesc; +import java.lang.reflect.AccessFlag; import java.util.AbstractList; import java.util.Collection; import java.util.List; +import java.util.function.Consumer; import java.util.function.Function; -import java.lang.classfile.Attribute; -import java.lang.classfile.AttributeMapper; -import java.lang.classfile.Attributes; -import java.lang.classfile.BufWriter; -import java.lang.classfile.ClassFile; -import java.lang.classfile.Opcode; -import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.constantpool.ModuleEntry; -import java.lang.classfile.constantpool.NameAndTypeEntry; -import java.lang.constant.ModuleDesc; -import java.lang.reflect.AccessFlag; import jdk.internal.access.SharedSecrets; +import jdk.internal.constant.ClassOrInterfaceDescImpl; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Stable; import static java.lang.classfile.ClassFile.ACC_STATIC; -import java.lang.classfile.attribute.CodeAttribute; -import java.lang.classfile.components.ClassPrinter; -import java.util.function.Consumer; - import static jdk.internal.constant.PrimitiveClassDescImpl.CD_double; import static jdk.internal.constant.PrimitiveClassDescImpl.CD_long; import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void; @@ -145,10 +134,10 @@ public static String toBinaryName(ClassDesc cd) { } public static String toInternalName(ClassDesc cd) { - var desc = cd.descriptorString(); - if (desc.charAt(0) == 'L') - return desc.substring(1, desc.length() - 1); - throw new IllegalArgumentException(desc); + if (cd instanceof ClassOrInterfaceDescImpl coi) { + return coi.internalName(); + } + throw new IllegalArgumentException(cd.descriptorString()); } public static ClassDesc toClassDesc(String classInternalNameOrArrayDesc) { @@ -231,16 +220,8 @@ public static MethodTypeDesc methodTypeSymbol(Utf8Entry utf8) { return ((AbstractPoolEntry.Utf8EntryImpl) utf8).methodTypeSymbol(); } - public static ClassDesc fieldTypeSymbol(NameAndTypeEntry nat) { - return fieldTypeSymbol(nat.type()); - } - - public static MethodTypeDesc methodTypeSymbol(NameAndTypeEntry nat) { - return methodTypeSymbol(nat.type()); - } - @SuppressWarnings("unchecked") - private static > void writeAttribute(BufWriterImpl writer, Attribute attr) { + public static > void writeAttribute(BufWriterImpl writer, Attribute attr) { if (attr instanceof CustomAttribute ca) { var mapper = (AttributeMapper) ca.attributeMapper(); mapper.writeAttribute(writer, (T) ca); @@ -260,11 +241,10 @@ public static void writeAttributes(BufWriterImpl buf, List list) { - int size = list.size(); + static void writeList(BufWriterImpl buf, Writable[] array, int size) { buf.writeU2(size); for (int i = 0; i < size; i++) { - list.get(i).writeTo(buf); + array[i].writeTo(buf); } } @@ -296,12 +276,10 @@ public static void dumpMethod(SplitConstantPool cp, ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override public void writeBody(BufWriterImpl b) { - b.writeU2(-1);//max stack - b.writeU2(-1);//max locals + b.writeU2U2(-1, -1);//max stack & locals b.writeInt(bytecode.length()); b.writeBytes(bytecode.array(), 0, bytecode.length()); - b.writeU2(0);//exception handlers - b.writeU2(0);//attributes + b.writeU2U2(0, 0);//exception handlers & attributes } })))); ClassPrinter.toYaml(clm.methods().get(0).code().get(), ClassPrinter.Verbosity.TRACE_ALL, dump); @@ -344,15 +322,6 @@ interface WritableLocalVariable { boolean writeLocalTo(BufWriterImpl buf); } - /** - * Returns the hash code of an internal name given the class or interface L descriptor. - */ - public static int internalNameHash(String desc) { - if (desc.length() > 0xffff) - throw new IllegalArgumentException("String too long: ".concat(Integer.toString(desc.length()))); - return (desc.hashCode() - pow31(desc.length() - 1) * 'L' - ';') * INVERSE_31; - } - /** * Returns the hash code of a class or interface L descriptor given the internal name. */ @@ -409,6 +378,7 @@ public static int pow31(int k) { 0x54fbc001, 0xb9f78001, 0x2ef34001, 0xb3ef0001, 0x48eac001, 0xede68001, 0xa2e24001, 0x67de0001, 0xcfbc0001, 0x379a0001, 0x9f780001, 0x07560001, 0x6f340001, 0xd7120001, 0x3ef00001, 0x7de00001, 0xbcd00001, 0xfbc00001, 0x3ab00001, 0x79a00001, 0xb8900001, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static int powersIndex(int digit, int index) { @@ -419,6 +389,6 @@ static int powersIndex(int digit, int index) { // digit: 0 - 7 // index: 0 - SIGNIFICANT_OCTAL_DIGITS - 1 private static int powerOctal(int digit, int index) { - return digit == 0 ? 1 : powers[powersIndex(digit, index)]; + return digit == 0 ? 1 : powers[powersIndex(digit, index) & 0x3F]; // & 0x3F eliminates bound check } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java index ed735b41e0e78..521d74ae1332f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java @@ -24,38 +24,27 @@ */ package jdk.internal.classfile.impl.verifier; -import java.lang.classfile.Annotation; -import java.lang.classfile.AnnotationValue; -import java.lang.constant.ClassDesc; -import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME; -import static java.lang.constant.ConstantDescs.INIT_NAME; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.lang.classfile.Attribute; -import java.lang.classfile.AttributedElement; -import java.lang.classfile.Attributes; -import java.lang.classfile.ClassModel; -import java.lang.classfile.ClassFileElement; -import java.lang.classfile.CodeModel; -import java.lang.classfile.CompoundElement; -import java.lang.classfile.CustomAttribute; -import java.lang.classfile.FieldModel; -import java.lang.classfile.MethodModel; -import java.lang.classfile.TypeAnnotation; -import java.lang.classfile.TypeKind; +import java.lang.classfile.*; import java.lang.classfile.attribute.*; import java.lang.classfile.constantpool.*; +import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.reflect.AccessFlag; +import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.ToIntFunction; +import java.util.stream.Collectors; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.Util; +import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME; +import static java.lang.constant.ConstantDescs.INIT_NAME; + /** * ParserVerifier performs selected checks of the class file format according to * {@jvms 4.8 Format Checking} diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java index 5aed968c6aefc..b12ec5101f5e5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java @@ -24,9 +24,9 @@ */ package jdk.internal.classfile.impl.verifier; -import static jdk.internal.classfile.impl.RawBytecodeHelper.*; - import jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType; + +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*; /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java index db07e0aa45b96..af009297405e5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java @@ -24,7 +24,9 @@ */ package jdk.internal.classfile.impl.verifier; -import static jdk.internal.classfile.impl.verifier.VerificationType.*; +import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Object; +import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Uninitialized; +import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_UninitializedThis; /** * @see hotspot/share/classfile/stackMapTable.hpp diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java index a2ecda88438a1..ff29d931332f5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java @@ -29,10 +29,11 @@ import java.util.IdentityHashMap; import java.util.Map; import java.util.Objects; + import jdk.internal.classfile.impl.ClassHierarchyImpl; import jdk.internal.classfile.impl.Util; + import static jdk.internal.classfile.impl.verifier.VerifierImpl.*; -import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*; /** * @see hotspot/share/classfile/verificationType.hpp diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java index d34f579b1f4f3..c76d0789244b0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java @@ -25,21 +25,21 @@ */ package jdk.internal.classfile.impl.verifier; -import java.lang.constant.ClassDesc; -import java.util.LinkedList; -import java.util.List; - +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassModel; +import java.lang.classfile.MethodModel; +import java.lang.classfile.attribute.LocalVariableInfo; import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.DynamicConstantPoolEntry; import java.lang.classfile.constantpool.MemberRefEntry; import java.lang.classfile.constantpool.NameAndTypeEntry; +import java.lang.constant.ClassDesc; import java.lang.reflect.AccessFlag; +import java.util.LinkedList; +import java.util.List; import java.util.stream.Collectors; -import java.lang.classfile.ClassModel; -import java.lang.classfile.constantpool.ConstantPool; -import java.lang.classfile.MethodModel; -import java.lang.classfile.attribute.LocalVariableInfo; -import java.lang.classfile.Attributes; + import jdk.internal.classfile.impl.BoundAttribute; import jdk.internal.classfile.impl.CodeImpl; import jdk.internal.classfile.impl.Util; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java index f41647788a175..ed93ff1fc5d67 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java @@ -24,20 +24,23 @@ */ package jdk.internal.classfile.impl.verifier; +import java.lang.classfile.ClassHierarchyResolver; +import java.lang.classfile.ClassModel; +import java.lang.classfile.components.ClassPrinter; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Consumer; -import java.lang.classfile.ClassHierarchyResolver; -import java.lang.classfile.ClassModel; -import java.lang.classfile.components.ClassPrinter; + import jdk.internal.classfile.impl.ClassHierarchyImpl; import jdk.internal.classfile.impl.RawBytecodeHelper; -import static jdk.internal.classfile.impl.RawBytecodeHelper.*; -import jdk.internal.classfile.impl.verifier.VerificationWrapper.ConstantPoolWrapper; -import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*; import jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType; +import jdk.internal.classfile.impl.verifier.VerificationWrapper.ConstantPoolWrapper; + +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; import static jdk.internal.classfile.impl.verifier.VerificationFrame.FLAG_THIS_UNINIT; +import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.T_BOOLEAN; +import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.T_LONG; /** * VerifierImpl performs selected checks and verifications of the class file diff --git a/src/java.base/share/classes/jdk/internal/constant/ArrayClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ArrayClassDescImpl.java new file mode 100644 index 0000000000000..763975cb76b27 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/constant/ArrayClassDescImpl.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.constant; + +import java.lang.constant.ClassDesc; +import java.lang.invoke.MethodHandles; + +import jdk.internal.vm.annotation.Stable; +import sun.invoke.util.Wrapper; + +import static java.lang.constant.ConstantDescs.CD_void; +import static jdk.internal.constant.ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS; + +/** + * An array class descriptor. + * Restrictions:
            + *
          • {@code rank} must be in {@code [1, 255]} + *
          • {@code element} must not be void or array + *
          + */ +public final class ArrayClassDescImpl implements ClassDesc { + private final ClassDesc elementType; + private final int rank; + private @Stable String cachedDescriptorString; + + public static ArrayClassDescImpl ofValidatedDescriptor(String desc) { + assert desc.charAt(0) == '['; + var lastChar = desc.charAt(desc.length() - 1); + ArrayClassDescImpl ret; + if (lastChar != ';') { + // Primitive element arrays + ret = ofValidated(Wrapper.forBasicType(lastChar).basicClassDescriptor(), desc.length() - 1); + } else { + int level = ConstantUtils.arrayDepth(desc, 0); + ret = ofValidated(ClassOrInterfaceDescImpl.ofValidated(desc.substring(level)), level); + } + ret.cachedDescriptorString = desc; + return ret; + } + + public static ArrayClassDescImpl ofValidated(ClassDesc elementType, int rank) { + assert !elementType.isArray() && elementType != CD_void; + assert rank > 0 && rank <= MAX_ARRAY_TYPE_DESC_DIMENSIONS; + + return new ArrayClassDescImpl(elementType, rank); + } + + private ArrayClassDescImpl(ClassDesc elementType, int rank) { + this.elementType = elementType; + this.rank = rank; + } + + @Override + public ClassDesc arrayType() { + int rank = this.rank + 1; + if (rank > MAX_ARRAY_TYPE_DESC_DIMENSIONS) + throw new IllegalStateException(ConstantUtils.invalidArrayRankMessage(rank)); + return new ArrayClassDescImpl(elementType, rank); + } + + @Override + public ClassDesc arrayType(int rank) { + if (rank <= 0) { + throw new IllegalArgumentException("rank " + rank + " is not a positive value"); + } + rank += this.rank; + ConstantUtils.validateArrayRank(rank); + return new ArrayClassDescImpl(elementType, rank); + } + + @Override + public boolean isArray() { + return true; + } + + @Override + public ClassDesc componentType() { + return rank == 1 ? elementType : new ArrayClassDescImpl(elementType, rank - 1); + } + + @Override + public String displayName() { + return elementType.displayName() + "[]".repeat(rank); + } + + @Override + public String descriptorString() { + var desc = cachedDescriptorString; + if (desc != null) + return desc; + + return cachedDescriptorString = computeDescriptor(); + } + + private String computeDescriptor() { + var componentDesc = elementType.descriptorString(); + StringBuilder sb = new StringBuilder(rank + componentDesc.length()); + sb.repeat('[', rank); + sb.append(componentDesc); + return sb.toString(); + } + + @Override + public Class resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException { + if (elementType.isPrimitive()) { + return lookup.findClass(descriptorString()); + } + // Class.forName is slow on class or interface arrays + Class clazz = elementType.resolveConstantDesc(lookup); + for (int i = 0; i < rank; i++) + clazz = clazz.arrayType(); + return clazz; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof ArrayClassDescImpl constant) { + return elementType.equals(constant.elementType) && rank == constant.rank; + } + return false; + } + + @Override + public int hashCode() { + return descriptorString().hashCode(); + } + + @Override + public String toString() { + return String.format("ArrayClassDesc[%s, %d]", elementType.displayName(), rank); + } +} diff --git a/src/java.base/share/classes/jdk/internal/constant/ClassOrInterfaceDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ClassOrInterfaceDescImpl.java new file mode 100644 index 0000000000000..dcdb2cff8b5a3 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/constant/ClassOrInterfaceDescImpl.java @@ -0,0 +1,162 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.constant; + +import java.lang.constant.ClassDesc; +import java.lang.invoke.MethodHandles; + +import jdk.internal.vm.annotation.Stable; + +import static jdk.internal.constant.ConstantUtils.*; + +/** + * A class or interface descriptor. + * Restrictions: + *
            + *
          • Starts with 'L' + *
          • Ends with ';' + *
          • No '.' or '[' or ';' in the middle + *
          • No leading/trailing/consecutive '/' + *
          + */ +public final class ClassOrInterfaceDescImpl implements ClassDesc { + private final String descriptor; + private @Stable String internalName; + + /** + * Creates a {@linkplain ClassOrInterfaceDescImpl} from a pre-validated descriptor string + * for a class or interface. + */ + public static ClassOrInterfaceDescImpl ofValidated(String descriptor) { + assert ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length()) + == descriptor.length() : descriptor; + assert descriptor.charAt(0) == 'L'; + return new ClassOrInterfaceDescImpl(descriptor); + } + + ClassOrInterfaceDescImpl(String descriptor) { + this.descriptor = descriptor; + } + + public String internalName() { + var internalName = this.internalName; + if (internalName == null) { + this.internalName = internalName = dropFirstAndLastChar(descriptor); + } + return internalName; + } + + @Override + public ClassDesc arrayType(int rank) { + ConstantUtils.validateArrayRank(rank); + return ArrayClassDescImpl.ofValidated(this, rank); + } + + @Override + public ClassDesc arrayType() { + return ArrayClassDescImpl.ofValidated(this, 1); + } + + @Override + public ClassDesc nested(String nestedName) { + validateMemberName(nestedName, false); + String desc = descriptorString(); + StringBuilder sb = new StringBuilder(desc.length() + nestedName.length() + 1); + sb.append(desc, 0, desc.length() - 1).append('$').append(nestedName).append(';'); + return ofValidated(sb.toString()); + } + + @Override + public ClassDesc nested(String firstNestedName, String... moreNestedNames) { + validateMemberName(firstNestedName, false); + // implicit null-check + for (String addNestedNames : moreNestedNames) { + validateMemberName(addNestedNames, false); + } + return moreNestedNames.length == 0 + ? nested(firstNestedName) + : nested(firstNestedName + "$" + String.join("$", moreNestedNames)); + + } + + @Override + public boolean isClassOrInterface() { + return true; + } + + @Override + public String packageName() { + String desc = descriptorString(); + int index = desc.lastIndexOf('/'); + return (index == -1) ? "" : internalToBinary(desc.substring(1, index)); + } + + @Override + public String displayName() { + String desc = descriptorString(); + return desc.substring(Math.max(1, desc.lastIndexOf('/') + 1), desc.length() - 1); + } + + @Override + public String descriptorString() { + return descriptor; + } + + @Override + public Class resolveConstantDesc(MethodHandles.Lookup lookup) + throws ReflectiveOperationException { + return lookup.findClass(internalToBinary(internalName())); + } + + /** + * Returns {@code true} if this {@linkplain ClassOrInterfaceDescImpl} is + * equal to another {@linkplain ClassOrInterfaceDescImpl}. Equality is + * determined by the two class descriptors having equal class descriptor + * strings. + * + * @param o the {@code ClassDesc} to compare to this + * {@code ClassDesc} + * @return {@code true} if the specified {@code ClassDesc} + * is equal to this {@code ClassDesc}. + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof ClassOrInterfaceDescImpl constant) { + return descriptor.equals(constant.descriptor); + } + return false; + } + + @Override + public int hashCode() { + return descriptor.hashCode(); + } + + @Override + public String toString() { + return String.format("ClassOrInterfaceDesc[%s]", displayName()); + } +} diff --git a/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java b/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java index 5640f849ab6b1..217919376491f 100644 --- a/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java +++ b/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java @@ -24,6 +24,7 @@ */ package jdk.internal.constant; +import jdk.internal.vm.annotation.Stable; import sun.invoke.util.Wrapper; import java.lang.constant.ClassDesc; @@ -31,8 +32,6 @@ import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodType; -import java.util.ArrayList; -import java.util.List; import java.util.Set; import jdk.internal.access.JavaLangAccess; @@ -50,6 +49,7 @@ public final class ConstantUtils { public static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0]; public static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255; public static final ClassDesc CD_module_info = binaryNameToDesc("module-info"); + public static @Stable ClassDesc CD_Object_array; // set from ConstantDescs, avoid circular initialization private static final Set pointyNames = Set.of(ConstantDescs.INIT_NAME, ConstantDescs.CLASS_INIT_NAME); @@ -70,7 +70,18 @@ private ConstantUtils() {} * @param binaryName a binary name */ public static ClassDesc binaryNameToDesc(String binaryName) { - return ReferenceClassDescImpl.ofValidated(concat("L", binaryToInternal(binaryName), ";")); + return internalNameToDesc(binaryToInternal(binaryName)); + } + + /** + * Creates a {@linkplain ClassDesc} from a pre-validated internal name + * for a class or interface type. Validated version of {@link + * ClassDesc#ofInternalName(String)}. + * + * @param internalName a binary name + */ + public static ClassDesc internalNameToDesc(String internalName) { + return ClassOrInterfaceDescImpl.ofValidated(concat("L", internalName, ";")); } /** @@ -91,7 +102,21 @@ public static ClassDesc classDesc(Class type) { * class or interface or an array type with a non-hidden component type. */ public static ClassDesc referenceClassDesc(Class type) { - return ReferenceClassDescImpl.ofValidated(type.descriptorString()); + return referenceClassDesc(type.descriptorString()); + } + + /** + * Creates a {@linkplain ClassDesc} from a pre-validated descriptor string + * for a class or interface type or an array type. + * + * @param descriptor a field descriptor string for a class or interface type + * @jvms 4.3.2 Field Descriptors + */ + public static ClassDesc referenceClassDesc(String descriptor) { + if (descriptor.charAt(0) == '[') { + return ArrayClassDescImpl.ofValidatedDescriptor(descriptor); + } + return ClassOrInterfaceDescImpl.ofValidated(descriptor); } /** @@ -128,6 +153,26 @@ public static MethodTypeDesc methodTypeDesc(Class returnType, Class[] para return MethodTypeDescImpl.ofValidated(returnDesc, paramDescs); } + /** + * Creates a {@linkplain ClassDesc} from a descriptor string for a class or + * interface type or an array type. + * + * @param descriptor a field descriptor string for a class or interface type + * @throws IllegalArgumentException if the descriptor string is not a valid + * field descriptor string, or does not describe a class or interface type + * @jvms 4.3.2 Field Descriptors + */ + public static ClassDesc parseReferenceTypeDesc(String descriptor) { + int dLen = descriptor.length(); + int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen); + if (len <= 1 || len != dLen) + throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor)); + if (descriptor.charAt(0) == '[') { + return ArrayClassDescImpl.ofValidatedDescriptor(descriptor); + } + return ClassOrInterfaceDescImpl.ofValidated(descriptor); + } + /** * Validates the correctness of a binary class name. In particular checks for the presence of * invalid characters in the name. @@ -140,8 +185,9 @@ public static MethodTypeDesc methodTypeDesc(Class returnType, Class[] para public static String validateBinaryClassName(String name) { for (int i = 0; i < name.length(); i++) { char ch = name.charAt(i); - if (ch == ';' || ch == '[' || ch == '/') - throw new IllegalArgumentException("Invalid class name: " + name); + if (ch == ';' || ch == '[' || ch == '/' + || ch == '.' && (i == 0 || i + 1 == name.length() || name.charAt(i - 1) == '.')) + throw invalidClassName(name); } return name; } @@ -158,8 +204,9 @@ public static String validateBinaryClassName(String name) { public static String validateInternalClassName(String name) { for (int i = 0; i < name.length(); i++) { char ch = name.charAt(i); - if (ch == ';' || ch == '[' || ch == '.') - throw new IllegalArgumentException("Invalid class name: " + name); + if (ch == ';' || ch == '[' || ch == '.' + || ch == '/' && (i == 0 || i + 1 == name.length() || name.charAt(i - 1) == '/')) + throw invalidClassName(name); } return name; } @@ -256,10 +303,24 @@ public static void validateClassOrInterface(ClassDesc classDesc) { throw new IllegalArgumentException("not a class or interface type: " + classDesc); } - public static int arrayDepth(String descriptorString) { + public static void validateArrayRank(int rank) { + // array rank must be representable with u1 and nonzero + if (rank == 0 || (rank & ~0xFF) != 0) { + throw new IllegalArgumentException(invalidArrayRankMessage(rank)); + } + } + + /** + * Retrieves the array depth on a trusted descriptor. + * Uses a simple loop with the assumption that most descriptors have + * 0 or very low array depths. + */ + public static int arrayDepth(String descriptorString, int off) { int depth = 0; - while (descriptorString.charAt(depth) == '[') + while (descriptorString.charAt(off) == '[') { depth++; + off++; + } return depth; } @@ -296,7 +357,22 @@ static ClassDesc resolveClassDesc(String descriptor, int start, int len) { } // Pre-verified in MethodTypeDescImpl#ofDescriptor; avoid redundant verification - return ReferenceClassDescImpl.ofValidated(descriptor.substring(start, start + len)); + int arrayDepth = arrayDepth(descriptor, start); + if (arrayDepth == 0) { + return ClassOrInterfaceDescImpl.ofValidated(descriptor.substring(start, start + len)); + } else if (arrayDepth + 1 == len) { + return ArrayClassDescImpl.ofValidated(forPrimitiveType(descriptor, start + arrayDepth), arrayDepth); + } else { + return ArrayClassDescImpl.ofValidated(ClassOrInterfaceDescImpl.ofValidated(descriptor.substring(start + arrayDepth, start + len)), arrayDepth); + } + } + + static String invalidArrayRankMessage(int rank) { + return "Array rank must be within [1, 255]: " + rank; + } + + static IllegalArgumentException invalidClassName(String className) { + return new IllegalArgumentException("Invalid class name: ".concat(className)); } static IllegalArgumentException badMethodDescriptor(String descriptor) { diff --git a/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java index 7d4442c255e8f..826fc095bbd28 100644 --- a/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java +++ b/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java @@ -39,13 +39,13 @@ import java.util.List; import java.util.Objects; +import static java.lang.constant.ConstantDescs.CD_void; import static java.util.Objects.requireNonNull; import static jdk.internal.constant.ConstantUtils.badMethodDescriptor; import static jdk.internal.constant.ConstantUtils.resolveClassDesc; import static jdk.internal.constant.ConstantUtils.skipOverFieldSignature; import static jdk.internal.constant.ConstantUtils.EMPTY_CLASSDESC; -import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void; /** * A nominal descriptor for a @@ -86,7 +86,7 @@ public static MethodTypeDescImpl ofTrusted(ClassDesc returnType, ClassDesc[] tru } private static ClassDesc validateArgument(ClassDesc arg) { - if (arg.descriptorString().charAt(0) == 'V') // implicit null check + if (requireNonNull(arg) == CD_void) throw new IllegalArgumentException("Void parameters not permitted"); return arg; } @@ -287,15 +287,31 @@ public String descriptorString() { if (desc != null) return desc; - int len = 2 + returnType.descriptorString().length(); - for (ClassDesc argType : argTypes) { - len += argType.descriptorString().length(); - } - StringBuilder sb = new StringBuilder(len).append('('); - for (ClassDesc argType : argTypes) { - sb.append(argType.descriptorString()); + return buildDescriptorString(); + } + + private String buildDescriptorString() { + var returnType = this.returnType; + var returnTypeDesc = returnType.descriptorString(); + var argTypes = this.argTypes; + String desc; + if (argTypes.length == 0) { + // getter + desc = "()".concat(returnTypeDesc); + } else if (argTypes.length == 1 && returnType == ConstantDescs.CD_void) { + // setter + desc = ConstantUtils.concat("(", argTypes[0].descriptorString(), ")V"); + } else { + int len = 2 + returnTypeDesc.length(); + for (ClassDesc argType : argTypes) { + len += argType.descriptorString().length(); + } + StringBuilder sb = new StringBuilder(len).append('('); + for (ClassDesc argType : argTypes) { + sb.append(argType.descriptorString()); + } + desc = sb.append(')').append(returnTypeDesc).toString(); } - desc = sb.append(')').append(returnType.descriptorString()).toString(); cachedDescriptorString = desc; return desc; } diff --git a/src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java index 35aa400781607..31ad92a2736c9 100644 --- a/src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java +++ b/src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java @@ -93,6 +93,31 @@ public Wrapper wrapper() { return this.lazyWrapper = Wrapper.forBasicType(descriptorString().charAt(0)); } + @Override + public boolean isPrimitive() { + return true; + } + + @Override + public ClassDesc arrayType(int rank) { + ConstantUtils.validateArrayRank(rank); + if (this == CD_void) + throw new IllegalArgumentException("not a valid reference type descriptor: " + "[".repeat(rank) + "V"); + return ArrayClassDescImpl.ofValidated(this, rank); + } + + @Override + public ClassDesc arrayType() { + if (this == CD_void) + throw new IllegalArgumentException("not a valid reference type descriptor: [V"); + return ArrayClassDescImpl.ofValidated(this, 1); + } + + @Override + public String displayName() { + return wrapper().primitiveSimpleName(); + } + @Override public String descriptorString() { return descriptor; diff --git a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java deleted file mode 100644 index b8cc9aacfe0a4..0000000000000 --- a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.constant; - -import java.lang.constant.ClassDesc; -import java.lang.invoke.MethodHandles; - -import static jdk.internal.constant.ConstantUtils.*; - -/** - * A nominal descriptor for a class, - * interface, or array type. A {@linkplain ReferenceClassDescImpl} corresponds to a - * {@code Constant_Class_info} entry in the constant pool of a classfile. - */ -public final class ReferenceClassDescImpl implements ClassDesc { - private final String descriptor; - - private ReferenceClassDescImpl(String descriptor) { - this.descriptor = descriptor; - } - - /** - * Creates a {@linkplain ClassDesc} from a descriptor string for a class or - * interface type or an array type. - * - * @param descriptor a field descriptor string for a class or interface type - * @throws IllegalArgumentException if the descriptor string is not a valid - * field descriptor string, or does not describe a class or interface type - * @jvms 4.3.2 Field Descriptors - */ - public static ReferenceClassDescImpl of(String descriptor) { - int dLen = descriptor.length(); - int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen); - if (len <= 1 || len != dLen) - throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor)); - return new ReferenceClassDescImpl(descriptor); - } - - /** - * Creates a {@linkplain ClassDesc} from a pre-validated descriptor string - * for a class or interface type or an array type. - * - * @param descriptor a field descriptor string for a class or interface type - * @jvms 4.3.2 Field Descriptors - */ - public static ReferenceClassDescImpl ofValidated(String descriptor) { - assert ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length()) - == descriptor.length() : descriptor; - return new ReferenceClassDescImpl(descriptor); - } - - @Override - public String descriptorString() { - return descriptor; - } - - @Override - public Class resolveConstantDesc(MethodHandles.Lookup lookup) - throws ReflectiveOperationException { - if (isArray()) { - if (isPrimitiveArray()) { - return lookup.findClass(descriptor); - } - // Class.forName is slow on class or interface arrays - int depth = ConstantUtils.arrayDepth(descriptor); - Class clazz = lookup.findClass(internalToBinary(descriptor.substring(depth + 1, descriptor.length() - 1))); - for (int i = 0; i < depth; i++) - clazz = clazz.arrayType(); - return clazz; - } - return lookup.findClass(internalToBinary(dropFirstAndLastChar(descriptor))); - } - - /** - * Whether the descriptor is one of a primitive array, given this is - * already a valid reference type descriptor. - */ - private boolean isPrimitiveArray() { - // All L-type descriptors must end with a semicolon; same for reference - // arrays, leaving primitive arrays the only ones without a final semicolon - return descriptor.charAt(descriptor.length() - 1) != ';'; - } - - /** - * Returns {@code true} if this {@linkplain ReferenceClassDescImpl} is - * equal to another {@linkplain ReferenceClassDescImpl}. Equality is - * determined by the two class descriptors having equal class descriptor - * strings. - * - * @param o the {@code ClassDesc} to compare to this - * {@code ClassDesc} - * @return {@code true} if the specified {@code ClassDesc} - * is equal to this {@code ClassDesc}. - */ - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o instanceof ReferenceClassDescImpl constant) { - return descriptor.equals(constant.descriptor); - } - return false; - } - - @Override - public int hashCode() { - return descriptor.hashCode(); - } - - @Override - public String toString() { - return String.format("ClassDesc[%s]", displayName()); - } -} diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java index 30e146a82f49b..d5a5954fa0e0b 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java @@ -200,8 +200,8 @@ private static long mismatch(AbstractMemorySegmentImpl src, long srcFromOffset, int offset = 0; final int limit = length & (NATIVE_THRESHOLD_MISMATCH - 8); for (; offset < limit; offset += 8) { - final long s = SCOPED_MEMORY_ACCESS.getLongUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, !Architecture.isLittleEndian()); - final long d = SCOPED_MEMORY_ACCESS.getLongUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, !Architecture.isLittleEndian()); + final long s = SCOPED_MEMORY_ACCESS.getLongUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, false); + final long d = SCOPED_MEMORY_ACCESS.getLongUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, false); if (s != d) { return start + offset + mismatch(s, d); } @@ -210,8 +210,8 @@ private static long mismatch(AbstractMemorySegmentImpl src, long srcFromOffset, // 0...0X00 if (remaining >= 4) { - final int s = SCOPED_MEMORY_ACCESS.getIntUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, !Architecture.isLittleEndian()); - final int d = SCOPED_MEMORY_ACCESS.getIntUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, !Architecture.isLittleEndian()); + final int s = SCOPED_MEMORY_ACCESS.getIntUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, false); + final int d = SCOPED_MEMORY_ACCESS.getIntUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, false); if (s != d) { return start + offset + mismatch(s, d); } @@ -220,8 +220,8 @@ private static long mismatch(AbstractMemorySegmentImpl src, long srcFromOffset, } // 0...00X0 if (remaining >= 2) { - final short s = SCOPED_MEMORY_ACCESS.getShortUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, !Architecture.isLittleEndian()); - final short d = SCOPED_MEMORY_ACCESS.getShortUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, !Architecture.isLittleEndian()); + final short s = SCOPED_MEMORY_ACCESS.getShortUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, false); + final short d = SCOPED_MEMORY_ACCESS.getShortUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, false); if (s != d) { return start + offset + mismatch(s, d); } @@ -243,26 +243,18 @@ private static long mismatch(AbstractMemorySegmentImpl src, long srcFromOffset, @ForceInline private static int mismatch(long first, long second) { final long x = first ^ second; - return (Architecture.isLittleEndian() - ? Long.numberOfTrailingZeros(x) - : Long.numberOfLeadingZeros(x)) / 8; + return Long.numberOfTrailingZeros(x) / 8; } @ForceInline private static int mismatch(int first, int second) { final int x = first ^ second; - return (Architecture.isLittleEndian() - ? Integer.numberOfTrailingZeros(x) - : Integer.numberOfLeadingZeros(x)) / 8; + return Integer.numberOfTrailingZeros(x) / 8; } @ForceInline private static int mismatch(short first, short second) { - if (Architecture.isLittleEndian()) { - return ((0xff & first) == (0xff & second)) ? 1 : 0; - } else { - return ((0xff & first) == (0xff & second)) ? 0 : 1; - } + return ((0xff & first) == (0xff & second)) ? 1 : 0; } /** diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java index bc5f63fd50ef7..41d7e3339d583 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java @@ -24,6 +24,7 @@ */ package jdk.internal.foreign.abi; +import java.lang.classfile.Annotation; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; import java.lang.classfile.Label; @@ -46,10 +47,13 @@ import jdk.internal.foreign.abi.Binding.ShiftRight; import jdk.internal.foreign.abi.Binding.VMLoad; import jdk.internal.foreign.abi.Binding.VMStore; +import jdk.internal.vm.annotation.ForceInline; import sun.security.action.GetBooleanAction; +import sun.security.action.GetIntegerAction; import sun.security.action.GetPropertyAction; import java.io.IOException; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; import java.lang.constant.DynamicConstantDesc; @@ -77,6 +81,8 @@ public class BindingSpecializer { = GetPropertyAction.privilegedGetProperty("jdk.internal.foreign.abi.Specializer.DUMP_CLASSES_DIR"); private static final boolean PERFORM_VERIFICATION = GetBooleanAction.privilegedGetProperty("jdk.internal.foreign.abi.Specializer.PERFORM_VERIFICATION"); + private static final int SCOPE_DEDUP_DEPTH + = GetIntegerAction.privilegedGetProperty("jdk.internal.foreign.abi.Specializer.SCOPE_DEDUP_DEPTH", 2); // Bunch of helper constants private static final int CLASSFILE_VERSION = ClassFileFormatVersion.latest().major(); @@ -99,6 +105,7 @@ public class BindingSpecializer { private static final ClassDesc CD_ValueLayout_OfFloat = referenceClassDesc(ValueLayout.OfFloat.class); private static final ClassDesc CD_ValueLayout_OfDouble = referenceClassDesc(ValueLayout.OfDouble.class); private static final ClassDesc CD_AddressLayout = referenceClassDesc(AddressLayout.class); + private static final ClassDesc CD_ForceInline = referenceClassDesc(ForceInline.class); private static final MethodTypeDesc MTD_NEW_BOUNDED_ARENA = MethodTypeDesc.of(CD_Arena, CD_long); private static final MethodTypeDesc MTD_NEW_EMPTY_ARENA = MethodTypeDesc.of(CD_Arena); @@ -193,12 +200,12 @@ private static byte[] specializeHelper(MethodType leafType, MethodType callerMet CallingSequence callingSequence, ABIDescriptor abi) { String className = callingSequence.forDowncall() ? CLASS_NAME_DOWNCALL : CLASS_NAME_UPCALL; byte[] bytes = ClassFile.of().build(ClassDesc.ofInternalName(className), clb -> { - clb.withFlags(ACC_PUBLIC + ACC_FINAL + ACC_SUPER); - clb.withSuperclass(CD_Object); - clb.withVersion(CLASSFILE_VERSION, 0); - - clb.withMethodBody(METHOD_NAME, methodTypeDesc(callerMethodType), ACC_PUBLIC | ACC_STATIC, - cb -> new BindingSpecializer(cb, callerMethodType, callingSequence, abi, leafType).specialize()); + clb.withFlags(ACC_PUBLIC + ACC_FINAL + ACC_SUPER) + .withSuperclass(CD_Object) + .withVersion(CLASSFILE_VERSION, 0) + .withMethod(METHOD_NAME, methodTypeDesc(callerMethodType), ACC_PUBLIC | ACC_STATIC, + mb -> mb.with(RuntimeVisibleAnnotationsAttribute.of(Annotation.of(CD_ForceInline))) + .withCode(cb -> new BindingSpecializer(cb, callerMethodType, callingSequence, abi, leafType).specialize())); }); if (DUMP_CLASSES_DIR != null) { @@ -275,8 +282,8 @@ private void specialize() { if (shouldAcquire(i)) { int scopeLocal = cb.allocateLocal(REFERENCE); initialScopeSlots[numScopes++] = scopeLocal; - cb.loadConstant(null); - cb.storeLocal(REFERENCE, scopeLocal); // need to initialize all scope locals here in case an exception occurs + cb.aconst_null() + .astore(scopeLocal); // need to initialize all scope locals here in case an exception occurs } } scopeSlots = Arrays.copyOf(initialScopeSlots, numScopes); // fit to size @@ -285,15 +292,15 @@ private void specialize() { // create a Binding.Context for this call if (callingSequence.allocationSize() != 0) { - cb.loadConstant(callingSequence.allocationSize()); - cb.invokestatic(CD_SharedUtils, "newBoundedArena", MTD_NEW_BOUNDED_ARENA); + cb.loadConstant(callingSequence.allocationSize()) + .invokestatic(CD_SharedUtils, "newBoundedArena", MTD_NEW_BOUNDED_ARENA); } else if (callingSequence.forUpcall() && needsSession()) { cb.invokestatic(CD_SharedUtils, "newEmptyArena", MTD_NEW_EMPTY_ARENA); } else { cb.getstatic(CD_SharedUtils, "DUMMY_ARENA", CD_Arena); } contextIdx = cb.allocateLocal(REFERENCE); - cb.storeLocal(REFERENCE, contextIdx); + cb.astore(contextIdx); // in case the call needs a return buffer, allocate it here. // for upcalls the VM wrapper stub allocates the buffer. @@ -301,7 +308,7 @@ private void specialize() { emitLoadInternalAllocator(); emitAllocateCall(callingSequence.returnBufferSize(), 1); returnBufferIdx = cb.allocateLocal(REFERENCE); - cb.storeLocal(REFERENCE, returnBufferIdx); + cb.astore(returnBufferIdx); } Label tryStart = cb.newLabel(); @@ -324,7 +331,7 @@ private void specialize() { // for downcalls, recipes have an input value, which we set up here if (callingSequence.needsReturnBuffer() && i == 0) { assert returnBufferIdx != -1; - cb.loadLocal(REFERENCE, returnBufferIdx); + cb.aload(returnBufferIdx); pushType(MemorySegment.class); } else { emitGetInput(); @@ -340,7 +347,7 @@ private void specialize() { // return buffer ptr is wrapped in a MemorySegment above, but not passed to the leaf handle popType(MemorySegment.class); returnBufferIdx = cb.allocateLocal(REFERENCE); - cb.storeLocal(REFERENCE, returnBufferIdx); + cb.astore(returnBufferIdx); } else { // for upcalls the recipe result is an argument to the leaf handle emitSetOutput(typeStack.pop()); @@ -355,7 +362,7 @@ private void specialize() { if (callingSequence.forDowncall()) { cb.loadConstant(CLASS_DATA_DESC); } else { - cb.loadLocal(REFERENCE, 0); // load target arg + cb.aload(0); // load target arg } cb.checkcast(CD_MethodHandle); // load all the leaf args @@ -496,32 +503,39 @@ private void emitGetInput() { } private void emitAcquireScope() { - cb.checkcast(CD_AbstractMemorySegmentImpl); - cb.invokevirtual(CD_AbstractMemorySegmentImpl, "sessionImpl", MTD_SESSION_IMPL); + cb.checkcast(CD_AbstractMemorySegmentImpl) + .invokevirtual(CD_AbstractMemorySegmentImpl, "sessionImpl", MTD_SESSION_IMPL); Label skipAcquire = cb.newLabel(); Label end = cb.newLabel(); // start with 1 scope to maybe acquire on the stack assert curScopeLocalIdx != -1; - boolean hasOtherScopes = curScopeLocalIdx != 0; - for (int i = 0; i < curScopeLocalIdx; i++) { - cb.dup(); // dup for comparison - cb.loadLocal(REFERENCE, scopeSlots[i]); - cb.if_acmpeq(skipAcquire); + boolean hasLookup = false; + + // Here we check if the current scope has not been already acquired. + // To do that, we generate many comparisons (one per cached scope). + // Note that we always skip comparisons against the very first cached scope + // (as that is the function address, which typically belongs to another scope). + // We also stop the comparisons at SCOPE_DEDUP_DEPTH, to keep a lid on the size + // of the generated code. + for (int i = 1; i < curScopeLocalIdx && i <= SCOPE_DEDUP_DEPTH; i++) { + cb.dup() // dup for comparison + .aload(scopeSlots[i]) + .if_acmpeq(skipAcquire); + hasLookup = true; } // 1 scope to acquire on the stack cb.dup(); int nextScopeLocal = scopeSlots[curScopeLocalIdx++]; // call acquire first here. So that if it fails, we don't call release - cb.invokevirtual(CD_MemorySessionImpl, "acquire0", MTD_ACQUIRE0); // call acquire on the other - cb.storeLocal(REFERENCE, nextScopeLocal); // store off one to release later - - if (hasOtherScopes) { // avoid ASM generating a bunch of nops for the dead code - cb.goto_(end); + cb.invokevirtual(CD_MemorySessionImpl, "acquire0", MTD_ACQUIRE0) // call acquire on the other + .astore(nextScopeLocal); // store off one to release later - cb.labelBinding(skipAcquire); - cb.pop(); // drop scope + if (hasLookup) { // avoid ASM generating a bunch of nops for the dead code + cb.goto_(end) + .labelBinding(skipAcquire) + .pop(); // drop scope } cb.labelBinding(end); @@ -529,10 +543,10 @@ private void emitAcquireScope() { private void emitReleaseScopes() { for (int scopeLocal : scopeSlots) { - cb.loadLocal(REFERENCE, scopeLocal); - cb.ifThen(Opcode.IFNONNULL, ifCb -> { - ifCb.loadLocal(REFERENCE, scopeLocal); - ifCb.invokevirtual(CD_MemorySessionImpl, "release0", MTD_RELEASE0); + cb.aload(scopeLocal) + .ifThen(Opcode.IFNONNULL, ifCb -> { + ifCb.aload(scopeLocal) + .invokevirtual(CD_MemorySessionImpl, "release0", MTD_RELEASE0); }); } } @@ -551,28 +565,28 @@ private void emitRestoreReturnValue(Class loadType) { private void emitLoadInternalSession() { assert contextIdx != -1; - cb.loadLocal(REFERENCE, contextIdx); - cb.checkcast(CD_Arena); - cb.invokeinterface(CD_Arena, "scope", MTD_SCOPE); - cb.checkcast(CD_MemorySessionImpl); + cb.aload(contextIdx) + .checkcast(CD_Arena) + .invokeinterface(CD_Arena, "scope", MTD_SCOPE) + .checkcast(CD_MemorySessionImpl); } private void emitLoadInternalAllocator() { assert contextIdx != -1; - cb.loadLocal(REFERENCE, contextIdx); + cb.aload(contextIdx); } private void emitCloseContext() { assert contextIdx != -1; - cb.loadLocal(REFERENCE, contextIdx); - cb.checkcast(CD_Arena); - cb.invokeinterface(CD_Arena, "close", MTD_CLOSE); + cb.aload(contextIdx) + .checkcast(CD_Arena) + .invokeinterface(CD_Arena, "close", MTD_CLOSE); } private void emitBoxAddress(BoxAddress boxAddress) { popType(long.class); - cb.loadConstant(boxAddress.size()); - cb.loadConstant(boxAddress.align()); + cb.loadConstant(boxAddress.size()) + .loadConstant(boxAddress.align()); if (needsSession()) { emitLoadInternalSession(); cb.invokestatic(CD_Utils, "longToAddress", MTD_LONG_TO_ADDRESS_SCOPE); @@ -585,7 +599,7 @@ private void emitBoxAddress(BoxAddress boxAddress) { private void emitAllocBuffer(Allocate binding) { if (callingSequence.forDowncall()) { assert returnAllocatorIdx != -1; - cb.loadLocal(REFERENCE, returnAllocatorIdx); + cb.aload(returnAllocatorIdx); } else { emitLoadInternalAllocator(); } @@ -607,8 +621,8 @@ private void emitBufferStore(BufferStore bufferStore) { cb.storeLocal(storeTypeKind, valueIdx); ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType); - cb.loadConstant(offset); - cb.loadLocal(storeTypeKind, valueIdx); + cb.loadConstant(offset) + .loadLocal(storeTypeKind, valueIdx); MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType)); cb.invokeinterface(CD_MemorySegment, "set", descriptor); } else { @@ -619,9 +633,9 @@ private void emitBufferStore(BufferStore bufferStore) { assert storeType == long.class; // chunking only for int and long } int longValueIdx = cb.allocateLocal(LONG); - cb.storeLocal(LONG, longValueIdx); + cb.lstore(longValueIdx); int writeAddrIdx = cb.allocateLocal(REFERENCE); - cb.storeLocal(REFERENCE, writeAddrIdx); + cb.astore(writeAddrIdx); int remaining = byteWidth; int chunkOffset = 0; @@ -648,25 +662,25 @@ private void emitBufferStore(BufferStore bufferStore) { //int writeChunk = (int) (((0xFFFF_FFFFL << shiftAmount) & longValue) >>> shiftAmount); int shiftAmount = chunkOffset * Byte.SIZE; mask = mask << shiftAmount; - cb.loadLocal(LONG, longValueIdx); - cb.loadConstant(mask); - cb.land(); + cb.lload(longValueIdx) + .loadConstant(mask) + .land(); if (shiftAmount != 0) { - cb.loadConstant(shiftAmount); - cb.lushr(); + cb.loadConstant(shiftAmount) + .lushr(); } cb.l2i(); TypeKind chunkStoreTypeKind = TypeKind.from(chunkStoreType); int chunkIdx = cb.allocateLocal(chunkStoreTypeKind); - cb.storeLocal(chunkStoreTypeKind, chunkIdx); + cb.storeLocal(chunkStoreTypeKind, chunkIdx) // chunk done, now write it //writeAddress.set(JAVA_SHORT_UNALIGNED, offset, writeChunk); - cb.loadLocal(REFERENCE, writeAddrIdx); + .aload(writeAddrIdx); ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkStoreType); long writeOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize); - cb.loadConstant(writeOffset); - cb.loadLocal(chunkStoreTypeKind, chunkIdx); + cb.loadConstant(writeOffset) + .loadLocal(chunkStoreTypeKind, chunkIdx); MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(chunkStoreType)); cb.invokeinterface(CD_MemorySegment, "set", descriptor); @@ -690,16 +704,16 @@ private void emitVMStore(VMStore vmStore) { if (!callingSequence.needsReturnBuffer()) { emitSaveReturnValue(storeType); } else { - int valueIdx = cb.allocateLocal(storeTypeKind); - cb.storeLocal(storeTypeKind, valueIdx); // store away the stored value, need it later - assert returnBufferIdx != -1; - cb.loadLocal(REFERENCE, returnBufferIdx); + int valueIdx = cb.allocateLocal(storeTypeKind); + cb.storeLocal(storeTypeKind, valueIdx) // store away the stored value, need it later + .aload(returnBufferIdx); ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType); - cb.loadConstant(retBufOffset); - cb.loadLocal(storeTypeKind, valueIdx); - MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType)); - cb.invokeinterface(CD_MemorySegment, "set", descriptor); + cb.loadConstant(retBufOffset) + .loadLocal(storeTypeKind, valueIdx) + .invokeinterface(CD_MemorySegment, + "set", + MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType))); retBufOffset += abi.arch.typeSize(vmStore.storage().type()); } } @@ -714,11 +728,12 @@ private void emitVMLoad(VMLoad vmLoad) { emitRestoreReturnValue(loadType); } else { assert returnBufferIdx != -1; - cb.loadLocal(REFERENCE, returnBufferIdx); + cb.aload(returnBufferIdx); ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType); - cb.loadConstant(retBufOffset); - MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long); - cb.invokeinterface(CD_MemorySegment, "get", descriptor); + cb.loadConstant(retBufOffset) + .invokeinterface(CD_MemorySegment, + "get", + MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long)); retBufOffset += abi.arch.typeSize(vmLoad.storage().type()); pushType(loadType); } @@ -736,15 +751,15 @@ private void emitDupBinding() { private void emitShiftLeft(ShiftLeft shiftLeft) { popType(long.class); - cb.loadConstant(shiftLeft.shiftAmount() * Byte.SIZE); - cb.lshl(); + cb.loadConstant(shiftLeft.shiftAmount() * Byte.SIZE) + .lshl(); pushType(long.class); } private void emitShiftRight(ShiftRight shiftRight) { popType(long.class); - cb.loadConstant(shiftRight.shiftAmount() * Byte.SIZE); - cb.lushr(); + cb.loadConstant(shiftRight.shiftAmount() * Byte.SIZE) + .lushr(); pushType(long.class); } @@ -758,11 +773,10 @@ private void emitCast(Cast cast) { // implement least significant byte non-zero test // select first byte - cb.loadConstant(0xFF); - cb.iand(); - - // convert to boolean - cb.invokestatic(CD_Utils, "byteToBoolean", MTD_BYTE_TO_BOOLEAN); + cb.loadConstant(0xFF) + .iand() + // convert to boolean + .invokestatic(CD_Utils, "byteToBoolean", MTD_BYTE_TO_BOOLEAN); } case INT_TO_BYTE -> cb.i2b(); case INT_TO_CHAR -> cb.i2c(); @@ -782,8 +796,8 @@ private void emitCast(Cast cast) { private void emitSegmentBase() { popType(MemorySegment.class); - cb.checkcast(CD_AbstractMemorySegmentImpl); - cb.invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetBase", MTD_UNSAFE_GET_BASE); + cb.checkcast(CD_AbstractMemorySegmentImpl) + .invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetBase", MTD_UNSAFE_GET_BASE); pushType(Object.class); } @@ -791,11 +805,11 @@ private void emitSegmentOffset(SegmentOffset segmentOffset) { popType(MemorySegment.class); if (!segmentOffset.allowHeap()) { - cb.dup(); - cb.invokestatic(CD_SharedUtils, "checkNative", MTD_CHECK_NATIVE); + cb.dup() + .invokestatic(CD_SharedUtils, "checkNative", MTD_CHECK_NATIVE); } - cb.checkcast(CD_AbstractMemorySegmentImpl); - cb.invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetOffset", MTD_UNSAFE_GET_OFFSET); + cb.checkcast(CD_AbstractMemorySegmentImpl) + .invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetOffset", MTD_UNSAFE_GET_OFFSET); pushType(long.class); } @@ -809,17 +823,17 @@ private void emitBufferLoad(BufferLoad bufferLoad) { if (SharedUtils.isPowerOfTwo(byteWidth)) { ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType); - cb.loadConstant(offset); - MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long); - cb.invokeinterface(CD_MemorySegment, "get", descriptor); + cb.loadConstant(offset) + .invokeinterface(CD_MemorySegment, + "get", + MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long)); } else { // chunked int readAddrIdx = cb.allocateLocal(REFERENCE); - cb.storeLocal(REFERENCE, readAddrIdx); - - cb.loadConstant(0L); // result + cb.astore(readAddrIdx) + .loadConstant(0L); // result int resultIdx = cb.allocateLocal(LONG); - cb.storeLocal(LONG, resultIdx); + cb.lstore(resultIdx); int remaining = byteWidth; int chunkOffset = 0; @@ -848,30 +862,30 @@ private void emitBufferLoad(BufferLoad bufferLoad) { throw new IllegalStateException("Unexpected chunk size for chunked write: " + chunkSize); } // read from segment - cb.loadLocal(REFERENCE, readAddrIdx); + cb.aload(readAddrIdx); ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkType); MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(chunkType), valueLayoutType, CD_long); long readOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize); - cb.loadConstant(readOffset); - cb.invokeinterface(CD_MemorySegment, "get", descriptor); - cb.invokestatic(toULongHolder, "toUnsignedLong", toULongDescriptor); + cb.loadConstant(readOffset) + .invokeinterface(CD_MemorySegment, "get", descriptor) + .invokestatic(toULongHolder, "toUnsignedLong", toULongDescriptor); // shift to right offset int shiftAmount = chunkOffset * Byte.SIZE; if (shiftAmount != 0) { - cb.loadConstant(shiftAmount); - cb.lshl(); + cb.loadConstant(shiftAmount) + .lshl(); } // add to result - cb.loadLocal(LONG, resultIdx); - cb.lor(); - cb.storeLocal(LONG, resultIdx); + cb.lload(resultIdx) + .lor() + .lstore(resultIdx); remaining -= chunkSize; chunkOffset += chunkSize; } while (remaining != 0); - cb.loadLocal(LONG, resultIdx); + cb.lload(resultIdx); if (loadType == int.class) { cb.l2i(); } else { @@ -898,19 +912,18 @@ private void emitCopyBuffer(Copy copy) { emitAllocateCall(size, alignment); cb.dup(); int storeIdx = cb.allocateLocal(REFERENCE); - cb.storeLocal(REFERENCE, storeIdx); - cb.loadConstant(0L); - cb.loadConstant(size); - cb.invokestatic(CD_MemorySegment, "copy", MTD_COPY, true); - - cb.loadLocal(REFERENCE, storeIdx); + cb.astore(storeIdx) + .loadConstant(0L) + .loadConstant(size) + .invokestatic(CD_MemorySegment, "copy", MTD_COPY, true) + .aload(storeIdx); pushType(MemorySegment.class); } private void emitAllocateCall(long size, long alignment) { - cb.loadConstant(size); - cb.loadConstant(alignment); - cb.invokeinterface(CD_SegmentAllocator, "allocate", MTD_ALLOCATE); + cb.loadConstant(size) + .loadConstant(alignment) + .invokeinterface(CD_SegmentAllocator, "allocate", MTD_ALLOCATE); } private ClassDesc emitLoadLayoutConstant(Class type) { diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index 05049effef8c4..c6ae5b13787ec 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -64,11 +64,10 @@ * Values should be annotated with the feature's {@code JEP}. */ public enum Feature { - // not used, but required for interim javac to not warn. - VIRTUAL_THREADS, - FOREIGN, - @JEP(number=459, title="String Templates", status="Second Preview") - STRING_TEMPLATES, + // while building the interim javac, the ClassReader will produce a warning when loading a class + // keeping the constant of a feature that has been integrated or dropped, serves the purpose of muting such warnings. + + //--- @JEP(number=477, title="Implicitly Declared Classes and Instance Main Methods", status="Third Preview") IMPLICIT_CLASSES, @JEP(number=481, title="Scoped Values", status="Third Preview") diff --git a/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java b/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java index 1f7df79009f51..84e5c50672d81 100644 --- a/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java +++ b/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java @@ -1084,5 +1084,8 @@ private static URL checkURL(URL url) { private void resetArchivedStates() { ucp = null; resourceCache = null; + if (!moduleToReader.isEmpty()) { + moduleToReader.clear(); + } } } diff --git a/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java b/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java index 7b0f4d13e4096..ab4aa3fb90734 100644 --- a/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java +++ b/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java @@ -210,13 +210,6 @@ void appendToClassPathForInstrumentation(String path) { protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { return super.defineOrCheckPackage(pn, man, url); } - - /** - * Called by the VM, during -Xshare:dump - */ - private void resetArchivedStates() { - setClassPath(null); - } } /** diff --git a/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java b/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java index 8b91ab67d2bfd..ca5ffb2ff681f 100644 --- a/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java +++ b/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java @@ -25,6 +25,7 @@ package jdk.internal.module; import java.util.Objects; +import java.util.Set; import java.util.function.Function; import java.lang.module.Configuration; import java.lang.module.ModuleFinder; @@ -43,19 +44,22 @@ class ArchivedModuleGraph { private final Configuration configuration; private final Function classLoaderFunction; private final String mainModule; + private final Set addModules; private ArchivedModuleGraph(boolean hasSplitPackages, boolean hasIncubatorModules, ModuleFinder finder, Configuration configuration, Function classLoaderFunction, - String mainModule) { + String mainModule, + Set addModules) { this.hasSplitPackages = hasSplitPackages; this.hasIncubatorModules = hasIncubatorModules; this.finder = finder; this.configuration = configuration; this.classLoaderFunction = classLoaderFunction; this.mainModule = mainModule; + this.addModules = addModules; } ModuleFinder finder() { @@ -78,12 +82,24 @@ boolean hasIncubatorModules() { return hasIncubatorModules; } + static boolean sameAddModules(Set addModules) { + if (archivedModuleGraph.addModules == null || addModules == null) { + return false; + } + + if (archivedModuleGraph.addModules.size() != addModules.size()) { + return false; + } + + return archivedModuleGraph.addModules.containsAll(addModules); + } + /** * Returns the ArchivedModuleGraph for the given initial module. */ - static ArchivedModuleGraph get(String mainModule) { + static ArchivedModuleGraph get(String mainModule, Set addModules) { ArchivedModuleGraph graph = archivedModuleGraph; - if ((graph != null) && Objects.equals(graph.mainModule, mainModule)) { + if ((graph != null) && Objects.equals(graph.mainModule, mainModule) && sameAddModules(addModules)) { return graph; } else { return null; @@ -98,13 +114,15 @@ static void archive(boolean hasSplitPackages, ModuleFinder finder, Configuration configuration, Function classLoaderFunction, - String mainModule) { + String mainModule, + Set addModules) { archivedModuleGraph = new ArchivedModuleGraph(hasSplitPackages, hasIncubatorModules, finder, configuration, classLoaderFunction, - mainModule); + mainModule, + addModules); } static { diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java index 04d607d06bb21..f5904915e26c6 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -33,6 +33,7 @@ import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; import java.net.URI; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -139,9 +140,7 @@ public static ModuleFinder limitedFinder() { */ private static boolean canUseArchivedBootLayer() { return getProperty("jdk.module.upgrade.path") == null && - getProperty("jdk.module.path") == null && getProperty("jdk.module.patch.0") == null && // --patch-module - getProperty("jdk.module.addmods.0") == null && // --add-modules getProperty("jdk.module.limitmods") == null && // --limit-modules getProperty("jdk.module.addreads.0") == null && // --add-reads getProperty("jdk.module.addexports.0") == null && // --add-exports @@ -203,7 +202,8 @@ private static ModuleLayer boot2() { SystemModules systemModules = null; ModuleFinder systemModuleFinder; - boolean haveModulePath = (appModulePath != null || upgradeModulePath != null); + boolean haveUpgradeModulePath = (upgradeModulePath != null); + boolean haveModulePath = (appModulePath != null || haveUpgradeModulePath); boolean needResolution = true; boolean mayContainSplitPackages = true; boolean mayContainIncubatorModules = true; @@ -211,10 +211,9 @@ private static ModuleLayer boot2() { // If the java heap was archived at CDS dump time, and the environment // at dump time matches the current environment, then use the archived // system modules and finder. - ArchivedModuleGraph archivedModuleGraph = ArchivedModuleGraph.get(mainModule); + ArchivedModuleGraph archivedModuleGraph = ArchivedModuleGraph.get(mainModule, addModules); if (archivedModuleGraph != null && !haveModulePath - && addModules.isEmpty() && limitModules.isEmpty() && !isPatched) { systemModuleFinder = archivedModuleGraph.finder(); @@ -463,7 +462,9 @@ private static ModuleLayer boot2() { // Step 8: CDS dump phase - if (CDS.isDumpingStaticArchive() && !haveModulePath && addModules.isEmpty()) { + if (CDS.isDumpingStaticArchive() + && !haveUpgradeModulePath + && allJrtOrModularJar(cf)) { assert !isPatched; // Archive module graph and maybe boot layer @@ -474,7 +475,8 @@ private static ModuleLayer boot2() { systemModuleFinder, cf, clf, - mainModule); + mainModule, + addModules); if (!hasSplitPackages && !hasIncubatorModules) { ArchivedBootLayer.archive(bootLayer); } @@ -510,6 +512,29 @@ private static void loadModules(Configuration cf, } } + /** + * Returns true if all modules in the configuration are in the run-time image or + * modular JAR files. + */ + private static boolean allJrtOrModularJar(Configuration cf) { + return !cf.modules().stream() + .map(m -> m.reference().location().orElseThrow()) + .anyMatch(uri -> !uri.getScheme().equalsIgnoreCase("jrt") + && !isJarFile(uri)); + } + + /** + * Returns true if the given URI locates a jar file on the file system. + */ + private static boolean isJarFile(URI uri) { + if ("file".equalsIgnoreCase(uri.getScheme())) { + Path path = Path.of(uri); + return path.toString().endsWith(".jar") && Files.isRegularFile(path); + } else { + return false; + } + } + /** * Returns true if the configuration contains modules with overlapping packages. */ diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java b/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java index a8b5eda709e7b..e48624bc524c0 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java @@ -51,32 +51,31 @@ private static final class Mapper implements Function { private static final ClassLoader APP_CLASSLOADER = ClassLoaders.appClassLoader(); - private static final Integer PLATFORM_LOADER_INDEX = 1; - private static final Integer APP_LOADER_INDEX = 2; + private static final String PLATFORM_LOADER_NAME = "PLATFORM"; + private static final String APP_LOADER_NAME = "APP"; /** - * Map from module to a class loader index. The index is resolved to the + * Map from module name to class loader name. The name is resolved to the * actual class loader in {@code apply}. */ - private final Map map; + private final Map map; /** * Creates a Mapper to map module names in the given Configuration to * built-in classloaders. * * As a proxy for the actual classloader, we store an easily archiveable - * index value in the internal map. The index is stored as a boxed value - * so that we can cheaply do identity comparisons during bootstrap. + * loader name in the internal map. */ Mapper(Configuration cf) { - var map = new HashMap(); + var map = new HashMap(); for (ResolvedModule resolvedModule : cf.modules()) { String mn = resolvedModule.name(); if (!Modules.bootModules.contains(mn)) { if (Modules.platformModules.contains(mn)) { - map.put(mn, PLATFORM_LOADER_INDEX); + map.put(mn, PLATFORM_LOADER_NAME); } else { - map.put(mn, APP_LOADER_INDEX); + map.put(mn, APP_LOADER_NAME); } } } @@ -85,12 +84,12 @@ private static final class Mapper implements Function { @Override public ClassLoader apply(String name) { - Integer loader = map.get(name); - if (loader == APP_LOADER_INDEX) { + String loader = map.get(name); + if (APP_LOADER_NAME.equals(loader)) { return APP_CLASSLOADER; - } else if (loader == PLATFORM_LOADER_INDEX) { + } else if (PLATFORM_LOADER_NAME.equals(loader)) { return PLATFORM_CLASSLOADER; - } else { // BOOT_LOADER_INDEX + } else { return null; } } diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java b/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java index 346838b47d995..a5ad79eb7c603 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java @@ -91,8 +91,19 @@ static ModuleReference newJarModule(ModuleInfo.Attributes attrs, ModulePatcher patcher, Path file) { URI uri = file.toUri(); - Supplier supplier = () -> new JarModuleReader(file, uri); - HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a); + String fileString = file.toString(); + Supplier supplier = new Supplier<>() { + @Override + public ModuleReader get() { + return new JarModuleReader(fileString, uri); + } + }; + HashSupplier hasher = new HashSupplier() { + @Override + public byte[] generate(String algorithm) { + return ModuleHashes.computeHash(supplier, algorithm); + } + }; return newModule(attrs, uri, supplier, patcher, hasher); } @@ -222,9 +233,9 @@ static class JarModuleReader extends SafeCloseModuleReader { private final JarFile jf; private final URI uri; - static JarFile newJarFile(Path path) { + static JarFile newJarFile(String path) { try { - return new JarFile(new File(path.toString()), + return new JarFile(new File(path), true, // verify ZipFile.OPEN_READ, JarFile.runtimeVersion()); @@ -233,7 +244,7 @@ static JarFile newJarFile(Path path) { } } - JarModuleReader(Path path, URI uri) { + JarModuleReader(String path, URI uri) { this.jf = newJarFile(path); this.uri = uri; } diff --git a/src/java.base/share/classes/jdk/internal/reflect/AccessorGenerator.java b/src/java.base/share/classes/jdk/internal/reflect/AccessorGenerator.java deleted file mode 100644 index d87e0fd167f5c..0000000000000 --- a/src/java.base/share/classes/jdk/internal/reflect/AccessorGenerator.java +++ /dev/null @@ -1,722 +0,0 @@ -/* - * Copyright (c) 2001, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.reflect; - -import java.lang.reflect.*; -import jdk.internal.misc.Unsafe; - -/** Shared functionality for all accessor generators */ - -class AccessorGenerator implements ClassFileConstants { - static final Unsafe unsafe = Unsafe.getUnsafe(); - - // Constants because there's no way to say "short integer constant", - // i.e., "1S" - protected static final short S0 = (short) 0; - protected static final short S1 = (short) 1; - protected static final short S2 = (short) 2; - protected static final short S3 = (short) 3; - protected static final short S4 = (short) 4; - protected static final short S5 = (short) 5; - protected static final short S6 = (short) 6; - - // Instance variables for shared functionality - protected ClassFileAssembler asm; - protected int modifiers; - protected short thisClass; - protected short superClass; - protected short targetClass; - // Common constant pool entries to FieldAccessor and MethodAccessor - protected short throwableClass; - protected short classCastClass; - protected short nullPointerClass; - protected short illegalArgumentClass; - protected short invocationTargetClass; - protected short initIdx; - protected short initNameAndTypeIdx; - protected short initStringNameAndTypeIdx; - protected short nullPointerCtorIdx; - protected short illegalArgumentCtorIdx; - protected short illegalArgumentStringCtorIdx; - protected short invocationTargetCtorIdx; - protected short superCtorIdx; - protected short objectClass; - protected short toStringIdx; - protected short codeIdx; - protected short exceptionsIdx; - // Boxing - protected short valueOfIdx; - protected short booleanIdx; - protected short booleanBoxIdx; - protected short booleanUnboxIdx; - protected short byteIdx; - protected short byteBoxIdx; - protected short byteUnboxIdx; - protected short characterIdx; - protected short characterBoxIdx; - protected short characterUnboxIdx; - protected short doubleIdx; - protected short doubleBoxIdx; - protected short doubleUnboxIdx; - protected short floatIdx; - protected short floatBoxIdx; - protected short floatUnboxIdx; - protected short integerIdx; - protected short integerBoxIdx; - protected short integerUnboxIdx; - protected short longIdx; - protected short longBoxIdx; - protected short longUnboxIdx; - protected short shortIdx; - protected short shortBoxIdx; - protected short shortUnboxIdx; - - protected final short NUM_COMMON_CPOOL_ENTRIES = (short) 30; - protected final short NUM_BOXING_CPOOL_ENTRIES = (short) 73; - - // Requires that superClass has been set up - protected void emitCommonConstantPoolEntries() { - // + [UTF-8] "java/lang/Throwable" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "java/lang/ClassCastException" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "java/lang/NullPointerException" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "java/lang/IllegalArgumentException" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "java/lang/InvocationTargetException" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "" - // + [UTF-8] "()V" - // + [CONSTANT_NameAndType_info] for above - // + [CONSTANT_Methodref_info] for NullPointerException's constructor - // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor - // + [UTF-8] "(Ljava/lang/String;)V" - // + [CONSTANT_NameAndType_info] for "(Ljava/lang/String;)V" - // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String - // + [UTF-8] "(Ljava/lang/Throwable;)V" - // + [CONSTANT_NameAndType_info] for "(Ljava/lang/Throwable;)V" - // + [CONSTANT_Methodref_info] for InvocationTargetException's constructor - // + [CONSTANT_Methodref_info] for "super()" - // + [UTF-8] "java/lang/Object" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "toString" - // + [UTF-8] "()Ljava/lang/String;" - // + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;" - // + [CONSTANT_Methodref_info] for Object's toString method - // + [UTF-8] "Code" - // + [UTF-8] "Exceptions" - asm.emitConstantPoolUTF8("java/lang/Throwable"); - asm.emitConstantPoolClass(asm.cpi()); - throwableClass = asm.cpi(); - asm.emitConstantPoolUTF8("java/lang/ClassCastException"); - asm.emitConstantPoolClass(asm.cpi()); - classCastClass = asm.cpi(); - asm.emitConstantPoolUTF8("java/lang/NullPointerException"); - asm.emitConstantPoolClass(asm.cpi()); - nullPointerClass = asm.cpi(); - asm.emitConstantPoolUTF8("java/lang/IllegalArgumentException"); - asm.emitConstantPoolClass(asm.cpi()); - illegalArgumentClass = asm.cpi(); - asm.emitConstantPoolUTF8("java/lang/reflect/InvocationTargetException"); - asm.emitConstantPoolClass(asm.cpi()); - invocationTargetClass = asm.cpi(); - asm.emitConstantPoolUTF8(""); - initIdx = asm.cpi(); - asm.emitConstantPoolUTF8("()V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); - initNameAndTypeIdx = asm.cpi(); - asm.emitConstantPoolMethodref(nullPointerClass, initNameAndTypeIdx); - nullPointerCtorIdx = asm.cpi(); - asm.emitConstantPoolMethodref(illegalArgumentClass, initNameAndTypeIdx); - illegalArgumentCtorIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(Ljava/lang/String;)V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); - initStringNameAndTypeIdx = asm.cpi(); - asm.emitConstantPoolMethodref(illegalArgumentClass, initStringNameAndTypeIdx); - illegalArgumentStringCtorIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(Ljava/lang/Throwable;)V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); - asm.emitConstantPoolMethodref(invocationTargetClass, asm.cpi()); - invocationTargetCtorIdx = asm.cpi(); - asm.emitConstantPoolMethodref(superClass, initNameAndTypeIdx); - superCtorIdx = asm.cpi(); - asm.emitConstantPoolUTF8("java/lang/Object"); - asm.emitConstantPoolClass(asm.cpi()); - objectClass = asm.cpi(); - asm.emitConstantPoolUTF8("toString"); - asm.emitConstantPoolUTF8("()Ljava/lang/String;"); - asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); - asm.emitConstantPoolMethodref(objectClass, asm.cpi()); - toStringIdx = asm.cpi(); - asm.emitConstantPoolUTF8("Code"); - codeIdx = asm.cpi(); - asm.emitConstantPoolUTF8("Exceptions"); - exceptionsIdx = asm.cpi(); - } - - /** Constant pool entries required to be able to box/unbox primitive - types. Note that we don't emit these if we don't need them. */ - protected void emitBoxingContantPoolEntries() { - // * [UTF-8] "valueOf" - // * [UTF-8] "java/lang/Boolean" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(Z)Ljava/lang/Boolean;" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "booleanValue" - // * [UTF-8] "()Z" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Byte" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(B)Ljava/lang/Byte;" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "byteValue" - // * [UTF-8] "()B" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Character" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(C)Ljava/lang/Character;" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "charValue" - // * [UTF-8] "()C" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Double" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(D)Ljava/lang/Double;" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "doubleValue" - // * [UTF-8] "()D" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Float" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(F)Ljava/lang/Float;" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "floatValue" - // * [UTF-8] "()F" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Integer" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(I)Ljava/lang/Integer;" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "intValue" - // * [UTF-8] "()I" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Long" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(J)Ljava/lang/Long;" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "longValue" - // * [UTF-8] "()J" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Short" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(S)Ljava/lang/Short;" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "shortValue" - // * [UTF-8] "()S" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - - // valueOf-method name - asm.emitConstantPoolUTF8("valueOf"); - valueOfIdx = asm.cpi(); - - // Boolean - asm.emitConstantPoolUTF8("java/lang/Boolean"); - asm.emitConstantPoolClass(asm.cpi()); - booleanIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(Z)Ljava/lang/Boolean;"); - asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - booleanBoxIdx = asm.cpi(); - asm.emitConstantPoolUTF8("booleanValue"); - asm.emitConstantPoolUTF8("()Z"); - asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); - booleanUnboxIdx = asm.cpi(); - - // Byte - asm.emitConstantPoolUTF8("java/lang/Byte"); - asm.emitConstantPoolClass(asm.cpi()); - byteIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(B)Ljava/lang/Byte;"); - asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - byteBoxIdx = asm.cpi(); - asm.emitConstantPoolUTF8("byteValue"); - asm.emitConstantPoolUTF8("()B"); - asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); - byteUnboxIdx = asm.cpi(); - - // Character - asm.emitConstantPoolUTF8("java/lang/Character"); - asm.emitConstantPoolClass(asm.cpi()); - characterIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(C)Ljava/lang/Character;"); - asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - characterBoxIdx = asm.cpi(); - asm.emitConstantPoolUTF8("charValue"); - asm.emitConstantPoolUTF8("()C"); - asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); - characterUnboxIdx = asm.cpi(); - - // Double - asm.emitConstantPoolUTF8("java/lang/Double"); - asm.emitConstantPoolClass(asm.cpi()); - doubleIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(D)Ljava/lang/Double;"); - asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - doubleBoxIdx = asm.cpi(); - asm.emitConstantPoolUTF8("doubleValue"); - asm.emitConstantPoolUTF8("()D"); - asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); - doubleUnboxIdx = asm.cpi(); - - // Float - asm.emitConstantPoolUTF8("java/lang/Float"); - asm.emitConstantPoolClass(asm.cpi()); - floatIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(F)Ljava/lang/Float;"); - asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - floatBoxIdx = asm.cpi(); - asm.emitConstantPoolUTF8("floatValue"); - asm.emitConstantPoolUTF8("()F"); - asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); - floatUnboxIdx = asm.cpi(); - - // Integer - asm.emitConstantPoolUTF8("java/lang/Integer"); - asm.emitConstantPoolClass(asm.cpi()); - integerIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(I)Ljava/lang/Integer;"); - asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - integerBoxIdx = asm.cpi(); - asm.emitConstantPoolUTF8("intValue"); - asm.emitConstantPoolUTF8("()I"); - asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); - integerUnboxIdx = asm.cpi(); - - // Long - asm.emitConstantPoolUTF8("java/lang/Long"); - asm.emitConstantPoolClass(asm.cpi()); - longIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(J)Ljava/lang/Long;"); - asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - longBoxIdx = asm.cpi(); - asm.emitConstantPoolUTF8("longValue"); - asm.emitConstantPoolUTF8("()J"); - asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); - longUnboxIdx = asm.cpi(); - - // Short - asm.emitConstantPoolUTF8("java/lang/Short"); - asm.emitConstantPoolClass(asm.cpi()); - shortIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(S)Ljava/lang/Short;"); - asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - shortBoxIdx = asm.cpi(); - asm.emitConstantPoolUTF8("shortValue"); - asm.emitConstantPoolUTF8("()S"); - asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); - asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); - shortUnboxIdx = asm.cpi(); - } - - // Necessary because of Java's annoying promotion rules - protected static short add(short s1, short s2) { - return (short) (s1 + s2); - } - - protected static short sub(short s1, short s2) { - return (short) (s1 - s2); - } - - protected boolean isStatic() { - return Modifier.isStatic(modifiers); - } - - protected boolean isPrivate() { - return Modifier.isPrivate(modifiers); - } - - /** Returns class name in "internal" form (i.e., '/' separators - instead of '.') */ - protected static String getClassName - (Class c, boolean addPrefixAndSuffixForNonPrimitiveTypes) - { - if (c.isPrimitive()) { - if (c == Boolean.TYPE) { - return "Z"; - } else if (c == Byte.TYPE) { - return "B"; - } else if (c == Character.TYPE) { - return "C"; - } else if (c == Double.TYPE) { - return "D"; - } else if (c == Float.TYPE) { - return "F"; - } else if (c == Integer.TYPE) { - return "I"; - } else if (c == Long.TYPE) { - return "J"; - } else if (c == Short.TYPE) { - return "S"; - } else if (c == Void.TYPE) { - return "V"; - } - throw new InternalError("Should have found primitive type"); - } else if (c.isArray()) { - return "[" + getClassName(c.getComponentType(), true); - } else { - if (addPrefixAndSuffixForNonPrimitiveTypes) { - return internalize("L" + c.getName() + ";"); - } else { - return internalize(c.getName()); - } - } - } - - private static String internalize(String className) { - return className.replace('.', '/'); - } - - protected void emitConstructor() { - // Generate code into fresh code buffer - ClassFileAssembler cb = new ClassFileAssembler(); - // 0 incoming arguments - cb.setMaxLocals(1); - cb.opc_aload_0(); - cb.opc_invokespecial(superCtorIdx, 0, 0); - cb.opc_return(); - - // Emit method - emitMethod(initIdx, cb.getMaxLocals(), cb, null, null); - } - - // The descriptor's index in the constant pool must be (1 + - // nameIdx). "numArgs" must indicate ALL arguments, including the - // implicit "this" argument; double and long arguments each count - // as 2 in this count. The code buffer must NOT contain the code - // length. The exception table may be null, but if non-null must - // NOT contain the exception table's length. The checked exception - // indices may be null. - protected void emitMethod(short nameIdx, - int numArgs, - ClassFileAssembler code, - ClassFileAssembler exceptionTable, - short[] checkedExceptionIndices) - { - int codeLen = code.getLength(); - int excLen = 0; - if (exceptionTable != null) { - excLen = exceptionTable.getLength(); - if ((excLen % 8) != 0) { - throw new IllegalArgumentException("Illegal exception table"); - } - } - int attrLen = 12 + codeLen + excLen; - excLen = excLen / 8; // No-op if no exception table - - asm.emitShort(ACC_PUBLIC); - asm.emitShort(nameIdx); - asm.emitShort(add(nameIdx, S1)); - if (checkedExceptionIndices == null) { - // Code attribute only - asm.emitShort(S1); - } else { - // Code and Exceptions attributes - asm.emitShort(S2); - } - // Code attribute - asm.emitShort(codeIdx); - asm.emitInt(attrLen); - asm.emitShort(code.getMaxStack()); - asm.emitShort((short) Math.max(numArgs, code.getMaxLocals())); - asm.emitInt(codeLen); - asm.append(code); - asm.emitShort((short) excLen); - if (exceptionTable != null) { - asm.append(exceptionTable); - } - asm.emitShort(S0); // No additional attributes for Code attribute - if (checkedExceptionIndices != null) { - // Exceptions attribute - asm.emitShort(exceptionsIdx); - asm.emitInt(2 + 2 * checkedExceptionIndices.length); - asm.emitShort((short) checkedExceptionIndices.length); - for (int i = 0; i < checkedExceptionIndices.length; i++) { - asm.emitShort(checkedExceptionIndices[i]); - } - } - } - - protected short indexForPrimitiveType(Class type) { - if (type == Boolean.TYPE) { - return booleanIdx; - } else if (type == Byte.TYPE) { - return byteIdx; - } else if (type == Character.TYPE) { - return characterIdx; - } else if (type == Double.TYPE) { - return doubleIdx; - } else if (type == Float.TYPE) { - return floatIdx; - } else if (type == Integer.TYPE) { - return integerIdx; - } else if (type == Long.TYPE) { - return longIdx; - } else if (type == Short.TYPE) { - return shortIdx; - } - throw new InternalError("Should have found primitive type"); - } - - protected short boxingMethodForPrimitiveType(Class type) { - if (type == Boolean.TYPE) { - return booleanBoxIdx; - } else if (type == Byte.TYPE) { - return byteBoxIdx; - } else if (type == Character.TYPE) { - return characterBoxIdx; - } else if (type == Double.TYPE) { - return doubleBoxIdx; - } else if (type == Float.TYPE) { - return floatBoxIdx; - } else if (type == Integer.TYPE) { - return integerBoxIdx; - } else if (type == Long.TYPE) { - return longBoxIdx; - } else if (type == Short.TYPE) { - return shortBoxIdx; - } - throw new InternalError("Should have found primitive type"); - } - - /** Returns true for widening or identity conversions for primitive - types only */ - protected static boolean canWidenTo(Class type, Class otherType) { - if (!type.isPrimitive()) { - return false; - } - - // Widening conversions (from JVM spec): - // byte to short, int, long, float, or double - // short to int, long, float, or double - // char to int, long, float, or double - // int to long, float, or double - // long to float or double - // float to double - - if (type == Boolean.TYPE) { - if (otherType == Boolean.TYPE) { - return true; - } - } else if (type == Byte.TYPE) { - if ( otherType == Byte.TYPE - || otherType == Short.TYPE - || otherType == Integer.TYPE - || otherType == Long.TYPE - || otherType == Float.TYPE - || otherType == Double.TYPE) { - return true; - } - } else if (type == Short.TYPE) { - if ( otherType == Short.TYPE - || otherType == Integer.TYPE - || otherType == Long.TYPE - || otherType == Float.TYPE - || otherType == Double.TYPE) { - return true; - } - } else if (type == Character.TYPE) { - if ( otherType == Character.TYPE - || otherType == Integer.TYPE - || otherType == Long.TYPE - || otherType == Float.TYPE - || otherType == Double.TYPE) { - return true; - } - } else if (type == Integer.TYPE) { - if ( otherType == Integer.TYPE - || otherType == Long.TYPE - || otherType == Float.TYPE - || otherType == Double.TYPE) { - return true; - } - } else if (type == Long.TYPE) { - if ( otherType == Long.TYPE - || otherType == Float.TYPE - || otherType == Double.TYPE) { - return true; - } - } else if (type == Float.TYPE) { - if ( otherType == Float.TYPE - || otherType == Double.TYPE) { - return true; - } - } else if (type == Double.TYPE) { - if (otherType == Double.TYPE) { - return true; - } - } - - return false; - } - - /** Emits the widening bytecode for the given primitive conversion - (or none if the identity conversion). Requires that a primitive - conversion exists; i.e., canWidenTo must have already been - called and returned true. */ - protected static void emitWideningBytecodeForPrimitiveConversion - (ClassFileAssembler cb, - Class fromType, - Class toType) - { - // Note that widening conversions for integral types (i.e., "b2s", - // "s2i") are no-ops since values on the Java stack are - // sign-extended. - - // Widening conversions (from JVM spec): - // byte to short, int, long, float, or double - // short to int, long, float, or double - // char to int, long, float, or double - // int to long, float, or double - // long to float or double - // float to double - - if ( fromType == Byte.TYPE - || fromType == Short.TYPE - || fromType == Character.TYPE - || fromType == Integer.TYPE) { - if (toType == Long.TYPE) { - cb.opc_i2l(); - } else if (toType == Float.TYPE) { - cb.opc_i2f(); - } else if (toType == Double.TYPE) { - cb.opc_i2d(); - } - } else if (fromType == Long.TYPE) { - if (toType == Float.TYPE) { - cb.opc_l2f(); - } else if (toType == Double.TYPE) { - cb.opc_l2d(); - } - } else if (fromType == Float.TYPE) { - if (toType == Double.TYPE) { - cb.opc_f2d(); - } - } - - // Otherwise, was identity or no-op conversion. Fall through. - } - - protected short unboxingMethodForPrimitiveType(Class primType) { - if (primType == Boolean.TYPE) { - return booleanUnboxIdx; - } else if (primType == Byte.TYPE) { - return byteUnboxIdx; - } else if (primType == Character.TYPE) { - return characterUnboxIdx; - } else if (primType == Short.TYPE) { - return shortUnboxIdx; - } else if (primType == Integer.TYPE) { - return integerUnboxIdx; - } else if (primType == Long.TYPE) { - return longUnboxIdx; - } else if (primType == Float.TYPE) { - return floatUnboxIdx; - } else if (primType == Double.TYPE) { - return doubleUnboxIdx; - } - throw new InternalError("Illegal primitive type " + primType.getName()); - } - - protected static final Class[] primitiveTypes = new Class[] { - Boolean.TYPE, - Byte.TYPE, - Character.TYPE, - Short.TYPE, - Integer.TYPE, - Long.TYPE, - Float.TYPE, - Double.TYPE - }; - - /** We don't consider "Void" to be a primitive type */ - protected static boolean isPrimitive(Class c) { - return (c.isPrimitive() && c != Void.TYPE); - } - - protected int typeSizeInStackSlots(Class c) { - if (c == Void.TYPE) { - return 0; - } - if (c == Long.TYPE || c == Double.TYPE) { - return 2; - } - return 1; - } - - private ClassFileAssembler illegalArgumentCodeBuffer; - protected ClassFileAssembler illegalArgumentCodeBuffer() { - if (illegalArgumentCodeBuffer == null) { - illegalArgumentCodeBuffer = new ClassFileAssembler(); - illegalArgumentCodeBuffer.opc_new(illegalArgumentClass); - illegalArgumentCodeBuffer.opc_dup(); - illegalArgumentCodeBuffer.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); - illegalArgumentCodeBuffer.opc_athrow(); - } - - return illegalArgumentCodeBuffer; - } -} diff --git a/src/java.base/share/classes/jdk/internal/reflect/ByteVectorFactory.java b/src/java.base/share/classes/jdk/internal/reflect/ByteVectorFactory.java deleted file mode 100644 index 3557bd5c5157d..0000000000000 --- a/src/java.base/share/classes/jdk/internal/reflect/ByteVectorFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.reflect; - -class ByteVectorFactory { - static ByteVector create() { - return new ByteVectorImpl(); - } - - static ByteVector create(int sz) { - return new ByteVectorImpl(sz); - } -} diff --git a/src/java.base/share/classes/jdk/internal/reflect/ByteVectorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/ByteVectorImpl.java deleted file mode 100644 index b0f9d81f7cf4f..0000000000000 --- a/src/java.base/share/classes/jdk/internal/reflect/ByteVectorImpl.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.reflect; - -class ByteVectorImpl implements ByteVector { - private byte[] data; - private int pos; - - public ByteVectorImpl() { - this(100); - } - - public ByteVectorImpl(int sz) { - data = new byte[sz]; - pos = -1; - } - - public int getLength() { - return pos + 1; - } - - public byte get(int index) { - if (index >= data.length) { - resize(index); - pos = index; - } - return data[index]; - } - - public void put(int index, byte value) { - if (index >= data.length) { - resize(index); - pos = index; - } - data[index] = value; - } - - public void add(byte value) { - if (++pos >= data.length) { - resize(pos); - } - data[pos] = value; - } - - public void trim() { - if (pos != data.length - 1) { - byte[] newData = new byte[pos + 1]; - System.arraycopy(data, 0, newData, 0, pos + 1); - data = newData; - } - } - - public byte[] getData() { - return data; - } - - private void resize(int minSize) { - if (minSize <= 2 * data.length) { - minSize = 2 * data.length; - } - byte[] newData = new byte[minSize]; - System.arraycopy(data, 0, newData, 0, data.length); - data = newData; - } -} diff --git a/src/java.base/share/classes/jdk/internal/reflect/ClassDefiner.java b/src/java.base/share/classes/jdk/internal/reflect/ClassDefiner.java deleted file mode 100644 index 185f61b9ba165..0000000000000 --- a/src/java.base/share/classes/jdk/internal/reflect/ClassDefiner.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2001, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.reflect; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -import jdk.internal.access.JavaLangAccess; -import jdk.internal.access.SharedSecrets; - -/** Utility class which assists in calling defineClass() by - * creating a new class loader which delegates to the one needed in - * order for proper resolution of the given bytecodes to occur. - * - * This is only used to define SerializationConstructorAccessor. - */ - -class ClassDefiner { - static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - - /**

          We define generated code into a new class loader which - delegates to the defining loader of the target class. It is - necessary for the VM to be able to resolve references to the - target class from the generated bytecodes, which could not occur - if the generated code was loaded into the bootstrap class - loader.

          - -

          There are two primary reasons for creating a new loader - instead of defining these bytecodes directly into the defining - loader of the target class: first, it avoids any possible - security risk of having these bytecodes in the same loader. - Second, it allows the generated bytecodes to be unloaded earlier - than would otherwise be possible, decreasing run-time - footprint.

          - */ - static Class defineClass(String name, byte[] bytes, int off, int len, - final ClassLoader parentClassLoader) - { - @SuppressWarnings("removal") - ClassLoader newLoader = AccessController.doPrivileged( - new PrivilegedAction() { - public ClassLoader run() { - return new DelegatingClassLoader(parentClassLoader); - } - }); - return JLA.defineClass(newLoader, name, bytes, null, "__ClassDefiner__"); - } -} - - -// NOTE: this class's name and presence are known to the virtual -// machine as of the fix for 4474172. -class DelegatingClassLoader extends ClassLoader { - DelegatingClassLoader(ClassLoader parent) { - super(parent); - } -} diff --git a/src/java.base/share/classes/jdk/internal/reflect/ClassFileAssembler.java b/src/java.base/share/classes/jdk/internal/reflect/ClassFileAssembler.java deleted file mode 100644 index 31ddb675667c2..0000000000000 --- a/src/java.base/share/classes/jdk/internal/reflect/ClassFileAssembler.java +++ /dev/null @@ -1,671 +0,0 @@ -/* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.reflect; - -import sun.nio.cs.UTF_8; - -class ClassFileAssembler implements ClassFileConstants { - private ByteVector vec; - private short cpIdx = 0; - - public ClassFileAssembler() { - this(ByteVectorFactory.create()); - } - - public ClassFileAssembler(ByteVector vec) { - this.vec = vec; - } - - public ByteVector getData() { - return vec; - } - - /** Length in bytes */ - public short getLength() { - return (short) vec.getLength(); - } - - public void emitMagicAndVersion() { - emitInt(0xCAFEBABE); - emitShort((short) 0); - emitShort((short) 49); - } - - public void emitInt(int val) { - emitByte((byte) (val >> 24)); - emitByte((byte) ((val >> 16) & 0xFF)); - emitByte((byte) ((val >> 8) & 0xFF)); - emitByte((byte) (val & 0xFF)); - } - - public void emitShort(short val) { - emitByte((byte) ((val >> 8) & 0xFF)); - emitByte((byte) (val & 0xFF)); - } - - // Support for labels; package-private - void emitShort(short bci, short val) { - vec.put(bci, (byte) ((val >> 8) & 0xFF)); - vec.put(bci + 1, (byte) (val & 0xFF)); - } - - public void emitByte(byte val) { - vec.add(val); - } - - public void append(ClassFileAssembler asm) { - append(asm.vec); - } - - public void append(ByteVector vec) { - for (int i = 0; i < vec.getLength(); i++) { - emitByte(vec.get(i)); - } - } - - /** Keeps track of the current (one-based) constant pool index; - incremented after emitting one of the following constant pool - entries. Can fetch the current constant pool index for use in - later entries. Index points at the last valid constant pool - entry; initially invalid. It is illegal to fetch the constant - pool index before emitting at least one constant pool entry. */ - public short cpi() { - if (cpIdx == 0) { - throw new RuntimeException("Illegal use of ClassFileAssembler"); - } - return cpIdx; - } - - public void emitConstantPoolUTF8(String str) { - byte[] bytes = str.getBytes(UTF_8.INSTANCE); - emitByte(CONSTANT_Utf8); - emitShort((short) bytes.length); - for (int i = 0; i < bytes.length; i++) { - emitByte(bytes[i]); - } - cpIdx++; - } - - public void emitConstantPoolClass(short index) { - emitByte(CONSTANT_Class); - emitShort(index); - cpIdx++; - } - - public void emitConstantPoolNameAndType(short nameIndex, short typeIndex) { - emitByte(CONSTANT_NameAndType); - emitShort(nameIndex); - emitShort(typeIndex); - cpIdx++; - } - - public void emitConstantPoolFieldref - (short classIndex, short nameAndTypeIndex) - { - emitByte(CONSTANT_Fieldref); - emitShort(classIndex); - emitShort(nameAndTypeIndex); - cpIdx++; - } - - public void emitConstantPoolMethodref - (short classIndex, short nameAndTypeIndex) - { - emitByte(CONSTANT_Methodref); - emitShort(classIndex); - emitShort(nameAndTypeIndex); - cpIdx++; - } - - public void emitConstantPoolInterfaceMethodref - (short classIndex, short nameAndTypeIndex) - { - emitByte(CONSTANT_InterfaceMethodref); - emitShort(classIndex); - emitShort(nameAndTypeIndex); - cpIdx++; - } - - public void emitConstantPoolString(short utf8Index) { - emitByte(CONSTANT_String); - emitShort(utf8Index); - cpIdx++; - } - - //---------------------------------------------------------------------- - // Opcodes. Keeps track of maximum stack and locals. Make a new - // assembler for each piece of assembled code, then append the - // result to the previous assembler's class file. - // - - private int stack = 0; - private int maxStack = 0; - private int maxLocals = 0; - - private void incStack() { - setStack(stack + 1); - } - - private void decStack() { - --stack; - } - - public short getMaxStack() { - return (short) maxStack; - } - - public short getMaxLocals() { - return (short) maxLocals; - } - - /** It's necessary to be able to specify the number of arguments at - the beginning of the method (which translates to the initial - value of max locals) */ - public void setMaxLocals(int maxLocals) { - this.maxLocals = maxLocals; - } - - /** Needed to do flow control. Returns current stack depth. */ - public int getStack() { - return stack; - } - - /** Needed to do flow control. */ - public void setStack(int value) { - stack = value; - if (stack > maxStack) { - maxStack = stack; - } - } - - //-----------// - // Constants // - //-----------// - - public void opc_aconst_null() { - emitByte(opc_aconst_null); - incStack(); - } - - public void opc_sipush(short constant) { - emitByte(opc_sipush); - emitShort(constant); - incStack(); - } - - public void opc_ldc(byte cpIdx) { - emitByte(opc_ldc); - emitByte(cpIdx); - incStack(); - } - - //---------------------------------// - // Local variable loads and stores // - //---------------------------------// - - public void opc_iload_0() { - emitByte(opc_iload_0); - if (maxLocals < 1) maxLocals = 1; - incStack(); - } - - public void opc_iload_1() { - emitByte(opc_iload_1); - if (maxLocals < 2) maxLocals = 2; - incStack(); - } - - public void opc_iload_2() { - emitByte(opc_iload_2); - if (maxLocals < 3) maxLocals = 3; - incStack(); - } - - public void opc_iload_3() { - emitByte(opc_iload_3); - if (maxLocals < 4) maxLocals = 4; - incStack(); - } - - public void opc_lload_0() { - emitByte(opc_lload_0); - if (maxLocals < 2) maxLocals = 2; - incStack(); - incStack(); - } - - public void opc_lload_1() { - emitByte(opc_lload_1); - if (maxLocals < 3) maxLocals = 3; - incStack(); - incStack(); - } - - public void opc_lload_2() { - emitByte(opc_lload_2); - if (maxLocals < 4) maxLocals = 4; - incStack(); - incStack(); - } - - public void opc_lload_3() { - emitByte(opc_lload_3); - if (maxLocals < 5) maxLocals = 5; - incStack(); - incStack(); - } - - public void opc_fload_0() { - emitByte(opc_fload_0); - if (maxLocals < 1) maxLocals = 1; - incStack(); - } - - public void opc_fload_1() { - emitByte(opc_fload_1); - if (maxLocals < 2) maxLocals = 2; - incStack(); - } - - public void opc_fload_2() { - emitByte(opc_fload_2); - if (maxLocals < 3) maxLocals = 3; - incStack(); - } - - public void opc_fload_3() { - emitByte(opc_fload_3); - if (maxLocals < 4) maxLocals = 4; - incStack(); - } - - public void opc_dload_0() { - emitByte(opc_dload_0); - if (maxLocals < 2) maxLocals = 2; - incStack(); - incStack(); - } - - public void opc_dload_1() { - emitByte(opc_dload_1); - if (maxLocals < 3) maxLocals = 3; - incStack(); - incStack(); - } - - public void opc_dload_2() { - emitByte(opc_dload_2); - if (maxLocals < 4) maxLocals = 4; - incStack(); - incStack(); - } - - public void opc_dload_3() { - emitByte(opc_dload_3); - if (maxLocals < 5) maxLocals = 5; - incStack(); - incStack(); - } - - public void opc_aload_0() { - emitByte(opc_aload_0); - if (maxLocals < 1) maxLocals = 1; - incStack(); - } - - public void opc_aload_1() { - emitByte(opc_aload_1); - if (maxLocals < 2) maxLocals = 2; - incStack(); - } - - public void opc_aload_2() { - emitByte(opc_aload_2); - if (maxLocals < 3) maxLocals = 3; - incStack(); - } - - public void opc_aload_3() { - emitByte(opc_aload_3); - if (maxLocals < 4) maxLocals = 4; - incStack(); - } - - public void opc_aaload() { - emitByte(opc_aaload); - decStack(); - } - - public void opc_astore_0() { - emitByte(opc_astore_0); - if (maxLocals < 1) maxLocals = 1; - decStack(); - } - - public void opc_astore_1() { - emitByte(opc_astore_1); - if (maxLocals < 2) maxLocals = 2; - decStack(); - } - - public void opc_astore_2() { - emitByte(opc_astore_2); - if (maxLocals < 3) maxLocals = 3; - decStack(); - } - - public void opc_astore_3() { - emitByte(opc_astore_3); - if (maxLocals < 4) maxLocals = 4; - decStack(); - } - - //--------------------// - // Stack manipulation // - //--------------------// - - public void opc_pop() { - emitByte(opc_pop); - decStack(); - } - - public void opc_dup() { - emitByte(opc_dup); - incStack(); - } - - public void opc_dup_x1() { - emitByte(opc_dup_x1); - incStack(); - } - - public void opc_swap() { - emitByte(opc_swap); - } - - //---------------------------// - // Widening conversions only // - //---------------------------// - - public void opc_i2l() { - emitByte(opc_i2l); - } - - public void opc_i2f() { - emitByte(opc_i2f); - } - - public void opc_i2d() { - emitByte(opc_i2d); - } - - public void opc_l2f() { - emitByte(opc_l2f); - } - - public void opc_l2d() { - emitByte(opc_l2d); - } - - public void opc_f2d() { - emitByte(opc_f2d); - } - - //--------------// - // Control flow // - //--------------// - - public void opc_ifeq(short bciOffset) { - emitByte(opc_ifeq); - emitShort(bciOffset); - decStack(); - } - - /** Control flow with forward-reference BCI. Stack assumes - straight-through control flow. */ - public void opc_ifeq(Label l) { - short instrBCI = getLength(); - emitByte(opc_ifeq); - l.add(this, instrBCI, getLength(), getStack() - 1); - emitShort((short) -1); // Must be patched later - } - - public void opc_if_icmpeq(short bciOffset) { - emitByte(opc_if_icmpeq); - emitShort(bciOffset); - setStack(getStack() - 2); - } - - /** Control flow with forward-reference BCI. Stack assumes straight - control flow. */ - public void opc_if_icmpeq(Label l) { - short instrBCI = getLength(); - emitByte(opc_if_icmpeq); - l.add(this, instrBCI, getLength(), getStack() - 2); - emitShort((short) -1); // Must be patched later - } - - public void opc_goto(short bciOffset) { - emitByte(opc_goto); - emitShort(bciOffset); - } - - /** Control flow with forward-reference BCI. Stack assumes straight - control flow. */ - public void opc_goto(Label l) { - short instrBCI = getLength(); - emitByte(opc_goto); - l.add(this, instrBCI, getLength(), getStack()); - emitShort((short) -1); // Must be patched later - } - - public void opc_ifnull(short bciOffset) { - emitByte(opc_ifnull); - emitShort(bciOffset); - decStack(); - } - - /** Control flow with forward-reference BCI. Stack assumes straight - control flow. */ - public void opc_ifnull(Label l) { - short instrBCI = getLength(); - emitByte(opc_ifnull); - l.add(this, instrBCI, getLength(), getStack() - 1); - emitShort((short) -1); // Must be patched later - decStack(); - } - - public void opc_ifnonnull(short bciOffset) { - emitByte(opc_ifnonnull); - emitShort(bciOffset); - decStack(); - } - - /** Control flow with forward-reference BCI. Stack assumes straight - control flow. */ - public void opc_ifnonnull(Label l) { - short instrBCI = getLength(); - emitByte(opc_ifnonnull); - l.add(this, instrBCI, getLength(), getStack() - 1); - emitShort((short) -1); // Must be patched later - decStack(); - } - - //---------------------// - // Return instructions // - //---------------------// - - public void opc_ireturn() { - emitByte(opc_ireturn); - setStack(0); - } - - public void opc_lreturn() { - emitByte(opc_lreturn); - setStack(0); - } - - public void opc_freturn() { - emitByte(opc_freturn); - setStack(0); - } - - public void opc_dreturn() { - emitByte(opc_dreturn); - setStack(0); - } - - public void opc_areturn() { - emitByte(opc_areturn); - setStack(0); - } - - public void opc_return() { - emitByte(opc_return); - setStack(0); - } - - //------------------// - // Field operations // - //------------------// - - public void opc_getstatic(short fieldIndex, int fieldSizeInStackSlots) { - emitByte(opc_getstatic); - emitShort(fieldIndex); - setStack(getStack() + fieldSizeInStackSlots); - } - - public void opc_putstatic(short fieldIndex, int fieldSizeInStackSlots) { - emitByte(opc_putstatic); - emitShort(fieldIndex); - setStack(getStack() - fieldSizeInStackSlots); - } - - public void opc_getfield(short fieldIndex, int fieldSizeInStackSlots) { - emitByte(opc_getfield); - emitShort(fieldIndex); - setStack(getStack() + fieldSizeInStackSlots - 1); - } - - public void opc_putfield(short fieldIndex, int fieldSizeInStackSlots) { - emitByte(opc_putfield); - emitShort(fieldIndex); - setStack(getStack() - fieldSizeInStackSlots - 1); - } - - //--------------------// - // Method invocations // - //--------------------// - - /** Long and double arguments and return types count as 2 arguments; - other values count as 1. */ - public void opc_invokevirtual(short methodIndex, - int numArgs, - int numReturnValues) - { - emitByte(opc_invokevirtual); - emitShort(methodIndex); - setStack(getStack() - numArgs - 1 + numReturnValues); - } - - /** Long and double arguments and return types count as 2 arguments; - other values count as 1. */ - public void opc_invokespecial(short methodIndex, - int numArgs, - int numReturnValues) - { - emitByte(opc_invokespecial); - emitShort(methodIndex); - setStack(getStack() - numArgs - 1 + numReturnValues); - } - - /** Long and double arguments and return types count as 2 arguments; - other values count as 1. */ - public void opc_invokestatic(short methodIndex, - int numArgs, - int numReturnValues) - { - emitByte(opc_invokestatic); - emitShort(methodIndex); - setStack(getStack() - numArgs + numReturnValues); - } - - /** Long and double arguments and return types count as 2 arguments; - other values count as 1. */ - public void opc_invokeinterface(short methodIndex, - int numArgs, - byte count, - int numReturnValues) - { - emitByte(opc_invokeinterface); - emitShort(methodIndex); - emitByte(count); - emitByte((byte) 0); - setStack(getStack() - numArgs - 1 + numReturnValues); - } - - //--------------// - // Array length // - //--------------// - - public void opc_arraylength() { - emitByte(opc_arraylength); - } - - //-----// - // New // - //-----// - - public void opc_new(short classIndex) { - emitByte(opc_new); - emitShort(classIndex); - incStack(); - } - - //--------// - // Athrow // - //--------// - - public void opc_athrow() { - emitByte(opc_athrow); - setStack(1); - } - - //--------------------------// - // Checkcast and instanceof // - //--------------------------// - - /** Assumes the checkcast succeeds */ - public void opc_checkcast(short classIndex) { - emitByte(opc_checkcast); - emitShort(classIndex); - } - - public void opc_instanceof(short classIndex) { - emitByte(opc_instanceof); - emitShort(classIndex); - } -} diff --git a/src/java.base/share/classes/jdk/internal/reflect/ClassFileConstants.java b/src/java.base/share/classes/jdk/internal/reflect/ClassFileConstants.java deleted file mode 100644 index 3562a8d5c7291..0000000000000 --- a/src/java.base/share/classes/jdk/internal/reflect/ClassFileConstants.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.reflect; - -/** Minimal set of class file constants for assembly of field and - method accessors. */ - -interface ClassFileConstants { - // Constants - public static final byte opc_aconst_null = (byte) 0x1; - public static final byte opc_sipush = (byte) 0x11; - public static final byte opc_ldc = (byte) 0x12; - - // Local variable loads and stores - public static final byte opc_iload_0 = (byte) 0x1a; - public static final byte opc_iload_1 = (byte) 0x1b; - public static final byte opc_iload_2 = (byte) 0x1c; - public static final byte opc_iload_3 = (byte) 0x1d; - public static final byte opc_lload_0 = (byte) 0x1e; - public static final byte opc_lload_1 = (byte) 0x1f; - public static final byte opc_lload_2 = (byte) 0x20; - public static final byte opc_lload_3 = (byte) 0x21; - public static final byte opc_fload_0 = (byte) 0x22; - public static final byte opc_fload_1 = (byte) 0x23; - public static final byte opc_fload_2 = (byte) 0x24; - public static final byte opc_fload_3 = (byte) 0x25; - public static final byte opc_dload_0 = (byte) 0x26; - public static final byte opc_dload_1 = (byte) 0x27; - public static final byte opc_dload_2 = (byte) 0x28; - public static final byte opc_dload_3 = (byte) 0x29; - public static final byte opc_aload_0 = (byte) 0x2a; - public static final byte opc_aload_1 = (byte) 0x2b; - public static final byte opc_aload_2 = (byte) 0x2c; - public static final byte opc_aload_3 = (byte) 0x2d; - public static final byte opc_aaload = (byte) 0x32; - public static final byte opc_astore_0 = (byte) 0x4b; - public static final byte opc_astore_1 = (byte) 0x4c; - public static final byte opc_astore_2 = (byte) 0x4d; - public static final byte opc_astore_3 = (byte) 0x4e; - - // Stack manipulation - public static final byte opc_pop = (byte) 0x57; - public static final byte opc_dup = (byte) 0x59; - public static final byte opc_dup_x1 = (byte) 0x5a; - public static final byte opc_swap = (byte) 0x5f; - - // Conversions - public static final byte opc_i2l = (byte) 0x85; - public static final byte opc_i2f = (byte) 0x86; - public static final byte opc_i2d = (byte) 0x87; - public static final byte opc_l2i = (byte) 0x88; - public static final byte opc_l2f = (byte) 0x89; - public static final byte opc_l2d = (byte) 0x8a; - public static final byte opc_f2i = (byte) 0x8b; - public static final byte opc_f2l = (byte) 0x8c; - public static final byte opc_f2d = (byte) 0x8d; - public static final byte opc_d2i = (byte) 0x8e; - public static final byte opc_d2l = (byte) 0x8f; - public static final byte opc_d2f = (byte) 0x90; - public static final byte opc_i2b = (byte) 0x91; - public static final byte opc_i2c = (byte) 0x92; - public static final byte opc_i2s = (byte) 0x93; - - // Control flow - public static final byte opc_ifeq = (byte) 0x99; - public static final byte opc_if_icmpeq = (byte) 0x9f; - public static final byte opc_goto = (byte) 0xa7; - - // Return instructions - public static final byte opc_ireturn = (byte) 0xac; - public static final byte opc_lreturn = (byte) 0xad; - public static final byte opc_freturn = (byte) 0xae; - public static final byte opc_dreturn = (byte) 0xaf; - public static final byte opc_areturn = (byte) 0xb0; - public static final byte opc_return = (byte) 0xb1; - - // Field operations - public static final byte opc_getstatic = (byte) 0xb2; - public static final byte opc_putstatic = (byte) 0xb3; - public static final byte opc_getfield = (byte) 0xb4; - public static final byte opc_putfield = (byte) 0xb5; - - // Method invocations - public static final byte opc_invokevirtual = (byte) 0xb6; - public static final byte opc_invokespecial = (byte) 0xb7; - public static final byte opc_invokestatic = (byte) 0xb8; - public static final byte opc_invokeinterface = (byte) 0xb9; - - // Array length - public static final byte opc_arraylength = (byte) 0xbe; - - // New - public static final byte opc_new = (byte) 0xbb; - - // Athrow - public static final byte opc_athrow = (byte) 0xbf; - - // Checkcast and instanceof - public static final byte opc_checkcast = (byte) 0xc0; - public static final byte opc_instanceof = (byte) 0xc1; - - // Ifnull and ifnonnull - public static final byte opc_ifnull = (byte) 0xc6; - public static final byte opc_ifnonnull = (byte) 0xc7; - - // Constant pool tags - public static final byte CONSTANT_Class = (byte) 7; - public static final byte CONSTANT_Fieldref = (byte) 9; - public static final byte CONSTANT_Methodref = (byte) 10; - public static final byte CONSTANT_InterfaceMethodref = (byte) 11; - public static final byte CONSTANT_NameAndType = (byte) 12; - public static final byte CONSTANT_String = (byte) 8; - public static final byte CONSTANT_Utf8 = (byte) 1; - - // Access flags - public static final short ACC_PUBLIC = (short) 0x0001; -} diff --git a/src/java.base/share/classes/jdk/internal/reflect/ConstructorAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/ConstructorAccessorImpl.java index 36f73b29cc3e3..18e69439ac78e 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ConstructorAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/ConstructorAccessorImpl.java @@ -27,12 +27,7 @@ import java.lang.reflect.InvocationTargetException; -/** Package-private implementation of the ConstructorAccessor - interface which has access to all classes and all fields, - regardless of language restrictions. See MagicAccessorImpl. */ - -abstract class ConstructorAccessorImpl extends MagicAccessorImpl - implements ConstructorAccessor { +abstract class ConstructorAccessorImpl implements ConstructorAccessor { /** Matches specification in {@link java.lang.reflect.Constructor} */ public abstract Object newInstance(Object[] args) throws InstantiationException, diff --git a/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java index baeb6bf895692..be832f2e393f4 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java @@ -28,12 +28,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; -/** Package-private implementation of the FieldAccessor interface - which has access to all classes and all fields, regardless of - language restrictions. See MagicAccessorImpl. */ - -abstract class FieldAccessorImpl extends MagicAccessorImpl - implements FieldAccessor { +abstract class FieldAccessorImpl implements FieldAccessor { protected final Field field; FieldAccessorImpl(Field field) { diff --git a/src/java.base/share/classes/jdk/internal/reflect/Label.java b/src/java.base/share/classes/jdk/internal/reflect/Label.java deleted file mode 100644 index eb531530f4a59..0000000000000 --- a/src/java.base/share/classes/jdk/internal/reflect/Label.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.reflect; - -import java.util.List; -import java.util.ArrayList; - -/** Allows forward references in bytecode streams emitted by - ClassFileAssembler. Assumes that the start of the method body is - the first byte in the assembler's buffer. May be used at more than - one branch site. */ - -class Label { - static class PatchInfo { - PatchInfo(ClassFileAssembler asm, - short instrBCI, - short patchBCI, - int stackDepth) - { - this.asm = asm; - this.instrBCI = instrBCI; - this.patchBCI = patchBCI; - this.stackDepth = stackDepth; - } - // This won't work for more than one assembler anyway, so this is - // unnecessary - final ClassFileAssembler asm; - final short instrBCI; - final short patchBCI; - final int stackDepth; - } - private final List patches = new ArrayList<>(); - - public Label() { - } - - void add(ClassFileAssembler asm, - short instrBCI, - short patchBCI, - int stackDepth) - { - patches.add(new PatchInfo(asm, instrBCI, patchBCI, stackDepth)); - } - - public void bind() { - for (PatchInfo patch : patches){ - short curBCI = patch.asm.getLength(); - short offset = (short) (curBCI - patch.instrBCI); - patch.asm.emitShort(patch.patchBCI, offset); - patch.asm.setStack(patch.stackDepth); - } - } -} diff --git a/src/java.base/share/classes/jdk/internal/reflect/MagicAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MagicAccessorImpl.java deleted file mode 100644 index e464e3b658413..0000000000000 --- a/src/java.base/share/classes/jdk/internal/reflect/MagicAccessorImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.reflect; - -/**

          MagicAccessorImpl (named for parity with FieldAccessorImpl and - others, not because it actually implements an interface) is a - marker class in the hierarchy. All subclasses of this class are - "magically" granted access by the VM to otherwise inaccessible - fields and methods of other classes. It is used to hold the code - for dynamically-generated FieldAccessorImpl and MethodAccessorImpl - subclasses. (Use of the word "unsafe" was avoided in this class's - name to avoid confusion with {@link jdk.internal.misc.Unsafe}.)

          - -

          The bug fix for 4486457 also necessitated disabling - verification for this class and all subclasses, as opposed to just - SerializationConstructorAccessorImpl and subclasses, to avoid - having to indicate to the VM which of these dynamically-generated - stub classes were known to be able to pass the verifier.

          - -

          Do not change the name of this class without also changing the - VM's code.

          */ - -class MagicAccessorImpl { -} diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorImpl.java index 1ef40d207f02c..a8d324d413c74 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorImpl.java @@ -27,11 +27,7 @@ import java.lang.reflect.InvocationTargetException; -/**

          Package-private implementation of the MethodAccessor interface - which has access to all classes and all fields, regardless of - language restrictions. See MagicAccessor.

          - -

          This class is known to the VM; do not change its name without +/**

          This class is known to the VM; do not change its name without also changing the VM's code.

          NOTE: ALL methods of subclasses are skipped during security @@ -40,8 +36,7 @@ methods for java.lang.reflect.Method.invoke().

          */ -abstract class MethodAccessorImpl extends MagicAccessorImpl - implements MethodAccessor { +abstract class MethodAccessorImpl implements MethodAccessor { /** Matches specification in {@link java.lang.reflect.Method} */ public abstract Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException; diff --git a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java index 9a31c5402d408..b0d9c7154cdec 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java +++ b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java @@ -334,16 +334,8 @@ public final Constructor newConstructorForSerialization(Class cl) { private final Constructor generateConstructor(Class cl, Constructor constructorToCall) { - ConstructorAccessor acc; - if (useOldSerializableConstructor()) { - acc = new SerializationConstructorAccessorGenerator(). - generateSerializationConstructor(cl, - constructorToCall.getParameterTypes(), - constructorToCall.getModifiers(), - constructorToCall.getDeclaringClass()); - } else { - acc = MethodHandleAccessorFactory.newSerializableConstructorAccessor(cl, constructorToCall); - } + ConstructorAccessor acc = MethodHandleAccessorFactory + .newSerializableConstructorAccessor(cl, constructorToCall); // Unlike other root constructors, this constructor is not copied for mutation // but directly mutated, as it is not cached. To cache this constructor, // setAccessible call must be done on a copy and return that copy instead. @@ -507,10 +499,6 @@ static boolean useNativeAccessorOnly() { return config().useNativeAccessorOnly; } - static boolean useOldSerializableConstructor() { - return config().useOldSerializableConstructor; - } - private static boolean disableSerialConstructorChecks() { return config().disableSerialConstructorChecks; } @@ -527,7 +515,6 @@ private static boolean disableSerialConstructorChecks() { private static @Stable Config config; private static final Config DEFAULT_CONFIG = new Config(false, // useNativeAccessorOnly - false, // useOldSerializeableConstructor false); // disableSerialConstructorChecks /** @@ -542,7 +529,6 @@ private static boolean disableSerialConstructorChecks() { * is to override them. */ private record Config(boolean useNativeAccessorOnly, - boolean useOldSerializableConstructor, boolean disableSerialConstructorChecks) { } @@ -566,12 +552,10 @@ private static Config loadConfig() { Properties props = GetPropertyAction.privilegedGetProperties(); boolean useNativeAccessorOnly = "true".equals(props.getProperty("jdk.reflect.useNativeAccessorOnly")); - boolean useOldSerializableConstructor = - "true".equals(props.getProperty("jdk.reflect.useOldSerializableConstructor")); boolean disableSerialConstructorChecks = "true".equals(props.getProperty("jdk.disableSerialConstructorChecks")); - return new Config(useNativeAccessorOnly, useOldSerializableConstructor, disableSerialConstructorChecks); + return new Config(useNativeAccessorOnly, disableSerialConstructorChecks); } /** diff --git a/src/java.base/share/classes/jdk/internal/reflect/SerializationConstructorAccessorGenerator.java b/src/java.base/share/classes/jdk/internal/reflect/SerializationConstructorAccessorGenerator.java deleted file mode 100644 index 1f9645a3e72c8..0000000000000 --- a/src/java.base/share/classes/jdk/internal/reflect/SerializationConstructorAccessorGenerator.java +++ /dev/null @@ -1,725 +0,0 @@ -/* - * Copyright (c) 2001, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.reflect; - -import java.security.AccessController; -import java.security.PrivilegedAction; - - -/** Generator for jdk.internal.reflect.SerializationConstructorAccessorImpl - objects using bytecodes to implement a constructor for serialization - returned by ReflectionFactory::newConstructorForSerialization. */ - -class SerializationConstructorAccessorGenerator extends AccessorGenerator { - - private static final short NUM_BASE_CPOOL_ENTRIES = (short) 12; - // One for invoke() plus one for constructor - private static final short NUM_METHODS = (short) 2; - // Only used if forSerialization is true - private static final short NUM_SERIALIZATION_CPOOL_ENTRIES = (short) 2; - - private static volatile int methodSymnum; - private static volatile int constructorSymnum; - private static volatile int serializationConstructorSymnum; - - private Class declaringClass; - private Class[] parameterTypes; - private Class returnType; - private boolean isConstructor; - private boolean forSerialization; - - private short targetMethodRef; - private short invokeIdx; - private short invokeDescriptorIdx; - // Constant pool index of CONSTANT_Class_info for first - // non-primitive parameter type. Should be incremented by 2. - private short nonPrimitiveParametersBaseIdx; - - SerializationConstructorAccessorGenerator() { - } - - /** This routine is not thread-safe */ - public SerializationConstructorAccessorImpl - generateSerializationConstructor(Class declaringClass, - Class[] parameterTypes, - int modifiers, - Class targetConstructorClass) - { - return (SerializationConstructorAccessorImpl) - generate(declaringClass, - "", - parameterTypes, - Void.TYPE, - modifiers, - true, - true, - targetConstructorClass); - } - - /** This routine is not thread-safe */ - @SuppressWarnings("removal") - private MagicAccessorImpl generate(final Class declaringClass, - String name, - Class[] parameterTypes, - Class returnType, - int modifiers, - boolean isConstructor, - boolean forSerialization, - Class serializationTargetClass) - { - ByteVector vec = ByteVectorFactory.create(); - asm = new ClassFileAssembler(vec); - this.declaringClass = declaringClass; - this.parameterTypes = parameterTypes; - this.returnType = returnType; - this.modifiers = modifiers; - this.isConstructor = isConstructor; - this.forSerialization = forSerialization; - - asm.emitMagicAndVersion(); - - // Constant pool entries: - // ( * = Boxing information: optional) - // (+ = Shared entries provided by AccessorGenerator) - // (^ = Only present if generating SerializationConstructorAccessor) - // [UTF-8] [This class's name] - // [CONSTANT_Class_info] for above - // [UTF-8] "jdk/internal/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" - // [CONSTANT_Class_info] for above - // [UTF-8] [Target class's name] - // [CONSTANT_Class_info] for above - // ^ [UTF-8] [Serialization: Class's name in which to invoke constructor] - // ^ [CONSTANT_Class_info] for above - // [UTF-8] target method or constructor name - // [UTF-8] target method or constructor signature - // [CONSTANT_NameAndType_info] for above - // [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method - // [UTF-8] "invoke" or "newInstance" - // [UTF-8] invoke or newInstance descriptor - // [UTF-8] descriptor for type of non-primitive parameter 1 - // [CONSTANT_Class_info] for type of non-primitive parameter 1 - // ... - // [UTF-8] descriptor for type of non-primitive parameter n - // [CONSTANT_Class_info] for type of non-primitive parameter n - // + [UTF-8] "java/lang/Exception" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "java/lang/ClassCastException" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "java/lang/NullPointerException" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "java/lang/IllegalArgumentException" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "java/lang/InvocationTargetException" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "" - // + [UTF-8] "()V" - // + [CONSTANT_NameAndType_info] for above - // + [CONSTANT_Methodref_info] for NullPointerException's constructor - // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor - // + [UTF-8] "(Ljava/lang/String;)V" - // + [CONSTANT_NameAndType_info] for "(Ljava/lang/String;)V" - // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String - // + [UTF-8] "(Ljava/lang/Throwable;)V" - // + [CONSTANT_NameAndType_info] for "(Ljava/lang/Throwable;)V" - // + [CONSTANT_Methodref_info] for InvocationTargetException's constructor - // + [CONSTANT_Methodref_info] for "super()" - // + [UTF-8] "java/lang/Object" - // + [CONSTANT_Class_info] for above - // + [UTF-8] "toString" - // + [UTF-8] "()Ljava/lang/String;" - // + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;" - // + [CONSTANT_Methodref_info] for Object's toString method - // + [UTF-8] "Code" - // + [UTF-8] "Exceptions" - // * [UTF-8] "java/lang/Boolean" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(Z)V" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "booleanValue" - // * [UTF-8] "()Z" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Byte" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(B)V" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "byteValue" - // * [UTF-8] "()B" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Character" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(C)V" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "charValue" - // * [UTF-8] "()C" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Double" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(D)V" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "doubleValue" - // * [UTF-8] "()D" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Float" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(F)V" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "floatValue" - // * [UTF-8] "()F" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Integer" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(I)V" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "intValue" - // * [UTF-8] "()I" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Long" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(J)V" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "longValue" - // * [UTF-8] "()J" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "java/lang/Short" - // * [CONSTANT_Class_info] for above - // * [UTF-8] "(S)V" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - // * [UTF-8] "shortValue" - // * [UTF-8] "()S" - // * [CONSTANT_NameAndType_info] for above - // * [CONSTANT_Methodref_info] for above - - short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES; - boolean usesPrimitives = usesPrimitiveTypes(); - if (usesPrimitives) { - numCPEntries += NUM_BOXING_CPOOL_ENTRIES; - } - if (forSerialization) { - numCPEntries += NUM_SERIALIZATION_CPOOL_ENTRIES; - } - - // Add in variable-length number of entries to be able to describe - // non-primitive parameter types and checked exceptions. - numCPEntries += (short) (2 * numNonPrimitiveParameterTypes()); - - asm.emitShort(add(numCPEntries, S1)); - - final String generatedName = generateName(isConstructor, forSerialization); - asm.emitConstantPoolUTF8(generatedName); - asm.emitConstantPoolClass(asm.cpi()); - thisClass = asm.cpi(); - if (isConstructor) { - if (forSerialization) { - asm.emitConstantPoolUTF8 - ("jdk/internal/reflect/SerializationConstructorAccessorImpl"); - } else { - asm.emitConstantPoolUTF8("jdk/internal/reflect/ConstructorAccessorImpl"); - } - } else { - asm.emitConstantPoolUTF8("jdk/internal/reflect/MethodAccessorImpl"); - } - asm.emitConstantPoolClass(asm.cpi()); - superClass = asm.cpi(); - asm.emitConstantPoolUTF8(getClassName(declaringClass, false)); - asm.emitConstantPoolClass(asm.cpi()); - targetClass = asm.cpi(); - short serializationTargetClassIdx = (short) 0; - if (forSerialization) { - asm.emitConstantPoolUTF8(getClassName(serializationTargetClass, false)); - asm.emitConstantPoolClass(asm.cpi()); - serializationTargetClassIdx = asm.cpi(); - } - asm.emitConstantPoolUTF8(name); - asm.emitConstantPoolUTF8(buildInternalSignature()); - asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); - if (isInterface()) { - asm.emitConstantPoolInterfaceMethodref(targetClass, asm.cpi()); - } else { - if (forSerialization) { - asm.emitConstantPoolMethodref(serializationTargetClassIdx, asm.cpi()); - } else { - asm.emitConstantPoolMethodref(targetClass, asm.cpi()); - } - } - targetMethodRef = asm.cpi(); - if (isConstructor) { - asm.emitConstantPoolUTF8("newInstance"); - } else { - asm.emitConstantPoolUTF8("invoke"); - } - invokeIdx = asm.cpi(); - if (isConstructor) { - asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;"); - } else { - asm.emitConstantPoolUTF8 - ("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); - } - invokeDescriptorIdx = asm.cpi(); - - // Output class information for non-primitive parameter types - nonPrimitiveParametersBaseIdx = add(asm.cpi(), S2); - for (int i = 0; i < parameterTypes.length; i++) { - Class c = parameterTypes[i]; - if (!isPrimitive(c)) { - asm.emitConstantPoolUTF8(getClassName(c, false)); - asm.emitConstantPoolClass(asm.cpi()); - } - } - - // Entries common to FieldAccessor, MethodAccessor and ConstructorAccessor - emitCommonConstantPoolEntries(); - - // Boxing entries - if (usesPrimitives) { - emitBoxingContantPoolEntries(); - } - - if (asm.cpi() != numCPEntries) { - throw new InternalError("Adjust this code (cpi = " + asm.cpi() + - ", numCPEntries = " + numCPEntries + ")"); - } - - // Access flags - asm.emitShort(ACC_PUBLIC); - - // This class - asm.emitShort(thisClass); - - // Superclass - asm.emitShort(superClass); - - // Interfaces count and interfaces - asm.emitShort(S0); - - // Fields count and fields - asm.emitShort(S0); - - // Methods count and methods - asm.emitShort(NUM_METHODS); - - emitConstructor(); - emitInvoke(); - - // Additional attributes (none) - asm.emitShort(S0); - - // Load class - vec.trim(); - final byte[] bytes = vec.getData(); - // Note: the class loader is the only thing that really matters - // here -- it's important to get the generated code into the - // same namespace as the target class. Since the generated code - // is privileged anyway, the protection domain probably doesn't - // matter. - return AccessController.doPrivileged( - new PrivilegedAction() { - @SuppressWarnings("deprecation") // Class.newInstance - public MagicAccessorImpl run() { - try { - return (MagicAccessorImpl) - ClassDefiner.defineClass - (generatedName, - bytes, - 0, - bytes.length, - declaringClass.getClassLoader()).newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - throw new InternalError(e); - } - } - }); - } - - /** This emits the code for either invoke() or newInstance() */ - private void emitInvoke() { - // NOTE that this code will only handle 65535 parameters since we - // use the sipush instruction to get the array index on the - // operand stack. - if (parameterTypes.length > 65535) { - throw new InternalError("Can't handle more than 65535 parameters"); - } - - // Generate code into fresh code buffer - ClassFileAssembler cb = new ClassFileAssembler(); - if (isConstructor) { - // 1 incoming argument - cb.setMaxLocals(2); - } else { - // 2 incoming arguments - cb.setMaxLocals(3); - } - - short illegalArgStartPC = 0; - - if (isConstructor) { - // Instantiate target class before continuing - // new - // dup - cb.opc_new(targetClass); - cb.opc_dup(); - } else { - // Get target object on operand stack if necessary. - - // We need to do an explicit null check here; we won't see - // NullPointerExceptions from the invoke bytecode, since it's - // covered by an exception handler. - if (!isStatic()) { - // aload_1 - // ifnonnull - // new - // dup - // invokespecial - // athrow - // - // aload_1 - // checkcast - cb.opc_aload_1(); - Label l = new Label(); - cb.opc_ifnonnull(l); - cb.opc_new(nullPointerClass); - cb.opc_dup(); - cb.opc_invokespecial(nullPointerCtorIdx, 0, 0); - cb.opc_athrow(); - l.bind(); - illegalArgStartPC = cb.getLength(); - cb.opc_aload_1(); - cb.opc_checkcast(targetClass); - } - } - - // Have to check length of incoming array and throw - // IllegalArgumentException if not correct. A concession to the - // JCK (isn't clearly specified in the spec): we allow null in the - // case where the argument list is zero length. - // if no-arg: - // aload_2 | aload_1 (Method | Constructor) - // ifnull - // aload_2 | aload_1 - // arraylength - // sipush - // if_icmpeq - // new - // dup - // invokespecial - // athrow - // - Label successLabel = new Label(); - if (parameterTypes.length == 0) { - if (isConstructor) { - cb.opc_aload_1(); - } else { - cb.opc_aload_2(); - } - cb.opc_ifnull(successLabel); - } - if (isConstructor) { - cb.opc_aload_1(); - } else { - cb.opc_aload_2(); - } - cb.opc_arraylength(); - cb.opc_sipush((short) parameterTypes.length); - cb.opc_if_icmpeq(successLabel); - cb.opc_new(illegalArgumentClass); - cb.opc_dup(); - cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); - cb.opc_athrow(); - successLabel.bind(); - - // Iterate through incoming actual parameters, ensuring that each - // is compatible with the formal parameter type, and pushing the - // actual on the operand stack (unboxing and widening if necessary). - - short paramTypeCPIdx = nonPrimitiveParametersBaseIdx; - Label nextParamLabel = null; - byte count = 1; // both invokeinterface opcode's "count" as well as - // num args of other invoke bytecodes - for (int i = 0; i < parameterTypes.length; i++) { - Class paramType = parameterTypes[i]; - count += (byte) typeSizeInStackSlots(paramType); - if (nextParamLabel != null) { - nextParamLabel.bind(); - nextParamLabel = null; - } - // aload_2 | aload_1 - // sipush - // aaload - if (isConstructor) { - cb.opc_aload_1(); - } else { - cb.opc_aload_2(); - } - cb.opc_sipush((short) i); - cb.opc_aaload(); - if (isPrimitive(paramType)) { - // Unboxing code. - // Put parameter into temporary local variable - // astore_3 | astore_2 - if (isConstructor) { - cb.opc_astore_2(); - } else { - cb.opc_astore_3(); - } - - // repeat for all possible widening conversions: - // aload_3 | aload_2 - // instanceof - // ifeq - // aload_3 | aload_2 - // checkcast // Note: this is "redundant", - // // but necessary for the verifier - // invokevirtual - // - // goto - // ... - // last unboxing label: - // new - // dup - // invokespecial - // athrow - - Label l = null; // unboxing label - nextParamLabel = new Label(); - - for (int j = 0; j < primitiveTypes.length; j++) { - Class c = primitiveTypes[j]; - if (canWidenTo(c, paramType)) { - if (l != null) { - l.bind(); - } - // Emit checking and unboxing code for this type - if (isConstructor) { - cb.opc_aload_2(); - } else { - cb.opc_aload_3(); - } - cb.opc_instanceof(indexForPrimitiveType(c)); - l = new Label(); - cb.opc_ifeq(l); - if (isConstructor) { - cb.opc_aload_2(); - } else { - cb.opc_aload_3(); - } - cb.opc_checkcast(indexForPrimitiveType(c)); - cb.opc_invokevirtual(unboxingMethodForPrimitiveType(c), - 0, - typeSizeInStackSlots(c)); - emitWideningBytecodeForPrimitiveConversion(cb, - c, - paramType); - cb.opc_goto(nextParamLabel); - } - } - - if (l == null) { - throw new InternalError - ("Must have found at least identity conversion"); - } - - // Fell through; given object is null or invalid. According to - // the spec, we can throw IllegalArgumentException for both of - // these cases. - - l.bind(); - cb.opc_new(illegalArgumentClass); - cb.opc_dup(); - cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); - cb.opc_athrow(); - } else { - // Emit appropriate checkcast - cb.opc_checkcast(paramTypeCPIdx); - paramTypeCPIdx = add(paramTypeCPIdx, S2); - // Fall through to next argument - } - } - // Bind last goto if present - if (nextParamLabel != null) { - nextParamLabel.bind(); - } - - short invokeStartPC = cb.getLength(); - - // OK, ready to perform the invocation. - if (isConstructor) { - cb.opc_invokespecial(targetMethodRef, count, 0); - } else { - if (isStatic()) { - cb.opc_invokestatic(targetMethodRef, - count, - typeSizeInStackSlots(returnType)); - } else { - if (isInterface()) { - cb.opc_invokeinterface(targetMethodRef, - count, - count, - typeSizeInStackSlots(returnType)); - } else { - cb.opc_invokevirtual(targetMethodRef, - count, - typeSizeInStackSlots(returnType)); - } - } - } - - short invokeEndPC = cb.getLength(); - - if (!isConstructor) { - // Box return value if necessary - if (isPrimitive(returnType)) { - cb.opc_invokestatic(boxingMethodForPrimitiveType(returnType), - typeSizeInStackSlots(returnType), - 0); - } else if (returnType == Void.TYPE) { - cb.opc_aconst_null(); - } - } - cb.opc_areturn(); - - // We generate two exception handlers; one which is responsible - // for catching ClassCastException and NullPointerException and - // throwing IllegalArgumentException, and the other which catches - // all java/lang/Throwable objects thrown from the target method - // and wraps them in InvocationTargetExceptions. - - short classCastHandler = cb.getLength(); - - // ClassCast, etc. exception handler - cb.setStack(1); - cb.opc_invokespecial(toStringIdx, 0, 1); - cb.opc_new(illegalArgumentClass); - cb.opc_dup_x1(); - cb.opc_swap(); - cb.opc_invokespecial(illegalArgumentStringCtorIdx, 1, 0); - cb.opc_athrow(); - - short invocationTargetHandler = cb.getLength(); - - // InvocationTargetException exception handler - cb.setStack(1); - cb.opc_new(invocationTargetClass); - cb.opc_dup_x1(); - cb.opc_swap(); - cb.opc_invokespecial(invocationTargetCtorIdx, 1, 0); - cb.opc_athrow(); - - // Generate exception table. We cover the entire code sequence - // with an exception handler which catches ClassCastException and - // converts it into an IllegalArgumentException. - - ClassFileAssembler exc = new ClassFileAssembler(); - - exc.emitShort(illegalArgStartPC); // start PC - exc.emitShort(invokeStartPC); // end PC - exc.emitShort(classCastHandler); // handler PC - exc.emitShort(classCastClass); // catch type - - exc.emitShort(illegalArgStartPC); // start PC - exc.emitShort(invokeStartPC); // end PC - exc.emitShort(classCastHandler); // handler PC - exc.emitShort(nullPointerClass); // catch type - - exc.emitShort(invokeStartPC); // start PC - exc.emitShort(invokeEndPC); // end PC - exc.emitShort(invocationTargetHandler); // handler PC - exc.emitShort(throwableClass); // catch type - - emitMethod(invokeIdx, cb.getMaxLocals(), cb, exc, - new short[] { invocationTargetClass }); - } - - private boolean usesPrimitiveTypes() { - // We need to emit boxing/unboxing constant pool information if - // the method takes a primitive type for any of its parameters or - // returns a primitive value (except void) - if (returnType.isPrimitive()) { - return true; - } - for (int i = 0; i < parameterTypes.length; i++) { - if (parameterTypes[i].isPrimitive()) { - return true; - } - } - return false; - } - - private int numNonPrimitiveParameterTypes() { - int num = 0; - for (int i = 0; i < parameterTypes.length; i++) { - if (!parameterTypes[i].isPrimitive()) { - ++num; - } - } - return num; - } - - private boolean isInterface() { - return declaringClass.isInterface(); - } - - private String buildInternalSignature() { - StringBuilder sb = new StringBuilder(); - sb.append("("); - for (int i = 0; i < parameterTypes.length; i++) { - sb.append(getClassName(parameterTypes[i], true)); - } - sb.append(")"); - sb.append(getClassName(returnType, true)); - return sb.toString(); - } - - private static synchronized String generateName(boolean isConstructor, - boolean forSerialization) - { - if (isConstructor) { - if (forSerialization) { - int num = ++serializationConstructorSymnum; - return "jdk/internal/reflect/GeneratedSerializationConstructorAccessor" + num; - } else { - int num = ++constructorSymnum; - return "jdk/internal/reflect/GeneratedConstructorAccessor" + num; - } - } else { - int num = ++methodSymnum; - return "jdk/internal/reflect/GeneratedMethodAccessor" + num; - } - } -} diff --git a/src/java.base/share/classes/jdk/internal/reflect/SerializationConstructorAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/SerializationConstructorAccessorImpl.java deleted file mode 100644 index 9dbbf0d2c7797..0000000000000 --- a/src/java.base/share/classes/jdk/internal/reflect/SerializationConstructorAccessorImpl.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.reflect; - -/**

          Java serialization (in java.io) expects to be able to - instantiate a class and invoke a no-arg constructor of that - class's first non-Serializable superclass. This is not a valid - operation according to the VM specification; one can not (for - classes A and B, where B is a subclass of A) write "new B; - invokespecial A()" without getting a verification error.

          - -

          In all other respects, the bytecode-based reflection framework - can be reused for this purpose. This marker class was originally - known to the VM and verification disabled for it and all - subclasses, but the bug fix for 4486457 necessitated disabling - verification for all of the dynamically-generated bytecodes - associated with reflection. This class has been left in place to - make future debugging easier.

          */ - -abstract class SerializationConstructorAccessorImpl - extends ConstructorAccessorImpl { -} diff --git a/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java b/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java new file mode 100644 index 0000000000000..a8d2fe8bb74b4 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.util; + +import jdk.internal.vm.annotation.ForceInline; + +/** + * Helper to JDK UTF putChar and Calculate length + * + * @since 24 + */ +public abstract class ModifiedUtf { + private ModifiedUtf() { + } + + @ForceInline + public static int putChar(byte[] buf, int offset, char c) { + if (c != 0 && c < 0x80) { + buf[offset++] = (byte) c; + } else if (c >= 0x800) { + buf[offset ] = (byte) (0xE0 | c >> 12 & 0x0F); + buf[offset + 1] = (byte) (0x80 | c >> 6 & 0x3F); + buf[offset + 2] = (byte) (0x80 | c & 0x3F); + offset += 3; + } else { + buf[offset ] = (byte) (0xC0 | c >> 6 & 0x1F); + buf[offset + 1] = (byte) (0x80 | c & 0x3F); + offset += 2; + } + return offset; + } + + /** + * Calculate the utf length of a string + * @param str input string + * @param countNonZeroAscii the number of non-zero ascii characters in the prefix calculated by JLA.countNonZeroAscii(str) + */ + @ForceInline + public static int utfLen(String str, int countNonZeroAscii) { + int utflen = str.length(); + for (int i = utflen - 1; i >= countNonZeroAscii; i--) { + int c = str.charAt(i); + if (c >= 0x80 || c == 0) + utflen += (c >= 0x800) ? 2 : 1; + } + return utflen; + } +} 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 da06bf07a65a4..9dcebeca470e7 100644 --- a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java +++ b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,19 +98,33 @@ private StaticProperty() {} 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", ""); + // for compatibility, check for old user.region property + USER_REGION = getProperty(props, "user.region", ""); + if (!USER_REGION.isEmpty()) { + // region can be of form country, country_variant, or _variant + int i = USER_REGION.indexOf('_'); + if (i >= 0) { + USER_COUNTRY = USER_REGION.substring(0, i); + USER_VARIANT = USER_REGION.substring(i + 1); + } else { + USER_COUNTRY = USER_REGION; + USER_VARIANT = ""; + } + USER_SCRIPT = ""; + } else { + USER_SCRIPT = getProperty(props, "user.script", ""); + USER_COUNTRY = getProperty(props, "user.country", ""); + USER_VARIANT = getProperty(props, "user.variant", ""); + } 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/Continuation.java b/src/java.base/share/classes/jdk/internal/vm/Continuation.java index 99d0c62aaec8d..b863def8e6a78 100644 --- a/src/java.base/share/classes/jdk/internal/vm/Continuation.java +++ b/src/java.base/share/classes/jdk/internal/vm/Continuation.java @@ -36,6 +36,7 @@ import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.vm.annotation.Hidden; +import jdk.internal.vm.annotation.JvmtiHideEvents; /** * A one-shot delimited continuation. @@ -305,6 +306,7 @@ private void finish() { @Hidden @DontInline @IntrinsicCandidate + @JvmtiHideEvents private static void enter(Continuation c, boolean isContinue) { // This method runs in the "entry frame". // A yield jumps to this method's caller as if returning from this method. @@ -316,6 +318,7 @@ private static void enter(Continuation c, boolean isContinue) { } @Hidden + @JvmtiHideEvents private void enter0() { target.run(); } @@ -340,6 +343,7 @@ private boolean isEmpty() { * @throws IllegalStateException if not currently in the given {@code scope}, */ @Hidden + @JvmtiHideEvents public static boolean yield(ContinuationScope scope) { Continuation cont = JLA.getContinuation(currentCarrierThread()); Continuation c; @@ -352,6 +356,7 @@ public static boolean yield(ContinuationScope scope) { } @Hidden + @JvmtiHideEvents private boolean yield0(ContinuationScope scope, Continuation child) { preempted = false; diff --git a/src/java.base/share/classes/jdk/internal/reflect/ByteVector.java b/src/java.base/share/classes/jdk/internal/vm/annotation/JvmtiHideEvents.java similarity index 70% rename from src/java.base/share/classes/jdk/internal/reflect/ByteVector.java rename to src/java.base/share/classes/jdk/internal/vm/annotation/JvmtiHideEvents.java index 2a07b072982c1..06572e64546e8 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ByteVector.java +++ b/src/java.base/share/classes/jdk/internal/vm/annotation/JvmtiHideEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 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,15 +23,18 @@ * questions. */ -package jdk.internal.reflect; +package jdk.internal.vm.annotation; -/** A growable array of bytes. */ +import java.lang.annotation.*; -interface ByteVector { - public int getLength(); - public byte get(int index); - public void put(int index, byte value); - public void add(byte value); - public void trim(); - public byte[] getData(); +/** + * A method may be annotated with JvmtiHideEvents to hint that JVMTI events + * should not be generated in context of the annotated method. + * + * @implNote + * This annotation is only used for some VirtualThread and Continuation methods. + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface JvmtiHideEvents { } diff --git a/src/java.base/share/classes/jdk/internal/vm/annotation/JvmtiMountTransition.java b/src/java.base/share/classes/jdk/internal/vm/annotation/JvmtiMountTransition.java index df0545e46b135..ff9f5d8bbbf75 100644 --- a/src/java.base/share/classes/jdk/internal/vm/annotation/JvmtiMountTransition.java +++ b/src/java.base/share/classes/jdk/internal/vm/annotation/JvmtiMountTransition.java @@ -28,8 +28,11 @@ import java.lang.annotation.*; /** - * A method is annotated as "jvmti mount transition" if it starts - * or ends virtual thread mount state transition (VTMS transition). + * A method may be annotated with JvmtiMountTransition to hint + * it is desirable to omit it from JVMTI stack traces. + * Normally, a method is annotated with @JvmtiMountTransition if it starts + * or ends Virtual Thread Mount State (VTMS) transition, so the thread + * identity is undefined or different at method entry and exit. * * @implNote * This annotation is only used for VirtualThread methods. diff --git a/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java b/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java index 5c4040d912804..afd6cc62ce5ba 100644 --- a/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java @@ -114,6 +114,13 @@ public class VectorSupport { public static final int VECTOR_OP_EXPM1 = 117; public static final int VECTOR_OP_HYPOT = 118; + public static final int VECTOR_OP_SADD = 119; + public static final int VECTOR_OP_SSUB = 120; + public static final int VECTOR_OP_SUADD = 121; + public static final int VECTOR_OP_SUSUB = 122; + public static final int VECTOR_OP_UMIN = 123; + public static final int VECTOR_OP_UMAX = 124; + // See src/hotspot/share/opto/subnode.hpp // struct BoolTest, and enclosed enum mask public static final int BT_eq = 0; // 0000 @@ -395,6 +402,24 @@ VM binaryOp(int oprId, assert isNonCapturingLambda(defaultImpl) : defaultImpl; return defaultImpl.apply(v1, v2, m); } + /* ============================================================================ */ + + public interface SelectFromTwoVector> { + V apply(V v1, V v2, V v3); + } + + @IntrinsicCandidate + public static + , + E> + V selectFromTwoVectorOp(Class vClass, Class eClass, int length, + V v1, V v2, V v3, + SelectFromTwoVector defaultImpl) { + assert isNonCapturingLambda(defaultImpl) : defaultImpl; + return defaultImpl.apply(v1, v2, v3); + } + + /* ============================================================================ */ /* ============================================================================ */ diff --git a/src/java.base/share/classes/sun/net/www/MessageHeader.java b/src/java.base/share/classes/sun/net/www/MessageHeader.java index 6af23e43ad25d..5095507d9684e 100644 --- a/src/java.base/share/classes/sun/net/www/MessageHeader.java +++ b/src/java.base/share/classes/sun/net/www/MessageHeader.java @@ -30,6 +30,8 @@ package sun.net.www; import java.io.*; +import java.lang.reflect.Array; +import java.net.ProtocolException; import java.util.Collections; import java.util.*; @@ -45,11 +47,32 @@ public final class MessageHeader { private String[] values; private int nkeys; + // max number of bytes for headers, <=0 means unlimited; + // this corresponds to the length of the names, plus the length + // of the values, plus an overhead of 32 bytes per name: value + // pair. + // Note: we use the same definition as HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE + // see RFC 9113, section 6.5.2. + // https://www.rfc-editor.org/rfc/rfc9113.html#SETTINGS_MAX_HEADER_LIST_SIZE + private final int maxHeaderSize; + + // Aggregate size of the field lines (name + value + 32) x N + // that have been parsed and accepted so far. + // This is defined as a long to force promotion to long + // and avoid overflows; see checkNewSize; + private long size; + public MessageHeader () { + this(0); + } + + public MessageHeader (int maxHeaderSize) { + this.maxHeaderSize = maxHeaderSize; grow(); } public MessageHeader (InputStream is) throws java.io.IOException { + maxHeaderSize = 0; parseHeader(is); } @@ -476,10 +499,28 @@ public static String canonicalID(String id) { public void parseHeader(InputStream is) throws java.io.IOException { synchronized (this) { nkeys = 0; + size = 0; } mergeHeader(is); } + private void checkMaxHeaderSize(int sz) throws ProtocolException { + if (maxHeaderSize > 0) checkNewSize(size, sz, 0); + } + + private long checkNewSize(long size, int name, int value) throws ProtocolException { + // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2. + long newSize = size + name + value + 32; + if (maxHeaderSize > 0 && newSize > maxHeaderSize) { + Arrays.fill(keys, 0, nkeys, null); + Arrays.fill(values,0, nkeys, null); + nkeys = 0; + throw new ProtocolException(String.format("Header size too big: %s > %s", + newSize, maxHeaderSize)); + } + return newSize; + } + /** Parse and merge a MIME header from an input stream. */ @SuppressWarnings("fallthrough") public void mergeHeader(InputStream is) throws java.io.IOException { @@ -493,7 +534,15 @@ public void mergeHeader(InputStream is) throws java.io.IOException { int c; boolean inKey = firstc > ' '; s[len++] = (char) firstc; + checkMaxHeaderSize(len); parseloop:{ + // We start parsing for a new name value pair here. + // The max header size includes an overhead of 32 bytes per + // name value pair. + // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2. + long maxRemaining = maxHeaderSize > 0 + ? maxHeaderSize - size - 32 + : Long.MAX_VALUE; while ((c = is.read()) >= 0) { switch (c) { case ':': @@ -527,6 +576,9 @@ public void mergeHeader(InputStream is) throws java.io.IOException { s = ns; } s[len++] = (char) c; + if (maxHeaderSize > 0 && len > maxRemaining) { + checkMaxHeaderSize(len); + } } firstc = -1; } @@ -548,6 +600,9 @@ public void mergeHeader(InputStream is) throws java.io.IOException { v = new String(); else v = String.copyValueOf(s, keyend, len - keyend); + int klen = k == null ? 0 : k.length(); + + size = checkNewSize(size, klen, v.length()); add(k, v); } } diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index f47261f4491d0..8351185350269 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -172,6 +172,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection { */ private static final int bufSize4ES; + private static final int maxHeaderSize; + /* * Restrict setting of request headers through the public api * consistent with JavaScript XMLHttpRequest2 with a few @@ -288,6 +290,19 @@ private static Set schemesListToSet(String list) { } else { restrictedHeaderSet = null; } + + int defMaxHeaderSize = 384 * 1024; + String maxHeaderSizeStr = getNetProperty("jdk.http.maxHeaderSize"); + int maxHeaderSizeVal = defMaxHeaderSize; + if (maxHeaderSizeStr != null) { + try { + maxHeaderSizeVal = Integer.parseInt(maxHeaderSizeStr); + } catch (NumberFormatException n) { + maxHeaderSizeVal = defMaxHeaderSize; + } + } + if (maxHeaderSizeVal < 0) maxHeaderSizeVal = 0; + maxHeaderSize = maxHeaderSizeVal; } static final String httpVersion = "HTTP/1.1"; @@ -754,7 +769,7 @@ private void writeRequests() throws IOException { } ps = (PrintStream) http.getOutputStream(); connected=true; - responses = new MessageHeader(); + responses = new MessageHeader(maxHeaderSize); setRequests=false; writeRequests(); } @@ -912,7 +927,7 @@ protected HttpURLConnection(URL u, Proxy p, Handler handler) throws IOException { super(checkURL(u)); requests = new MessageHeader(); - responses = new MessageHeader(); + responses = new MessageHeader(maxHeaderSize); userHeaders = new MessageHeader(); this.handler = handler; instProxy = p; @@ -2810,7 +2825,7 @@ private boolean followRedirect0(String loc, int stat, URL locUrl) } // clear out old response headers!!!! - responses = new MessageHeader(); + responses = new MessageHeader(maxHeaderSize); if (stat == HTTP_USE_PROXY) { /* This means we must re-request the resource through the * proxy denoted in the "Location:" field of the response. @@ -3000,7 +3015,7 @@ private void reset() throws IOException { } catch (IOException e) { } } responseCode = -1; - responses = new MessageHeader(); + responses = new MessageHeader(maxHeaderSize); connected = false; } diff --git a/src/java.base/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java b/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java similarity index 97% rename from src/java.base/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java rename to src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java index 178ffe84a0643..17ca43d4ace9f 100644 --- a/src/java.base/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, 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 @@ -32,6 +32,8 @@ import java.util.HashMap; import java.util.jar.JarFile; import java.security.Permission; + +import jdk.internal.util.OperatingSystem; import sun.net.util.URLUtil; /* A factory for cached JAR file. This class is used to both retrieve @@ -148,6 +150,11 @@ boolean cacheIfAbsent(URL url, JarFile jarFile) { } private URL urlFor(URL url) throws IOException { + // for systems other than Windows we don't + // do any special conversion + if (!OperatingSystem.isWindows()) { + return url; + } if (url.getProtocol().equalsIgnoreCase("file")) { // Deal with UNC pathnames specially. See 4180841 diff --git a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java index 8cf5c720b8d6b..14b2058d28dcf 100644 --- a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java +++ b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.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 @@ -38,6 +38,7 @@ import java.util.Arrays; import java.util.Objects; import jdk.internal.util.ArraysSupport; +import jdk.internal.vm.annotation.Stable; /** * An InputStream that reads bytes from a channel. @@ -53,6 +54,10 @@ class ChannelInputStream extends InputStream { private byte[] bs; // Invoker's previous array private byte[] b1; + // if isOther is true, then the file being read is not a regular file, + // nor a directory, nor a symbolic link, hence possibly not seekable + private @Stable Boolean isOther; + /** * Initialize a ChannelInputStream that reads from the given channel. */ @@ -60,6 +65,17 @@ class ChannelInputStream extends InputStream { this.ch = ch; } + private boolean isOther() throws IOException { + Boolean isOther = this.isOther; + if (isOther == null) { + if (ch instanceof FileChannelImpl fci) + this.isOther = isOther = fci.isOther(); + else + this.isOther = isOther = Boolean.FALSE; + } + return isOther; + } + /** * Reads a sequence of bytes from the channel into the given buffer. */ @@ -105,7 +121,8 @@ public synchronized int read(byte[] bs, int off, int len) @Override public byte[] readAllBytes() throws IOException { - if (!(ch instanceof SeekableByteChannel sbc)) + if (!(ch instanceof SeekableByteChannel sbc) || + (ch instanceof FileChannelImpl fci && isOther())) return super.readAllBytes(); long length = sbc.size(); @@ -156,7 +173,8 @@ public byte[] readNBytes(int len) throws IOException { if (len == 0) return new byte[0]; - if (!(ch instanceof SeekableByteChannel sbc)) + if (!(ch instanceof SeekableByteChannel sbc) || + (ch instanceof FileChannelImpl fci && isOther())) return super.readNBytes(len); long length = sbc.size(); @@ -192,7 +210,9 @@ public byte[] readNBytes(int len) throws IOException { @Override public int available() throws IOException { // special case where the channel is to a file - if (ch instanceof SeekableByteChannel sbc) { + if (ch instanceof FileChannelImpl fci) { + return fci.available(); + } else if (ch instanceof SeekableByteChannel sbc) { long rem = Math.max(0, sbc.size() - sbc.position()); return (rem > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)rem; } @@ -202,7 +222,8 @@ public int available() throws IOException { @Override public synchronized long skip(long n) throws IOException { // special case where the channel is to a file - if (ch instanceof SeekableByteChannel sbc) { + if (ch instanceof SeekableByteChannel sbc && + !(ch instanceof FileChannelImpl fci && isOther())) { long pos = sbc.position(); long newPos; if (n > 0) { @@ -224,7 +245,8 @@ public synchronized long skip(long n) throws IOException { public long transferTo(OutputStream out) throws IOException { Objects.requireNonNull(out, "out"); - if (ch instanceof FileChannel fc) { + if (ch instanceof FileChannel fc && + !(fc instanceof FileChannelImpl fci && isOther())) { // FileChannel -> SocketChannel if (out instanceof SocketOutputStream sos) { SocketChannelImpl sc = sos.channel(); 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 f65a390074059..72de217a83ce6 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -454,6 +454,7 @@ private long traceImplWrite(ByteBuffer[] srcs, int offset, int length) throws IO } return bytesWritten; } + // -- Other operations -- @Override @@ -529,6 +530,49 @@ public long size() throws IOException { } } + /** + * Returns an estimate of the number of remaining bytes that can be read + * from this channel without blocking. + */ + int available() throws IOException { + ensureOpen(); + synchronized (positionLock) { + int a = -1; + int ti = -1; + try { + beginBlocking(); + ti = threads.add(); + if (!isOpen()) + return -1; + a = nd.available(fd); + } finally { + threads.remove(ti); + endBlocking(a > -1); + } + return a; + } + } + + /** + * Tells whether the channel represents something other than a regular + * file, directory, or symbolic link. + */ + boolean isOther() throws IOException { + ensureOpen(); + int ti = -1; + Boolean isOther = null; + try { + beginBlocking(); + ti = threads.add(); + if (!isOpen()) + return false; + return isOther = nd.isOther(fd); + } finally { + threads.remove(ti); + endBlocking(isOther != null); + } + } + @Override public FileChannel truncate(long newSize) throws IOException { ensureOpen(); diff --git a/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java b/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java index f13f632495170..35ecef64baf9c 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java +++ b/src/java.base/share/classes/sun/nio/ch/FileDispatcher.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 @@ -49,6 +49,10 @@ abstract class FileDispatcher extends NativeDispatcher { abstract long size(FileDescriptor fd) throws IOException; + abstract int available(FileDescriptor fd) throws IOException; + + abstract boolean isOther(FileDescriptor fd) throws IOException; + abstract int lock(FileDescriptor fd, boolean blocking, long pos, long size, boolean shared) throws IOException; diff --git a/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java b/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java new file mode 100644 index 0000000000000..88a2909cfac1c --- /dev/null +++ b/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java @@ -0,0 +1,143 @@ +/* + * 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.pkcs; + +import sun.security.util.DerInputStream; +import sun.security.util.DerValue; +import sun.security.x509.AlgorithmId; + +import javax.security.auth.DestroyFailedException; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.Serial; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; + +/// Represents a private key from an algorithm family that is specialized +/// with a named parameter set. +/// +/// This key is generated by either a [sun.security.provider.NamedKeyPairGenerator] +/// or [sun.security.provider.NamedKeyFactory]. Its [#getAlgorithm] method +/// returns the algorithm family name, while its [#getParams()] method returns +/// the parameter set name as a [NamedParameterSpec] object. The algorithm +/// identifier in the PKCS #8 encoding of the key is always a single OID derived +/// from the parameter set name. +/// +/// @see sun.security.provider.NamedKeyPairGenerator +public final class NamedPKCS8Key extends PKCS8Key { + @Serial + private static final long serialVersionUID = 1L; + + private final String fname; + private final transient NamedParameterSpec paramSpec; + private final byte[] rawBytes; + + private transient boolean destroyed = false; + + /// Ctor from family name, parameter set name, raw key bytes. + /// Key bytes won't be cloned, caller must relinquish ownership + public NamedPKCS8Key(String fname, String pname, byte[] rawBytes) { + this.fname = fname; + this.paramSpec = new NamedParameterSpec(pname); + try { + this.algid = AlgorithmId.get(pname); + } catch (NoSuchAlgorithmException e) { + throw new ProviderException(e); + } + this.rawBytes = rawBytes; + + DerValue val = new DerValue(DerValue.tag_OctetString, rawBytes); + try { + this.key = val.toByteArray(); + } finally { + val.clear(); + } + } + + /// Ctor from family name, and PKCS #8 bytes + public NamedPKCS8Key(String fname, byte[] encoded) throws InvalidKeyException { + super(encoded); + this.fname = fname; + try { + paramSpec = new NamedParameterSpec(algid.getName()); + if (algid.getEncodedParams() != null) { + throw new InvalidKeyException("algorithm identifier has params"); + } + rawBytes = new DerInputStream(key).getOctetString(); + } catch (IOException e) { + throw new InvalidKeyException("Cannot parse input", e); + } + } + + @Override + public String toString() { + // Do not modify: this can be used by earlier JDKs that + // do not have the getParams() method + return paramSpec.getName() + " private key"; + } + + /// Returns the reference to the internal key. Caller must not modify + /// the content or keep a reference. + public byte[] getRawBytes() { + return rawBytes; + } + + @Override + public NamedParameterSpec getParams() { + return paramSpec; + } + + @Override + public String getAlgorithm() { + return fname; + } + + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "NamedPKCS8Key keys are not directly deserializable"); + } + + @Override + public void destroy() throws DestroyFailedException { + Arrays.fill(rawBytes, (byte)0); + Arrays.fill(key, (byte)0); + if (encodedKey != null) { + Arrays.fill(encodedKey, (byte)0); + } + destroyed = true; + } + + @Override + public boolean isDestroyed() { + return destroyed; + } +} diff --git a/src/java.base/share/classes/sun/security/provider/DRBG.java b/src/java.base/share/classes/sun/security/provider/DRBG.java index 923c8c3aa544a..01958285e430a 100644 --- a/src/java.base/share/classes/sun/security/provider/DRBG.java +++ b/src/java.base/share/classes/sun/security/provider/DRBG.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 @@ -26,6 +26,7 @@ package sun.security.provider; import java.io.IOException; +import java.io.InvalidObjectException; import java.security.AccessController; import java.security.DrbgParameters; import java.security.PrivilegedAction; @@ -272,11 +273,18 @@ private static void checkTwice(boolean flag, String name) { } } + /** + * Restores the state of this object from the stream. + * + * @param s the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ @java.io.Serial private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); - if (mdp.mech == null) { + if (mdp == null || mdp.mech == null) { throw new IllegalArgumentException("Input data is corrupted"); } createImpl(); diff --git a/src/java.base/share/classes/sun/security/provider/NamedKEM.java b/src/java.base/share/classes/sun/security/provider/NamedKEM.java new file mode 100644 index 0000000000000..2731b3460af3b --- /dev/null +++ b/src/java.base/share/classes/sun/security/provider/NamedKEM.java @@ -0,0 +1,223 @@ +/* + * 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.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; +import java.util.Objects; + +/// A base class for all `KEM` implementations that can be +/// configured with a named parameter set. See [NamedKeyPairGenerator] +/// for more details. +public abstract class NamedKEM implements KEMSpi { + + private final String fname; // family name + private final String[] pnames; // allowed parameter set name (at least one) + + /// Creates a new `NamedKEM` object. + /// + /// @param fname the family name + /// @param pnames the standard parameter set names, at least one is needed. + protected NamedKEM(String fname, String... pnames) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + if (pnames == null || pnames.length == 0) { + throw new AssertionError("pnames cannot be null or empty"); + } + this.fname = fname; + this.pnames = pnames; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, + AlgorithmParameterSpec spec, SecureRandom secureRandom) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (spec != null) { + throw new InvalidAlgorithmParameterException( + "The " + fname + " algorithm does not take any parameters"); + } + // translate also check the key + var nk = (NamedX509Key) new NamedKeyFactory(fname, pnames) + .engineTranslateKey(publicKey); + var pk = nk.getRawBytes(); + return getKeyConsumerImpl(this, nk.getParams(), pk, + implCheckPublicKey(nk.getParams().getName(), pk), secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator( + PrivateKey privateKey, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (spec != null) { + throw new InvalidAlgorithmParameterException( + "The " + fname + " algorithm does not take any parameters"); + } + // translate also check the key + var nk = (NamedPKCS8Key) new NamedKeyFactory(fname, pnames) + .engineTranslateKey(privateKey); + var sk = nk.getRawBytes(); + return getKeyConsumerImpl(this, nk.getParams(), sk, + implCheckPrivateKey(nk.getParams().getName(), sk), null); + } + + // We don't have a flag on whether key is public key or private key. + // The correct method should always be called. + private record KeyConsumerImpl(NamedKEM kem, String name, int sslen, + int clen, byte[] key, Object k2, SecureRandom sr) + implements KEMSpi.EncapsulatorSpi, KEMSpi.DecapsulatorSpi { + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, + String algorithm) throws DecapsulateException { + if (encapsulation.length != clen) { + throw new DecapsulateException("Invalid key encapsulation message length"); + } + var ss = kem.implDecapsulate(name, key, k2, encapsulation); + try { + return new SecretKeySpec(ss, + from, to - from, algorithm); + } finally { + Arrays.fill(ss, (byte)0); + } + } + + @Override + public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) { + var enc = kem.implEncapsulate(name, key, k2, sr); + try { + return new KEM.Encapsulated( + new SecretKeySpec(enc[1], + from, to - from, algorithm), + enc[0], + null); + } finally { + Arrays.fill(enc[1], (byte)0); + } + } + + @Override + public int engineSecretSize() { + return sslen; + } + + @Override + public int engineEncapsulationSize() { + return clen; + } + } + + private static KeyConsumerImpl getKeyConsumerImpl(NamedKEM kem, + NamedParameterSpec nps, byte[] key, Object k2, SecureRandom sr) { + String name = nps.getName(); + return new KeyConsumerImpl(kem, name, kem.implSecretSize(name), kem.implEncapsulationSize(name), + key, k2, sr); + } + + /// User-defined encap function. + /// + /// @param name parameter name + /// @param pk public key in raw bytes + /// @param pk2 parsed public key, `null` if none. See [#implCheckPublicKey]. + /// @param sr SecureRandom object, `null` if not initialized + /// @return the key encapsulation message and the shared key (in this order) + /// @throws ProviderException if there is an internal error + protected abstract byte[][] implEncapsulate(String name, byte[] pk, Object pk2, SecureRandom sr); + + /// User-defined decap function. + /// + /// @param name parameter name + /// @param sk private key in raw bytes + /// @param sk2 parsed private key, `null` if none. See [#implCheckPrivateKey]. + /// @param encap the key encapsulation message + /// @return the shared key + /// @throws ProviderException if there is an internal error + /// @throws DecapsulateException if there is another error + protected abstract byte[] implDecapsulate(String name, byte[] sk, Object sk2, byte[] encap) + throws DecapsulateException; + + /// User-defined function returning shared secret key length. + /// + /// @param name parameter name + /// @return shared secret key length + /// @throws ProviderException if there is an internal error + protected abstract int implSecretSize(String name); + + /// User-defined function returning key encapsulation message length. + /// + /// @param name parameter name + /// @return key encapsulation message length + /// @throws ProviderException if there is an internal error + protected abstract int implEncapsulationSize(String name); + + /// User-defined function to validate a public key. + /// + /// This method will be called in `newEncapsulator`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implEncapsulate] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param name parameter name + /// @param pk public key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPublicKey(String name, byte[] pk) throws InvalidKeyException { + return null; + } + + /// User-defined function to validate a private key. + /// + /// This method will be called in `newDecapsulator`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implDecapsulate] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param name parameter name + /// @param sk private key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPrivateKey(String name, byte[] sk) throws InvalidKeyException { + return null; + } +} diff --git a/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java b/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java new file mode 100644 index 0000000000000..727358dd07491 --- /dev/null +++ b/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java @@ -0,0 +1,288 @@ +/* + * 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.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.util.RawKeySpec; +import sun.security.x509.NamedX509Key; + +import java.security.AsymmetricKey; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.NamedParameterSpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; +import java.util.Objects; + +/// A base class for all `KeyFactory` implementations that can be +/// configured with a named parameter set. See [NamedKeyPairGenerator] +/// for more details. +/// +/// This factory supports reading and writing to RAW formats: +/// +/// 1. It reads from a RAW key using `translateKey` if `key.getFormat` is "RAW". +/// 2. It writes to a RAW [EncodedKeySpec] if `getKeySpec(key, EncodedKeySpec.class)` +/// is called. The format of the output is "RAW" and the algorithm is +/// intentionally left unspecified. +/// 3. It reads from and writes to the internal type [RawKeySpec]. +/// +/// When reading from a RAW format, it needs enough info to derive the +/// parameter set name. +public class NamedKeyFactory extends KeyFactorySpi { + + private final String fname; // family name + private final String[] pnames; // allowed parameter set name (at least one) + + /// Creates a new `NamedKeyFactory` object. + /// + /// @param fname the family name + /// @param pnames the standard parameter set names, at least one is needed. + protected NamedKeyFactory(String fname, String... pnames) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + if (pnames == null || pnames.length == 0) { + throw new AssertionError("pnames cannot be null or empty"); + } + this.fname = fname; + this.pnames = pnames; + } + + private String checkName(String name) throws InvalidKeyException { + for (var pname : pnames) { + if (pname.equalsIgnoreCase(name)) { + // return the stored standard name + return pname; + } + } + throw new InvalidKeyException("Unsupported parameter set name: " + name); + } + + @Override + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + if (keySpec instanceof X509EncodedKeySpec xspec) { + try { + return fromX509(xspec.getEncoded()); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } + } else if (keySpec instanceof RawKeySpec rks) { + if (pnames.length == 1) { + return new NamedX509Key(fname, pnames[0], rks.getKeyArr()); + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } else if (keySpec instanceof EncodedKeySpec espec + && espec.getFormat().equalsIgnoreCase("RAW")) { + if (pnames.length == 1) { + return new NamedX509Key(fname, pnames[0], espec.getEncoded()); + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } else { + throw new InvalidKeySpecException("Unsupported keyspec: " + keySpec); + } + } + + @Override + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException { + if (keySpec instanceof PKCS8EncodedKeySpec pspec) { + var bytes = pspec.getEncoded(); + try { + return fromPKCS8(bytes); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } finally { + Arrays.fill(bytes, (byte) 0); + } + } else if (keySpec instanceof RawKeySpec rks) { + if (pnames.length == 1) { + var bytes = rks.getKeyArr(); + try { + return new NamedPKCS8Key(fname, pnames[0], bytes); + } finally { + Arrays.fill(bytes, (byte) 0); + } + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } else if (keySpec instanceof EncodedKeySpec espec + && espec.getFormat().equalsIgnoreCase("RAW")) { + if (pnames.length == 1) { + var bytes = espec.getEncoded(); + try { + return new NamedPKCS8Key(fname, pnames[0], bytes); + } finally { + Arrays.fill(bytes, (byte) 0); + } + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } else { + throw new InvalidKeySpecException("Unsupported keyspec: " + keySpec); + } + } + + private PrivateKey fromPKCS8(byte[] bytes) + throws InvalidKeyException, InvalidKeySpecException { + var k = new NamedPKCS8Key(fname, bytes); + checkName(k.getParams().getName()); + return k; + } + + private PublicKey fromX509(byte[] bytes) + throws InvalidKeyException, InvalidKeySpecException { + var k = new NamedX509Key(fname, bytes); + checkName(k.getParams().getName()); + return k; + } + + private static class RawEncodedKeySpec extends EncodedKeySpec { + public RawEncodedKeySpec(byte[] encodedKey) { + super(encodedKey); + } + + @Override + public String getFormat() { + return "RAW"; + } + } + + @Override + protected T engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException { + try { + key = engineTranslateKey(key); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } + // key is now either NamedPKCS8Key or NamedX509Key of permitted param set + if (key instanceof NamedPKCS8Key nk) { + byte[] bytes = null; + try { + if (keySpec == PKCS8EncodedKeySpec.class) { + return keySpec.cast( + new PKCS8EncodedKeySpec(bytes = key.getEncoded())); + } else if (keySpec == RawKeySpec.class) { + return keySpec.cast(new RawKeySpec(nk.getRawBytes())); + } else if (keySpec.isAssignableFrom(EncodedKeySpec.class)) { + return keySpec.cast( + new RawEncodedKeySpec(nk.getRawBytes())); + } else { + throw new InvalidKeySpecException("Unsupported type: " + keySpec); + } + } finally { + if (bytes != null) { + Arrays.fill(bytes, (byte)0); + } + } + } else if (key instanceof NamedX509Key nk) { + if (keySpec == X509EncodedKeySpec.class + && key.getFormat().equalsIgnoreCase("X.509")) { + return keySpec.cast(new X509EncodedKeySpec(key.getEncoded())); + } else if (keySpec == RawKeySpec.class) { + return keySpec.cast(new RawKeySpec(nk.getRawBytes())); + } else if (keySpec.isAssignableFrom(EncodedKeySpec.class)) { + return keySpec.cast(new RawEncodedKeySpec(nk.getRawBytes())); + } else { + throw new InvalidKeySpecException("Unsupported type: " + keySpec); + } + } + throw new AssertionError("No " + keySpec.getName() + " for " + key.getClass()); + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + if (key == null) { + throw new InvalidKeyException("Key must not be null"); + } + if (key instanceof NamedX509Key nk) { + checkName(nk.getParams().getName()); + return key; + } + if (key instanceof NamedPKCS8Key nk) { + checkName(nk.getParams().getName()); + return key; + } + var format = key.getFormat(); + if (format == null) { + throw new InvalidKeyException("Unextractable key"); + } else if (format.equalsIgnoreCase("RAW")) { + var kAlg = key.getAlgorithm(); + if (key instanceof AsymmetricKey pk) { + String name; + // Three cases that we can find the parameter set name from a RAW key: + // 1. getParams() returns one + // 2. getAlgorithm() returns param set name (some provider does this) + // 3. getAlgorithm() returns family name but this KF is for param set name + if (pk.getParams() instanceof NamedParameterSpec nps) { + name = checkName(nps.getName()); + } else { + if (kAlg.equalsIgnoreCase(fname)) { + if (pnames.length == 1) { + name = pnames[0]; + } else { + throw new InvalidKeyException("No parameter set info"); + } + } else { + name = checkName(kAlg); + } + } + return key instanceof PrivateKey + ? new NamedPKCS8Key(fname, name, key.getEncoded()) + : new NamedX509Key(fname, name, key.getEncoded()); + } else { + throw new InvalidKeyException("Unsupported key type: " + key.getClass()); + } + } else if (format.equalsIgnoreCase("PKCS#8") && key instanceof PrivateKey) { + var bytes = key.getEncoded(); + try { + return fromPKCS8(bytes); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException("Invalid PKCS#8 key", e); + } finally { + Arrays.fill(bytes, (byte) 0); + } + } else if (format.equalsIgnoreCase("X.509") && key instanceof PublicKey) { + try { + return fromX509(key.getEncoded()); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException("Invalid X.509 key", e); + } + } else { + throw new InvalidKeyException("Unsupported key format: " + key.getFormat()); + } + } +} diff --git a/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java b/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java new file mode 100644 index 0000000000000..5be2b2b2a08b0 --- /dev/null +++ b/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java @@ -0,0 +1,177 @@ +/* + * 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.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.KeyPair; +import java.security.KeyPairGeneratorSpi; +import java.security.ProviderException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; +import java.util.Objects; + +/// A base class for all `KeyPairGenerator` implementations that can be +/// configured with a named parameter set. +/// +/// Together with [NamedKeyFactory], [NamedKEM], and [NamedSignature], these +/// classes form a compact framework designed to support any public key +/// algorithm standardized with named parameter sets. In this scenario, +/// the algorithm name is the "family name" and each standardized parameter +/// set has a "parameter set name". Implementations of these classes are able +/// to instantiate a `KeyPairGenerator`, `KeyFactory`, or `KEM` or `Signature` +/// object using either the family name or a parameter set name. All keys used +/// in this context will be of the type [NamedPKCS8Key] or [NamedX509Key], +/// with `getAlgorithm` returning the family name, and `getParams` returning +/// the parameter set name as a [NamedParameterSpec] object. +/// +/// An implementation must include a zero-argument public constructor that +/// calls `super(fname, pnames)`, where `fname` is the family name of the +/// algorithm and `pnames` are its supported parameter set names. `pnames` +/// must contain at least one element. For an implementation of +/// `NamedKeyPairGenerator`, the first element becomes its default parameter +/// set, i.e. the parameter set to be used in key pair generation unless +/// [#initialize(AlgorithmParameterSpec, java.security.SecureRandom)] +/// is called on a different parameter set. +/// +/// An implementation must implement all abstract methods. For all these +/// methods, the implementation must relinquish any "ownership" of any input +/// and output array argument. Precisely, the implementation must not retain +/// any reference to a returning array so that it won't be able to modify its +/// content later. Similarly, the implementation must not modify any input +/// array argument and must not retain any reference to an input array argument +/// after the call. +/// +/// Also, an implementation must not keep any extra copy of a private key. +/// For key generation, the only copy is the one returned in the +/// [#implGenerateKeyPair] call. For all other methods, it must not make +/// a copy of the input private key. A `KEM` implementation also must not +/// keep a copy of the shared secret key, no matter if it's an encapsulator +/// or a decapsulator. Only the code that owns these sensitive data can +/// choose to perform cleanup when it determines they are no longer needed. +/// +/// The `NamedSignature` and `NamedKEM` classes provide `implCheckPublicKey` +/// and `implCheckPrivateKey` methods that allow an implementation to validate +/// a key before using it. An implementation may return a parsed key in +/// a local type, and this parsed key will be passed to an operational method +/// (For example, `implSign`) later. An implementation must not retain +/// a reference of the parsed key. +/// +/// When constructing a [NamedX509Key] or [NamedPKCS8Key] object from raw key +/// bytes, the key bytes are directly referenced within the object, so the +/// caller must not modify them afterward. Similarly, the key's `getRawBytes` +/// method returns direct references to the underlying raw key bytes, meaning +/// the caller must not alter the contents of the returned value. +/// +/// Together, these measures ensure the classes are as efficient as possible, +/// preventing unnecessary array cloning and potential data leaks. While these +/// classes should not be considered immutable, strictly adhering to the rules +/// above will ensure data integrity is maintained. +/// +/// Note: A limitation of `NamedKeyPairGenerator` and `NamedKeyFactory` is +/// that the keys generated by their implementations will always be of type +/// `NamedX509Key` or `NamedPKCS8Key`. Existing implementations of algorithms +/// like EdDSA and XDH have been generating keys implementing `EdECKey` or +/// `XECKey` interfaces, and they are not rewritten with this framework. +/// `NamedParameterSpec` fields not implemented with this framework include +/// Ed25519, Ed448, X25519, and X448. +public abstract class NamedKeyPairGenerator extends KeyPairGeneratorSpi { + + private final String fname; // family name + private final String[] pnames; // allowed parameter set name (at least one) + + protected String name; // init as + private SecureRandom secureRandom; + + /// Creates a new `NamedKeyPairGenerator` object. + /// + /// @param fname the family name + /// @param pnames supported parameter set names, at least one is needed. + /// If multiple, the first one becomes the default parameter set name. + protected NamedKeyPairGenerator(String fname, String... pnames) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + if (pnames == null || pnames.length == 0) { + throw new AssertionError("pnames cannot be null or empty"); + } + this.fname = fname; + this.pnames = pnames; + } + + private String checkName(String name) throws InvalidAlgorithmParameterException { + for (var pname : pnames) { + if (pname.equalsIgnoreCase(name)) { + // return the stored standard name + return pname; + } + } + throw new InvalidAlgorithmParameterException( + "Unsupported parameter set name: " + name); + } + + @Override + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException { + if (params instanceof NamedParameterSpec spec) { + name = checkName(spec.getName()); + } else { + throw new InvalidAlgorithmParameterException( + "Unsupported AlgorithmParameterSpec: " + params); + } + this.secureRandom = random; + } + + @Override + public void initialize(int keysize, SecureRandom random) { + if (keysize != -1) { + // User can call initialize(-1, sr) to provide a SecureRandom + // without touching the parameter set currently used + throw new InvalidParameterException("keysize not supported"); + } + this.secureRandom = random; + } + + @Override + public KeyPair generateKeyPair() { + String pname = name != null ? name : pnames[0]; + var keys = implGenerateKeyPair(pname, secureRandom); + return new KeyPair(new NamedX509Key(fname, pname, keys[0]), + new NamedPKCS8Key(fname, pname, keys[1])); + } + + /// User-defined key pair generator. + /// + /// @param pname parameter set name + /// @param sr `SecureRandom` object, `null` if not initialized + /// @return public key and private key (in this order) in raw bytes + /// @throws ProviderException if there is an internal error + protected abstract byte[][] implGenerateKeyPair(String pname, SecureRandom sr); +} diff --git a/src/java.base/share/classes/sun/security/provider/NamedSignature.java b/src/java.base/share/classes/sun/security/provider/NamedSignature.java new file mode 100644 index 0000000000000..921a39cfc926d --- /dev/null +++ b/src/java.base/share/classes/sun/security/provider/NamedSignature.java @@ -0,0 +1,222 @@ +/* + * 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.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import java.io.ByteArrayOutputStream; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.SignatureSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Objects; + +/// A base class for all `Signature` implementations that can be +/// configured with a named parameter set. See [NamedKeyPairGenerator] +/// for more details. +/// +/// This class does not work with preHash signatures. +public abstract class NamedSignature extends SignatureSpi { + + private final String fname; // family name + private final String[] pnames; // allowed parameter set name (at least one) + + private final ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + // init with... + private String name; + private byte[] secKey; + private byte[] pubKey; + + private Object sk2; + private Object pk2; + + /// Creates a new `NamedSignature` object. + /// + /// @param fname the family name + /// @param pnames the standard parameter set names, at least one is needed. + protected NamedSignature(String fname, String... pnames) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + if (pnames == null || pnames.length == 0) { + throw new AssertionError("pnames cannot be null or empty"); + } + this.fname = fname; + this.pnames = pnames; + } + + @Override + protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { + // translate also check the key + var nk = (NamedX509Key) new NamedKeyFactory(fname, pnames) + .engineTranslateKey(publicKey); + name = nk.getParams().getName(); + pubKey = nk.getRawBytes(); + pk2 = implCheckPublicKey(name, pubKey); + secKey = null; + bout.reset(); + } + + @Override + protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { + // translate also check the key + var nk = (NamedPKCS8Key) new NamedKeyFactory(fname, pnames) + .engineTranslateKey(privateKey); + name = nk.getParams().getName(); + secKey = nk.getRawBytes(); + sk2 = implCheckPrivateKey(name, secKey); + pubKey = null; + bout.reset(); + } + + @Override + protected void engineUpdate(byte b) throws SignatureException { + bout.write(b); + } + + @Override + protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { + bout.write(b, off, len); + } + + @Override + protected byte[] engineSign() throws SignatureException { + if (secKey != null) { + var msg = bout.toByteArray(); + bout.reset(); + return implSign(name, secKey, sk2, msg, appRandom); + } else { + throw new SignatureException("No private key"); + } + } + + @Override + protected boolean engineVerify(byte[] sig) throws SignatureException { + if (pubKey != null) { + var msg = bout.toByteArray(); + bout.reset(); + return implVerify(name, pubKey, pk2, msg, sig); + } else { + throw new SignatureException("No public key"); + } + } + + @Override + @SuppressWarnings("deprecation") + protected void engineSetParameter(String param, Object value) + throws InvalidParameterException { + throw new InvalidParameterException("setParameter() not supported"); + } + + @Override + @SuppressWarnings("deprecation") + protected Object engineGetParameter(String param) throws InvalidParameterException { + throw new InvalidParameterException("getParameter() not supported"); + } + + @Override + protected void engineSetParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidAlgorithmParameterException( + "The " + fname + " algorithm does not take any parameters"); + } + } + + @Override + protected AlgorithmParameters engineGetParameters() { + return null; + } + + /// User-defined sign function. + /// + /// @param name parameter name + /// @param sk private key in raw bytes + /// @param sk2 parsed private key, `null` if none. See [#implCheckPrivateKey]. + /// @param msg the message + /// @param sr SecureRandom object, `null` if not initialized + /// @return the signature + /// @throws ProviderException if there is an internal error + /// @throws SignatureException if there is another error + protected abstract byte[] implSign(String name, byte[] sk, Object sk2, + byte[] msg, SecureRandom sr) throws SignatureException; + + /// User-defined verify function. + /// + /// @param name parameter name + /// @param pk public key in raw bytes + /// @param pk2 parsed public key, `null` if none. See [#implCheckPublicKey]. + /// @param msg the message + /// @param sig the signature + /// @return true if verified + /// @throws ProviderException if there is an internal error + /// @throws SignatureException if there is another error + protected abstract boolean implVerify(String name, byte[] pk, Object pk2, + byte[] msg, byte[] sig) throws SignatureException; + + /// User-defined function to validate a public key. + /// + /// This method will be called in `initVerify`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implVerify] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param name parameter name + /// @param pk public key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPublicKey(String name, byte[] pk) throws InvalidKeyException { + return null; + } + + /// User-defined function to validate a private key. + /// + /// This method will be called in `initSign`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implSign] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param name parameter name + /// @param sk private key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPrivateKey(String name, byte[] sk) throws InvalidKeyException { + return null; + } +} diff --git a/src/java.base/share/classes/sun/security/provider/SHA3.java b/src/java.base/share/classes/sun/security/provider/SHA3.java index 75430c63916a9..5f974bc6ea658 100644 --- a/src/java.base/share/classes/sun/security/provider/SHA3.java +++ b/src/java.base/share/classes/sun/security/provider/SHA3.java @@ -32,6 +32,7 @@ import java.util.Arrays; import java.util.Objects; +import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.IntrinsicCandidate; import static java.lang.Math.min; @@ -99,6 +100,7 @@ private SHA3(String name, int digestLength, byte suffix, int c) { private void implCompressCheck(byte[] b, int ofs) { Objects.requireNonNull(b); + Preconditions.checkIndex(ofs + blockSize - 1, b.length, Preconditions.AIOOBE_FORMATTER); } /** 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 babf2bb452da4..e75076b11d64f 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHello.java @@ -213,8 +213,6 @@ byte[] getHelloCookieBytes() { // ignore cookie hos.putBytes16(getEncodedCipherSuites()); hos.putBytes8(compressionMethod); - extensions.send(hos); // In TLS 1.3, use of certain - // extensions is mandatory. } catch (IOException ioe) { // unlikely } @@ -1426,6 +1424,9 @@ public void consume(ConnectionContext context, shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id, SSLHandshake.SERVER_HELLO); + // Reset the ClientHello non-zero offset fragment allowance + shc.acceptCliHelloFragments = false; + // // produce // diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java index 337cf76f2c241..e0196f3009cb8 100644 --- a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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 @@ -40,12 +40,23 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { private DTLSReassembler reassembler = null; private int readEpoch; + private SSLContextImpl sslContext; DTLSInputRecord(HandshakeHash handshakeHash) { super(handshakeHash, SSLReadCipher.nullDTlsReadCipher()); this.readEpoch = 0; } + // Method to set TransportContext + public void setTransportContext(TransportContext tc) { + this.tc = tc; + } + + // Method to set SSLContext + public void setSSLContext(SSLContextImpl sslContext) { + this.sslContext = sslContext; + } + @Override void changeReadCiphers(SSLReadCipher readCipher) { this.readCipher = readCipher; @@ -537,6 +548,27 @@ public int compareTo(RecordFragment o) { } } + /** + * Turn a sufficiently-large initial ClientHello fragment into one that + * stops immediately after the compression methods. This is only used + * for the initial CH message fragment at offset 0. + * + * @param srcFrag the fragment actually received by the DTLSReassembler + * @param limit the size of the new, cloned/truncated handshake fragment + * + * @return a truncated handshake fragment that is sized to look like a + * complete message, but actually contains only up to the compression + * methods (no extensions) + */ + private static HandshakeFragment truncateChFragment(HandshakeFragment srcFrag, + int limit) { + return new HandshakeFragment(Arrays.copyOf(srcFrag.fragment, limit), + srcFrag.contentType, srcFrag.majorVersion, + srcFrag.minorVersion, srcFrag.recordEnS, srcFrag.recordEpoch, + srcFrag.recordSeq, srcFrag.handshakeType, limit, + srcFrag.messageSeq, srcFrag.fragmentOffset, limit); + } + private static final class HoleDescriptor { int offset; // fragment_offset int limit; // fragment_offset + fragment_length @@ -640,10 +672,17 @@ void expectingFinishFlight() { // Queue up a handshake message. void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException { if (!isDesirable(hsf)) { - // Not a dedired record, discard it. + // Not a desired record, discard it. return; } + if (hsf.handshakeType == SSLHandshake.CLIENT_HELLO.id) { + // validate the first or subsequent ClientHello message + if ((hsf = valHello(hsf, hsf.messageSeq == 0)) == null) { + return; + } + } + // Clean up the retransmission messages if necessary. cleanUpRetransmit(hsf); @@ -769,6 +808,100 @@ void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException { } } + private HandshakeFragment valHello(HandshakeFragment hsf, + boolean firstHello) { + ServerHandshakeContext shc = + (ServerHandshakeContext) tc.handshakeContext; + // Drop any fragment that is not a zero offset until we've received + // a second (or possibly later) CH message that passes the cookie + // check. + if (shc == null || !shc.acceptCliHelloFragments) { + if (hsf.fragmentOffset != 0) { + return null; + } + } else { + // Let this fragment through to the DTLSReassembler as-is + return hsf; + } + + try { + ByteBuffer fragmentData = ByteBuffer.wrap(hsf.fragment); + + ProtocolVersion pv = ProtocolVersion.valueOf( + Record.getInt16(fragmentData)); + if (!pv.isDTLS) { + return null; + } + // Read the random (32 bytes) + if (fragmentData.remaining() < 32) { + if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + SSLLogger.fine("Rejected client hello fragment (bad random len) " + + "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength); + } + return null; + } + fragmentData.position(fragmentData.position() + 32); + + // SessionID + byte[] sessId = Record.getBytes8(fragmentData); + if (sessId.length > 0 && + !SSLConfiguration.enableDtlsResumeCookie) { + // If we are in a resumption it is possible that the cookie + // exchange will be skipped. This is a server-side setting + // and it is NOT the default. If enableDtlsResumeCookie is + // false though, then we will buffer fragments since there + // is no cookie exchange to execute prior to performing + // reassembly. + return hsf; + } + + // Cookie + byte[] cookie = Record.getBytes8(fragmentData); + if (firstHello && cookie.length != 0) { + if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + SSLLogger.fine("Rejected initial client hello fragment (bad cookie len) " + + "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength); + } + return null; + } + // CipherSuites + Record.getBytes16(fragmentData); + // Compression methods + Record.getBytes8(fragmentData); + + // If it's the first fragment, we'll truncate it and push it + // through the reassembler. + if (firstHello) { + return truncateChFragment(hsf, fragmentData.position()); + } else { + HelloCookieManager hcMgr = sslContext. + getHelloCookieManager(ProtocolVersion.DTLS10); + ByteBuffer msgFragBuf = ByteBuffer.wrap(hsf.fragment, 0, + fragmentData.position()); + ClientHello.ClientHelloMessage chMsg = + new ClientHello.ClientHelloMessage(shc, msgFragBuf, null); + if (!hcMgr.isCookieValid(shc, chMsg, cookie)) { + // Bad cookie check, truncate it and let the ClientHello + // consumer recheck, fail and take the appropriate action. + return truncateChFragment(hsf, fragmentData.position()); + } else { + // It's a good cookie, return the original handshake + // fragment and let it go into the DTLSReassembler like + // any other fragment so we can wait for the rest of + // the CH message. + shc.acceptCliHelloFragments = true; + return hsf; + } + } + } catch (IOException ioe) { + if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + SSLLogger.fine("Rejected client hello fragment " + + "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength); + } + return null; + } + } + // Queue up a ChangeCipherSpec message void queueUpChangeCipherSpec(RecordFragment rf) throws SSLProtocolException { diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java index 829fa2af96c7c..11b625e57911c 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.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 @@ -55,6 +55,7 @@ class ServerHandshakeContext extends HandshakeContext { CertificateMessage.CertificateEntry currentCertEntry; private static final long DEFAULT_STATUS_RESP_DELAY = 5000L; final long statusRespTimeout; + boolean acceptCliHelloFragments = false; ServerHandshakeContext(SSLContextImpl sslContext, diff --git a/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java b/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java index 0632f846cbf71..1baf3264122e4 100644 --- a/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java +++ b/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,7 +257,20 @@ Map get(CertStatusRequestType type, } if (!task.isCancelled()) { - StatusInfo info = task.get(); + StatusInfo info; + try { + info = task.get(); + } catch (ExecutionException exc) { + // Check for an underlying cause available and log + // that, otherwise just log the ExecutionException + Throwable cause = Optional.ofNullable( + exc.getCause()).orElse(exc); + if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + SSLLogger.fine("Exception during OCSP fetch: " + + cause); + } + continue; + } if (info != null && info.responseData != null) { responseMap.put(info.cert, info.responseData.ocspBytes); @@ -272,10 +285,12 @@ Map get(CertStatusRequestType type, } } } - } catch (InterruptedException | ExecutionException exc) { - // Not sure what else to do here + } catch (InterruptedException intex) { + // Log and reset the interrupt state + Thread.currentThread().interrupt(); if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { - SSLLogger.fine("Exception when getting data: ", exc); + SSLLogger.fine("Interrupt occurred while fetching: " + + intex); } } } @@ -582,8 +597,7 @@ private void addToCache(CertId certId, ResponseCacheEntry entry) { } - static final StaplingParameters processStapling( - ServerHandshakeContext shc) { + static StaplingParameters processStapling(ServerHandshakeContext shc) { StaplingParameters params = null; SSLExtension ext = null; CertStatusRequestType type = null; diff --git a/src/java.base/share/classes/sun/security/ssl/TransportContext.java b/src/java.base/share/classes/sun/security/ssl/TransportContext.java index c235da3068cba..f65a08dfcfed8 100644 --- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java +++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -156,6 +156,11 @@ private TransportContext(SSLContextImpl sslContext, SSLTransport transport, this.acc = AccessController.getContext(); this.consumers = new HashMap<>(); + + if (inputRecord instanceof DTLSInputRecord dtlsInputRecord) { + dtlsInputRecord.setTransportContext(this); + dtlsInputRecord.setSSLContext(this.sslContext); + } } // Dispatch plaintext to a specific consumer. diff --git a/src/java.base/share/classes/sun/security/util/KeyUtil.java b/src/java.base/share/classes/sun/security/util/KeyUtil.java index 6884b9b201a39..d057bb689e99e 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -184,13 +184,13 @@ public static final int getKeySize(AlgorithmParameters parameters) { */ public static final String fullDisplayAlgName(Key key) { String result = key.getAlgorithm(); - if (key instanceof ECKey) { - ECParameterSpec paramSpec = ((ECKey) key).getParams(); + if (key instanceof AsymmetricKey ak) { + AlgorithmParameterSpec paramSpec = ak.getParams(); if (paramSpec instanceof NamedCurve nc) { result += " (" + nc.getNameAndAliases()[0] + ")"; + } else if (paramSpec instanceof NamedParameterSpec nps) { + result = nps.getName(); } - } else if (key instanceof EdECKey) { - result = ((EdECKey) key).getParams().getName(); } return result; } diff --git a/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java b/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java index 6181bf223e9ae..306d34d7149f4 100644 --- a/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java +++ b/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,13 +127,24 @@ public final class ObjectIdentifier implements Serializable { // Is the component's field calculated? private transient boolean componentsCalculated = false; + /** + * Restores the state of this object from the stream. + * + * @param is the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ @java.io.Serial private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { is.defaultReadObject(); if (encoding == null) { // from an old version - int[] comp = (int[])components; + if (components == null) { + throw new InvalidObjectException("OID components is null"); + } + + int[] comp = ((int[]) components).clone(); if (componentLen > comp.length) { componentLen = comp.length; } @@ -142,7 +153,9 @@ private void readObject(ObjectInputStream is) // will be performed again in init(). checkOidSize(componentLen); init(comp, componentLen); + components = comp; } else { + encoding = encoding.clone(); // defensive copying checkOidSize(encoding.length); check(encoding); } @@ -261,6 +274,7 @@ public ObjectIdentifier(DerInputStream in) throws IOException { encoding = in.getDerValue().getOID().encoding; } + // set 'encoding' field based on the specified 'components' and 'length' private void init(int[] components, int length) throws IOException { int pos = 0; byte[] tmp = new byte[length * 5 + 1]; // +1 for empty input diff --git a/src/java.base/share/classes/sun/security/util/SignatureUtil.java b/src/java.base/share/classes/sun/security/util/SignatureUtil.java index 155adc198d0e9..c1ffd248f2a60 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureUtil.java +++ b/src/java.base/share/classes/sun/security/util/SignatureUtil.java @@ -33,6 +33,7 @@ import java.security.spec.*; import java.util.Locale; +import sun.security.pkcs.NamedPKCS8Key; import sun.security.rsa.RSAUtil; import jdk.internal.access.SharedSecrets; import sun.security.x509.AlgorithmId; @@ -274,7 +275,7 @@ public static String extractDigestAlgFromDwithE(String signatureAlgorithm) { return signatureAlgorithm.substring(0, with); } else { throw new IllegalArgumentException( - "Unknown algorithm: " + signatureAlgorithm); + "Cannot extract digest algorithm from " + signatureAlgorithm); } } @@ -390,8 +391,8 @@ private static Signature autoInitInternal(String alg, PrivateKey key, Signature public static AlgorithmId fromSignature(Signature sigEngine, PrivateKey key) throws SignatureException { try { - if (key instanceof EdECKey) { - return AlgorithmId.get(((EdECKey) key).getParams().getName()); + if (key.getParams() instanceof NamedParameterSpec nps) { + return AlgorithmId.get(nps.getName()); } AlgorithmParameters params = null; @@ -431,6 +432,14 @@ public static AlgorithmId fromSignature(Signature sigEngine, PrivateKey key) public static void checkKeyAndSigAlgMatch(PrivateKey key, String sAlg) { String kAlg = key.getAlgorithm().toUpperCase(Locale.ENGLISH); sAlg = checkName(sAlg); + if (key instanceof NamedPKCS8Key n8k) { + if (!sAlg.equalsIgnoreCase(n8k.getAlgorithm()) + && !sAlg.equalsIgnoreCase(n8k.getParams().getName())) { + throw new IllegalArgumentException( + "key algorithm not compatible with signature algorithm"); + } + return; + } switch (sAlg) { case "RSASSA-PSS" -> { if (!kAlg.equals("RSASSA-PSS") @@ -495,8 +504,10 @@ public static String getDefaultSigAlgForKey(PrivateKey k) { case "EDDSA" -> k instanceof EdECPrivateKey ? ((EdECPrivateKey) k).getParams().getName() : kAlg; - default -> kAlg; // All modern signature algorithms, - // RSASSA-PSS, ED25519, ED448, HSS/LMS, etc + default -> kAlg.contains("KEM") ? null : kAlg; + // All modern signature algorithms use the same name across + // key algorithms and signature algorithms, for example, + // RSASSA-PSS, ED25519, ED448, HSS/LMS, etc }; } diff --git a/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java b/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java index 3a3d384a0e861..764d77e6da87f 100644 --- a/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java +++ b/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,13 @@ package sun.security.x509; +import java.io.ObjectInputStream; import java.io.IOException; +import java.io.InvalidObjectException; import java.math.BigInteger; import java.security.*; import java.security.interfaces.DSAParams; - +import java.util.Arrays; import sun.security.util.*; @@ -72,33 +74,42 @@ * * @author David Brownell */ -public final -class AlgIdDSA extends AlgorithmId implements DSAParams -{ +public final class AlgIdDSA extends AlgorithmId implements DSAParams { @java.io.Serial private static final long serialVersionUID = 3437177836797504046L; + private static class DSAComponents { + private final BigInteger p; + private final BigInteger q; + private final BigInteger g; + DSAComponents(BigInteger p, BigInteger q, BigInteger g) { + this.p = p; + this.q = q; + this.g = g; + } + } + /* * The three unsigned integer parameters. */ - private BigInteger p , q, g; + private BigInteger p, q, g; /** Returns the DSS/DSA parameter "P" */ - public BigInteger getP () { return p; } + public BigInteger getP() { return p; } /** Returns the DSS/DSA parameter "Q" */ - public BigInteger getQ () { return q; } + public BigInteger getQ() { return q; } /** Returns the DSS/DSA parameter "G" */ - public BigInteger getG () { return g; } + public BigInteger getG() { return g; } /** * Default constructor. The OID and parameters must be * deserialized before this algorithm ID is used. */ @Deprecated - public AlgIdDSA () {} + public AlgIdDSA() {} /** * Constructs a DSS/DSA Algorithm ID from numeric parameters. @@ -109,7 +120,7 @@ public AlgIdDSA () {} * @param q the DSS/DSA parameter "Q" * @param g the DSS/DSA parameter "G" */ - public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g) { + public AlgIdDSA(BigInteger p, BigInteger q, BigInteger g) { super (DSA_oid); if (p != null || q != null || g != null) { @@ -120,8 +131,10 @@ public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g) { this.p = p; this.q = q; this.g = g; - initializeParams (); - + // For algorithm IDs which haven't been created from a DER + // encoded value, need to create DER encoding and store it + // into "encodedParams" + encodedParams = encode(p, q, g); } catch (IOException e) { /* this should not happen */ throw new ProviderException ("Construct DSS/DSA Algorithm ID"); @@ -133,50 +146,10 @@ public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g) { * Returns "DSA", indicating the Digital Signature Algorithm (DSA) as * defined by the Digital Signature Standard (DSS), FIPS 186. */ - public String getName () - { return "DSA"; } - - - /* - * For algorithm IDs which haven't been created from a DER encoded - * value, "params" must be created. - */ - private void initializeParams () throws IOException { - DerOutputStream out = new DerOutputStream(); - out.putInteger(p); - out.putInteger(q); - out.putInteger(g); - DerOutputStream result = new DerOutputStream(); - result.write(DerValue.tag_Sequence, out); - encodedParams = result.toByteArray(); - } - - /** - * Parses algorithm parameters P, Q, and G. They're found - * in the "params" member, which never needs to be changed. - */ - protected void decodeParams () throws IOException { - if (encodedParams == null) { - throw new IOException("DSA alg params are null"); - } - - DerValue params = new DerValue(encodedParams); - if (params.tag != DerValue.tag_Sequence) { - throw new IOException("DSA alg parsing error"); - } - - params.data.reset (); - - this.p = params.data.getBigInteger(); - this.q = params.data.getBigInteger(); - this.g = params.data.getBigInteger(); - - if (params.data.available () != 0) - throw new IOException ("AlgIdDSA params, extra="+ - params.data.available ()); + public String getName() { + return "DSA"; } - /* * Returns a formatted string describing the parameters. */ @@ -197,4 +170,44 @@ protected String paramsToString () { "\n"; } } + + /** + * Restores the state of this object from the stream. Override to check + * on the 'p', 'q', 'g', and 'encodedParams'. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) throws IOException { + try { + stream.defaultReadObject(); + // if any of the 'p', 'q', 'g', 'encodedParams' is non-null, + // then they must be all non-null w/ matching encoding + if ((p != null || q != null || g != null || encodedParams != null) + && !Arrays.equals(encodedParams, encode(p, q, g))) { + throw new InvalidObjectException("Invalid DSA alg params"); + } + } catch (ClassNotFoundException e) { + throw new IOException(e); + } + } + + /* + * Create the DER encoding w/ the specified 'p', 'q', 'g' + */ + private static byte[] encode(BigInteger p, BigInteger q, + BigInteger g) throws IOException { + if (p == null || q == null || g == null) { + throw new InvalidObjectException("invalid null value"); + } + DerOutputStream out = new DerOutputStream(); + out.putInteger(p); + out.putInteger(q); + out.putInteger(g); + DerOutputStream result = new DerOutputStream(); + result.write(DerValue.tag_Sequence, out); + return result.toByteArray(); + } } diff --git a/src/java.base/share/classes/sun/security/x509/NamedX509Key.java b/src/java.base/share/classes/sun/security/x509/NamedX509Key.java new file mode 100644 index 0000000000000..dc36bd3b9b306 --- /dev/null +++ b/src/java.base/share/classes/sun/security/x509/NamedX509Key.java @@ -0,0 +1,120 @@ +/* + * 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.x509; + +import sun.security.util.BitArray; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.Serial; +import java.security.InvalidKeyException; +import java.security.KeyRep; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.security.spec.NamedParameterSpec; + +/// Represents a public key from an algorithm family that is specialized +/// with a named parameter set. +/// +/// This key is generated by either a [sun.security.provider.NamedKeyPairGenerator] +/// or [sun.security.provider.NamedKeyFactory]. Its [#getAlgorithm] method +/// returns the algorithm family name, while its [#getParams()] method returns +/// the parameter set name as a [NamedParameterSpec] object. The algorithm +/// identifier in the X.509 encoding of the key is always a single OID derived +/// from the parameter set name. +/// +/// @see sun.security.provider.NamedKeyPairGenerator +public final class NamedX509Key extends X509Key { + @Serial + private static final long serialVersionUID = 1L; + + private final String fname; + private final transient NamedParameterSpec paramSpec; + private final byte[] rawBytes; + + /// Ctor from family name, parameter set name, raw key bytes. + /// Key bytes won't be cloned, caller must relinquish ownership + public NamedX509Key(String fname, String pname, byte[] rawBytes) { + this.fname = fname; + this.paramSpec = new NamedParameterSpec(pname); + try { + this.algid = AlgorithmId.get(pname); + } catch (NoSuchAlgorithmException e) { + throw new ProviderException(e); + } + this.rawBytes = rawBytes; + + setKey(new BitArray(rawBytes.length * 8, rawBytes)); + } + + /// Ctor from family name, and X.509 bytes + public NamedX509Key(String fname, byte[] encoded) throws InvalidKeyException { + this.fname = fname; + decode(encoded); + this.paramSpec = new NamedParameterSpec(algid.getName()); + if (algid.encodedParams != null) { + throw new InvalidKeyException("algorithm identifier has params"); + } + this.rawBytes = getKey().toByteArray(); + } + + @Override + public String toString() { + // Do not modify: this can be used by earlier JDKs that + // do not have the getParams() method + return paramSpec.getName() + " public key"; + } + + /// Returns the reference to the internal key. Caller must not modify + /// the content or keep a reference. + public byte[] getRawBytes() { + return rawBytes; + } + + @Override + public NamedParameterSpec getParams() { + return paramSpec; + } + + @Override + public String getAlgorithm() { + return fname; + } + + @java.io.Serial + private Object writeReplace() throws java.io.ObjectStreamException { + return new KeyRep(KeyRep.Type.PUBLIC, getAlgorithm(), getFormat(), + getEncoded()); + } + + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "NamedX509Key keys are not directly deserializable"); + } +} diff --git a/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java b/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java index 9f72a6c55403c..c5421114f7d49 100644 --- a/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java +++ b/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -280,14 +280,20 @@ public X500Principal getIssuerX500Principal() { * prevCertIssuer if it does not exist */ private X500Principal getCertIssuer(X509CRLEntryImpl entry, - X500Principal prevCertIssuer) { + X500Principal prevCertIssuer) throws CRLException { CertificateIssuerExtension ciExt = entry.getCertificateIssuerExtension(); if (ciExt != null) { GeneralNames names = ciExt.getNames(); - X500Name issuerDN = (X500Name) names.get(0).getName(); - return issuerDN.asX500Principal(); + Iterator itr = names.iterator(); + while (itr.hasNext()) { + if (itr.next().getName() instanceof X500Name issuerDN) { + return issuerDN.asX500Principal(); + } + } + throw new CRLException("Parsing error: CertificateIssuer " + + "field does not contain an X.500 DN"); } else { return prevCertIssuer; } diff --git a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java index 4e30e403bb2f5..8bfb8088108ce 100644 --- a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -36,6 +36,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.time.LocalDateTime; +import java.time.ZoneId; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Arrays; @@ -43,14 +44,12 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.SimpleTimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.zip.CRC32; import jdk.internal.util.StaticProperty; -import sun.security.action.GetPropertyAction; /** * Loads TZDB time-zone rules for j.u.TimeZone @@ -65,19 +64,12 @@ public final class ZoneInfoFile { * @return a set of time zone IDs. */ public static String[] getZoneIds() { - int len = regions.length + oldMappings.length; - if (!USE_OLDMAPPING) { - len += 3; // EST/HST/MST not in tzdb.dat - } + var shortIDs = ZoneId.SHORT_IDS.keySet(); + int len = regions.length + shortIDs.size(); String[] ids = Arrays.copyOf(regions, len); int i = regions.length; - if (!USE_OLDMAPPING) { - ids[i++] = "EST"; - ids[i++] = "HST"; - ids[i++] = "MST"; - } - for (int j = 0; j < oldMappings.length; j++) { - ids[i++] = oldMappings[j][0]; + for (var id : shortIDs) { + ids[i++] = id; } return ids; } @@ -216,42 +208,7 @@ private ZoneInfoFile() { private static String[] regions; private static int[] indices; - // Flag for supporting JDK backward compatible IDs, such as "EST". - private static final boolean USE_OLDMAPPING; - - private static final String[][] oldMappings = new String[][] { - { "ACT", "Australia/Darwin" }, - { "AET", "Australia/Sydney" }, - { "AGT", "America/Argentina/Buenos_Aires" }, - { "ART", "Africa/Cairo" }, - { "AST", "America/Anchorage" }, - { "BET", "America/Sao_Paulo" }, - { "BST", "Asia/Dhaka" }, - { "CAT", "Africa/Harare" }, - { "CNT", "America/St_Johns" }, - { "CST", "America/Chicago" }, - { "CTT", "Asia/Shanghai" }, - { "EAT", "Africa/Addis_Ababa" }, - { "ECT", "Europe/Paris" }, - { "IET", "America/Indiana/Indianapolis" }, - { "IST", "Asia/Kolkata" }, - { "JST", "Asia/Tokyo" }, - { "MIT", "Pacific/Apia" }, - { "NET", "Asia/Yerevan" }, - { "NST", "Pacific/Auckland" }, - { "PLT", "Asia/Karachi" }, - { "PNT", "America/Phoenix" }, - { "PRT", "America/Puerto_Rico" }, - { "PST", "America/Los_Angeles" }, - { "SST", "Pacific/Guadalcanal" }, - { "VST", "Asia/Ho_Chi_Minh" }, - }; - static { - String oldmapping = GetPropertyAction - .privilegedGetProperty("sun.timezone.ids.oldmapping", "false") - .toLowerCase(Locale.ROOT); - USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true")); loadTZDB(); } @@ -274,25 +231,6 @@ public Void run() { }); } - private static void addOldMapping() { - for (String[] alias : oldMappings) { - aliases.put(alias[0], alias[1]); - } - if (USE_OLDMAPPING) { - aliases.put("EST", "America/New_York"); - aliases.put("MST", "America/Denver"); - aliases.put("HST", "Pacific/Honolulu"); - } else { - zones.put("EST", new ZoneInfo("EST", -18000000)); - zones.put("MST", new ZoneInfo("MST", -25200000)); - zones.put("HST", new ZoneInfo("HST", -36000000)); - } - } - - public static boolean useOldMapping() { - return USE_OLDMAPPING; - } - /** * Loads the rules from a DateInputStream * @@ -351,7 +289,7 @@ private static void load(DataInputStream dis) throws IOException { } } // old us time-zone names - addOldMapping(); + aliases.putAll(ZoneId.SHORT_IDS); } /////////////////////////Ser///////////////////////////////// diff --git a/src/java.base/share/conf/net.properties b/src/java.base/share/conf/net.properties index 67f294355a10e..2aa9a9630bed2 100644 --- a/src/java.base/share/conf/net.properties +++ b/src/java.base/share/conf/net.properties @@ -130,3 +130,20 @@ jdk.http.auth.tunneling.disabledSchemes=Basic #jdk.http.ntlm.transparentAuth=trustedHosts # jdk.http.ntlm.transparentAuth=disabled + +# +# Maximum HTTP field section size that a client is prepared to accept +# +# jdk.http.maxHeaderSize=393216 +# +# This is the maximum header field section size that a client is prepared to accept. +# This is computed as the sum of the size of the uncompressed header name, plus +# the size of the uncompressed header value, plus an overhead of 32 bytes for +# each field section line. If a peer sends a field section that exceeds this +# size a {@link java.net.ProtocolException ProtocolException} will be raised. +# This applies to all versions of the HTTP protocol. A value of zero or a negative +# value means no limit. If left unspecified, the default value is 393216 bytes +# or 384kB. +# +# Note: This property is currently used by the JDK Reference implementation. It +# is not guaranteed to be examined and used by other implementations. diff --git a/src/java.base/share/data/tzdata/VERSION b/src/java.base/share/data/tzdata/VERSION index b138ed7fa78f5..740427424a600 100644 --- a/src/java.base/share/data/tzdata/VERSION +++ b/src/java.base/share/data/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2024a +tzdata2024b diff --git a/src/java.base/share/data/tzdata/africa b/src/java.base/share/data/tzdata/africa index 72b188f074deb..8098f4bea9d30 100644 --- a/src/java.base/share/data/tzdata/africa +++ b/src/java.base/share/data/tzdata/africa @@ -126,17 +126,16 @@ Zone Africa/Algiers 0:12:12 - LMT 1891 Mar 16 # Cape Verde / Cabo Verde # -# From Paul Eggert (2018-02-16): -# Shanks gives 1907 for the transition to +02. -# For now, ignore that and follow the 1911-05-26 Portuguese decree -# (see Europe/Lisbon). +# From Tim Parenti (2024-07-01), per Paul Eggert (2018-02-16): +# For timestamps before independence, see commentary for Europe/Lisbon. +# Shanks gives 1907 instead for the transition to -02. # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Atlantic/Cape_Verde -1:34:04 - LMT 1912 Jan 01 2:00u # Praia - -2:00 - -02 1942 Sep - -2:00 1:00 -01 1945 Oct 15 - -2:00 - -02 1975 Nov 25 2:00 - -1:00 - -01 + -2:00 - %z 1942 Sep + -2:00 1:00 %z 1945 Oct 15 + -2:00 - %z 1975 Nov 25 2:00 + -1:00 - %z # Chad # Zone NAME STDOFF RULES FORMAT [UNTIL] @@ -368,14 +367,12 @@ Zone Africa/Cairo 2:05:09 - LMT 1900 Oct # Guinea-Bissau # -# From Paul Eggert (2018-02-16): -# Shanks gives 1911-05-26 for the transition to WAT, -# evidently confusing the date of the Portuguese decree -# (see Europe/Lisbon) with the date that it took effect. +# From Tim Parenti (2024-07-01), per Paul Eggert (2018-02-16): +# For timestamps before independence, see commentary for Europe/Lisbon. # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Bissau -1:02:20 - LMT 1912 Jan 1 1:00u - -1:00 - -01 1975 + -1:00 - %z 1975 0:00 - GMT # Comoros @@ -440,10 +437,10 @@ Zone Africa/Bissau -1:02:20 - LMT 1912 Jan 1 1:00u # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Nairobi 2:27:16 - LMT 1908 May - 2:30 - +0230 1928 Jun 30 24:00 + 2:30 - %z 1928 Jun 30 24:00 3:00 - EAT 1930 Jan 4 24:00 - 2:30 - +0230 1936 Dec 31 24:00 - 2:45 - +0245 1942 Jul 31 24:00 + 2:30 - %z 1936 Dec 31 24:00 + 2:45 - %z 1942 Jul 31 24:00 3:00 - EAT # Liberia @@ -614,7 +611,7 @@ Rule Mauritius 2008 only - Oct lastSun 2:00 1:00 - Rule Mauritius 2009 only - Mar lastSun 2:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis - 4:00 Mauritius +04/+05 + 4:00 Mauritius %z # Agalega Is, Rodriguez # no information; probably like Indian/Mauritius @@ -1094,10 +1091,10 @@ Rule Morocco 2087 only - May 11 2:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26 - 0:00 Morocco +00/+01 1984 Mar 16 - 1:00 - +01 1986 - 0:00 Morocco +00/+01 2018 Oct 28 3:00 - 1:00 Morocco +01/+00 + 0:00 Morocco %z 1984 Mar 16 + 1:00 - %z 1986 + 0:00 Morocco %z 2018 Oct 28 3:00 + 1:00 Morocco %z # Western Sahara # @@ -1111,9 +1108,9 @@ Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26 # since most of it was then controlled by Morocco. Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún - -1:00 - -01 1976 Apr 14 - 0:00 Morocco +00/+01 2018 Oct 28 3:00 - 1:00 Morocco +01/+00 + -1:00 - %z 1976 Apr 14 + 0:00 Morocco %z 2018 Oct 28 3:00 + 1:00 Morocco %z # Botswana # Burundi @@ -1124,13 +1121,27 @@ Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún # Zambia # Zimbabwe # -# Shanks gives 1903-03-01 for the transition to CAT. -# Perhaps the 1911-05-26 Portuguese decree -# https://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf -# merely made it official? +# From Tim Parenti (2024-07-01): +# For timestamps before Mozambique's independence, see commentary for +# Europe/Lisbon. +# +# From Paul Eggert (2024-05-24): +# The London Gazette, 1903-04-03, page 2245, says that +# as of 1903-03-03 a time ball at the port of Lourenço Marques +# (as Maputo was then called) was dropped daily at 13:00:00 LMT, +# corresponding to 22:49:41.7 GMT, so local time was +02:10:18.3. +# Conversely, the newspaper South Africa, 1909-02-09, page 321, +# says the port had just installed an apparatus that communicated +# "from the controlling clock in the new Observatory at Reuben Point ... +# exact mean South African time, i.e., 30 deg., or 2 hours East of Greenwich". +# Although Shanks gives 1903-03-01 for the transition to CAT, +# evidently the port transitioned to CAT after 1903-03-03 but before +# the Portuguese legal transition of 1912-01-01 (see Europe/Lisbon commentary). +# For lack of better info, list 1909 as the transition date. # # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Africa/Maputo 2:10:20 - LMT 1903 Mar + #STDOFF 2:10:18.3 +Zone Africa/Maputo 2:10:18 - LMT 1909 2:00 - CAT # Namibia @@ -1195,7 +1206,7 @@ Rule Namibia 1995 2017 - Apr Sun>=1 2:00 -1:00 WAT # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8 - 1:30 - +0130 1903 Mar + 1:30 - %z 1903 Mar 2:00 - SAST 1942 Sep 20 2:00 2:00 1:00 SAST 1943 Mar 21 2:00 2:00 - SAST 1990 Mar 21 # independence @@ -1283,7 +1294,7 @@ Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8 Zone Africa/Lagos 0:13:35 - LMT 1905 Jul 1 0:00 - GMT 1908 Jul 1 0:13:35 - LMT 1914 Jan 1 - 0:30 - +0030 1919 Sep 1 + 0:30 - %z 1919 Sep 1 1:00 - WAT # São Tomé and Príncipe diff --git a/src/java.base/share/data/tzdata/antarctica b/src/java.base/share/data/tzdata/antarctica index fc7176cd0d57a..058d8d6a7a28b 100644 --- a/src/java.base/share/data/tzdata/antarctica +++ b/src/java.base/share/data/tzdata/antarctica @@ -110,34 +110,34 @@ # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Casey 0 - -00 1969 - 8:00 - +08 2009 Oct 18 2:00 - 11:00 - +11 2010 Mar 5 2:00 - 8:00 - +08 2011 Oct 28 2:00 - 11:00 - +11 2012 Feb 21 17:00u - 8:00 - +08 2016 Oct 22 - 11:00 - +11 2018 Mar 11 4:00 - 8:00 - +08 2018 Oct 7 4:00 - 11:00 - +11 2019 Mar 17 3:00 - 8:00 - +08 2019 Oct 4 3:00 - 11:00 - +11 2020 Mar 8 3:00 - 8:00 - +08 2020 Oct 4 0:01 - 11:00 - +11 2021 Mar 14 0:00 - 8:00 - +08 2021 Oct 3 0:01 - 11:00 - +11 2022 Mar 13 0:00 - 8:00 - +08 2022 Oct 2 0:01 - 11:00 - +11 2023 Mar 9 3:00 - 8:00 - +08 + 8:00 - %z 2009 Oct 18 2:00 + 11:00 - %z 2010 Mar 5 2:00 + 8:00 - %z 2011 Oct 28 2:00 + 11:00 - %z 2012 Feb 21 17:00u + 8:00 - %z 2016 Oct 22 + 11:00 - %z 2018 Mar 11 4:00 + 8:00 - %z 2018 Oct 7 4:00 + 11:00 - %z 2019 Mar 17 3:00 + 8:00 - %z 2019 Oct 4 3:00 + 11:00 - %z 2020 Mar 8 3:00 + 8:00 - %z 2020 Oct 4 0:01 + 11:00 - %z 2021 Mar 14 0:00 + 8:00 - %z 2021 Oct 3 0:01 + 11:00 - %z 2022 Mar 13 0:00 + 8:00 - %z 2022 Oct 2 0:01 + 11:00 - %z 2023 Mar 9 3:00 + 8:00 - %z Zone Antarctica/Davis 0 - -00 1957 Jan 13 - 7:00 - +07 1964 Nov + 7:00 - %z 1964 Nov 0 - -00 1969 Feb - 7:00 - +07 2009 Oct 18 2:00 - 5:00 - +05 2010 Mar 10 20:00u - 7:00 - +07 2011 Oct 28 2:00 - 5:00 - +05 2012 Feb 21 20:00u - 7:00 - +07 + 7:00 - %z 2009 Oct 18 2:00 + 5:00 - %z 2010 Mar 10 20:00u + 7:00 - %z 2011 Oct 28 2:00 + 5:00 - %z 2012 Feb 21 20:00u + 7:00 - %z Zone Antarctica/Mawson 0 - -00 1954 Feb 13 - 6:00 - +06 2009 Oct 18 2:00 - 5:00 - +05 + 6:00 - %z 2009 Oct 18 2:00 + 5:00 - %z # References: # Casey Weather (1998-02-26) # http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html @@ -313,10 +313,10 @@ Zone Antarctica/Troll 0 - -00 2005 Feb 12 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Vostok 0 - -00 1957 Dec 16 - 7:00 - +07 1994 Feb + 7:00 - %z 1994 Feb 0 - -00 1994 Nov - 7:00 - +07 2023 Dec 18 2:00 - 5:00 - +05 + 7:00 - %z 2023 Dec 18 2:00 + 5:00 - %z # S Africa - year-round bases # Marion Island, -4653+03752 @@ -349,7 +349,7 @@ Zone Antarctica/Vostok 0 - -00 1957 Dec 16 # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Rothera 0 - -00 1976 Dec 1 - -3:00 - -03 + -3:00 - %z # Uruguay - year round base # Artigas, King George Island, -621104-0585107 diff --git a/src/java.base/share/data/tzdata/asia b/src/java.base/share/data/tzdata/asia index 3a54291919d60..5c8568f334aee 100644 --- a/src/java.base/share/data/tzdata/asia +++ b/src/java.base/share/data/tzdata/asia @@ -106,8 +106,8 @@ Rule RussiaAsia 1996 2010 - Oct lastSun 2:00s 0 - # Afghanistan # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Kabul 4:36:48 - LMT 1890 - 4:00 - +04 1945 - 4:30 - +0430 + 4:00 - %z 1945 + 4:30 - %z # Armenia # From Paul Eggert (2006-03-22): @@ -139,12 +139,12 @@ Rule Armenia 2011 only - Mar lastSun 2:00s 1:00 - Rule Armenia 2011 only - Oct lastSun 2:00s 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Yerevan 2:58:00 - LMT 1924 May 2 - 3:00 - +03 1957 Mar - 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s - 3:00 RussiaAsia +03/+04 1995 Sep 24 2:00s - 4:00 - +04 1997 - 4:00 RussiaAsia +04/+05 2011 - 4:00 Armenia +04/+05 + 3:00 - %z 1957 Mar + 4:00 RussiaAsia %z 1991 Mar 31 2:00s + 3:00 RussiaAsia %z 1995 Sep 24 2:00s + 4:00 - %z 1997 + 4:00 RussiaAsia %z 2011 + 4:00 Armenia %z # Azerbaijan @@ -165,12 +165,12 @@ Rule Azer 1997 2015 - Mar lastSun 4:00 1:00 - Rule Azer 1997 2015 - Oct lastSun 5:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Baku 3:19:24 - LMT 1924 May 2 - 3:00 - +03 1957 Mar - 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s - 3:00 RussiaAsia +03/+04 1992 Sep lastSun 2:00s - 4:00 - +04 1996 - 4:00 EUAsia +04/+05 1997 - 4:00 Azer +04/+05 + 3:00 - %z 1957 Mar + 4:00 RussiaAsia %z 1991 Mar 31 2:00s + 3:00 RussiaAsia %z 1992 Sep lastSun 2:00s + 4:00 - %z 1996 + 4:00 EUAsia %z 1997 + 4:00 Azer %z # Bangladesh # From Alexander Krivenyshev (2009-05-13): @@ -251,17 +251,17 @@ Rule Dhaka 2009 only - Dec 31 24:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Dhaka 6:01:40 - LMT 1890 5:53:20 - HMT 1941 Oct # Howrah Mean Time? - 6:30 - +0630 1942 May 15 - 5:30 - +0530 1942 Sep - 6:30 - +0630 1951 Sep 30 - 6:00 - +06 2009 - 6:00 Dhaka +06/+07 + 6:30 - %z 1942 May 15 + 5:30 - %z 1942 Sep + 6:30 - %z 1951 Sep 30 + 6:00 - %z 2009 + 6:00 Dhaka %z # Bhutan # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Thimphu 5:58:36 - LMT 1947 Aug 15 # or Thimbu - 5:30 - +0530 1987 Oct - 6:00 - +06 + 5:30 - %z 1987 Oct + 6:00 - %z # British Indian Ocean Territory # Whitman and the 1995 CIA time zone map say 5:00, but the @@ -271,8 +271,8 @@ Zone Asia/Thimphu 5:58:36 - LMT 1947 Aug 15 # or Thimbu # then contained the Chagos Archipelago). # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Indian/Chagos 4:49:40 - LMT 1907 - 5:00 - +05 1996 - 6:00 - +06 + 5:00 - %z 1996 + 6:00 - %z # Cocos (Keeling) Islands # Myanmar (Burma) @@ -288,9 +288,9 @@ Zone Indian/Chagos 4:49:40 - LMT 1907 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Yangon 6:24:47 - LMT 1880 # or Rangoon 6:24:47 - RMT 1920 # Rangoon local time - 6:30 - +0630 1942 May - 9:00 - +09 1945 May 3 - 6:30 - +0630 + 6:30 - %z 1942 May + 9:00 - %z 1945 May 3 + 6:30 - %z # China @@ -679,7 +679,7 @@ Zone Asia/Shanghai 8:05:43 - LMT 1901 # Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi # / Wulumuqi. (Please use Asia/Shanghai if you prefer Beijing time.) Zone Asia/Urumqi 5:50:20 - LMT 1928 - 6:00 - +06 + 6:00 - %z # Hong Kong @@ -1137,7 +1137,7 @@ Rule Macau 1979 only - Oct Sun>=16 03:30 0 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Macau 7:34:10 - LMT 1904 Oct 30 8:00 - CST 1941 Dec 21 23:00 - 9:00 Macau +09/+10 1945 Sep 30 24:00 + 9:00 Macau %z 1945 Sep 30 24:00 8:00 Macau C%sT @@ -1180,7 +1180,7 @@ Zone Asia/Nicosia 2:13:28 - LMT 1921 Nov 14 Zone Asia/Famagusta 2:15:48 - LMT 1921 Nov 14 2:00 Cyprus EE%sT 1998 Sep 2:00 EUAsia EE%sT 2016 Sep 8 - 3:00 - +03 2017 Oct 29 1:00u + 3:00 - %z 2017 Oct 29 1:00u 2:00 EUAsia EE%sT # Georgia @@ -1221,18 +1221,25 @@ Zone Asia/Famagusta 2:15:48 - LMT 1921 Nov 14 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Tbilisi 2:59:11 - LMT 1880 2:59:11 - TBMT 1924 May 2 # Tbilisi Mean Time - 3:00 - +03 1957 Mar - 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s - 3:00 RussiaAsia +03/+04 1992 - 3:00 E-EurAsia +03/+04 1994 Sep lastSun - 4:00 E-EurAsia +04/+05 1996 Oct lastSun - 4:00 1:00 +05 1997 Mar lastSun - 4:00 E-EurAsia +04/+05 2004 Jun 27 - 3:00 RussiaAsia +03/+04 2005 Mar lastSun 2:00 - 4:00 - +04 + 3:00 - %z 1957 Mar + 4:00 RussiaAsia %z 1991 Mar 31 2:00s + 3:00 RussiaAsia %z 1992 + 3:00 E-EurAsia %z 1994 Sep lastSun + 4:00 E-EurAsia %z 1996 Oct lastSun + 4:00 1:00 %z 1997 Mar lastSun + 4:00 E-EurAsia %z 2004 Jun 27 + 3:00 RussiaAsia %z 2005 Mar lastSun 2:00 + 4:00 - %z # East Timor +# From Tim Parenti (2024-07-01): +# The 1912-01-01 transition occurred at 00:00 new time, per the 1911-05-24 +# Portuguese decree (see Europe/Lisbon). A provision in article 5(c) of the +# decree prescribed that Timor "will keep counting time in harmony with +# neighboring foreign colonies, [for] as long as they do not adopt the time +# that belongs to them in [the Washington Convention] system." + # See Indonesia for the 1945 transition. # From João Carrascalão, brother of the former governor of East Timor, in @@ -1256,11 +1263,11 @@ Zone Asia/Tbilisi 2:59:11 - LMT 1880 # midnight on Saturday, September 16. # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Asia/Dili 8:22:20 - LMT 1912 Jan 1 - 8:00 - +08 1942 Feb 21 23:00 - 9:00 - +09 1976 May 3 - 8:00 - +08 2000 Sep 17 0:00 - 9:00 - +09 +Zone Asia/Dili 8:22:20 - LMT 1911 Dec 31 16:00u + 8:00 - %z 1942 Feb 21 23:00 + 9:00 - %z 1976 May 3 + 8:00 - %z 2000 Sep 17 0:00 + 9:00 - %z # India @@ -1326,9 +1333,9 @@ Zone Asia/Kolkata 5:53:28 - LMT 1854 Jun 28 # Kolkata 5:53:20 - HMT 1870 # Howrah Mean Time? 5:21:10 - MMT 1906 Jan 1 # Madras local time 5:30 - IST 1941 Oct - 5:30 1:00 +0630 1942 May 15 + 5:30 1:00 %z 1942 May 15 5:30 - IST 1942 Sep - 5:30 1:00 +0630 1945 Oct 15 + 5:30 1:00 %z 1945 Oct 15 5:30 - IST # Since 1970 the following are like Asia/Kolkata: # Andaman Is @@ -1380,33 +1387,33 @@ Zone Asia/Jakarta 7:07:12 - LMT 1867 Aug 10 # Shanks & Pottenger say the next transition was at 1924 Jan 1 0:13, # but this must be a typo. 7:07:12 - BMT 1923 Dec 31 16:40u # Batavia - 7:20 - +0720 1932 Nov - 7:30 - +0730 1942 Mar 23 - 9:00 - +09 1945 Sep 23 - 7:30 - +0730 1948 May - 8:00 - +08 1950 May - 7:30 - +0730 1964 + 7:20 - %z 1932 Nov + 7:30 - %z 1942 Mar 23 + 9:00 - %z 1945 Sep 23 + 7:30 - %z 1948 May + 8:00 - %z 1950 May + 7:30 - %z 1964 7:00 - WIB # west and central Borneo Zone Asia/Pontianak 7:17:20 - LMT 1908 May 7:17:20 - PMT 1932 Nov # Pontianak MT - 7:30 - +0730 1942 Jan 29 - 9:00 - +09 1945 Sep 23 - 7:30 - +0730 1948 May - 8:00 - +08 1950 May - 7:30 - +0730 1964 + 7:30 - %z 1942 Jan 29 + 9:00 - %z 1945 Sep 23 + 7:30 - %z 1948 May + 8:00 - %z 1950 May + 7:30 - %z 1964 8:00 - WITA 1988 Jan 1 7:00 - WIB # Sulawesi, Lesser Sundas, east and south Borneo Zone Asia/Makassar 7:57:36 - LMT 1920 7:57:36 - MMT 1932 Nov # Macassar MT - 8:00 - +08 1942 Feb 9 - 9:00 - +09 1945 Sep 23 + 8:00 - %z 1942 Feb 9 + 9:00 - %z 1945 Sep 23 8:00 - WITA # Maluku Islands, West Papua, Papua Zone Asia/Jayapura 9:22:48 - LMT 1932 Nov - 9:00 - +09 1944 Sep 1 - 9:30 - +0930 1964 + 9:00 - %z 1944 Sep 1 + 9:30 - %z 1964 9:00 - WIT # Iran @@ -1642,9 +1649,9 @@ Rule Iran 2021 2022 - Sep 21 24:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Tehran 3:25:44 - LMT 1916 3:25:44 - TMT 1935 Jun 13 # Tehran Mean Time - 3:30 Iran +0330/+0430 1977 Oct 20 24:00 - 4:00 Iran +04/+05 1979 - 3:30 Iran +0330/+0430 + 3:30 Iran %z 1977 Oct 20 24:00 + 4:00 Iran %z 1979 + 3:30 Iran %z # Iraq @@ -1687,8 +1694,8 @@ Rule Iraq 1991 2007 - Oct 1 3:00s 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Baghdad 2:57:40 - LMT 1890 2:57:36 - BMT 1918 # Baghdad Mean Time? - 3:00 - +03 1982 May - 3:00 Iraq +03/+04 + 3:00 - %z 1982 May + 3:00 Iraq %z ############################################################################### @@ -2285,7 +2292,7 @@ Rule Jordan 2022 only - Feb lastThu 24:00 1:00 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Amman 2:23:44 - LMT 1931 2:00 Jordan EE%sT 2022 Oct 28 0:00s - 3:00 - +03 + 3:00 - %z # Kazakhstan @@ -2496,88 +2503,88 @@ Zone Asia/Amman 2:23:44 - LMT 1931 # Almaty (formerly Alma-Ata), representing most locations in Kazakhstan # This includes Abai/Abay (ISO 3166-2 code KZ-10), Aqmola/Akmola (KZ-11), # Almaty (KZ-19), Almaty city (KZ-75), Astana city (KZ-71), -# East Kazkhstan (KZ-63), Jambyl/Zhambyl (KZ-31), Jetisu/Zhetysu (KZ-33), +# East Kazakhstan (KZ-63), Jambyl/Zhambyl (KZ-31), Jetisu/Zhetysu (KZ-33), # Karaganda (KZ-35), North Kazakhstan (KZ-59), Pavlodar (KZ-55), -# Shyumkent city (KZ-79), Turkistan (KZ-61), and Ulytau (KZ-62). +# Shymkent city (KZ-79), Turkistan (KZ-61), and Ulytau (KZ-62). Zone Asia/Almaty 5:07:48 - LMT 1924 May 2 # or Alma-Ata - 5:00 - +05 1930 Jun 21 - 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s - 5:00 RussiaAsia +05/+06 1992 Jan 19 2:00s - 6:00 RussiaAsia +06/+07 2004 Oct 31 2:00s - 6:00 - +06 2024 Mar 1 0:00 - 5:00 - +05 + 5:00 - %z 1930 Jun 21 + 6:00 RussiaAsia %z 1991 Mar 31 2:00s + 5:00 RussiaAsia %z 1992 Jan 19 2:00s + 6:00 RussiaAsia %z 2004 Oct 31 2:00s + 6:00 - %z 2024 Mar 1 0:00 + 5:00 - %z # Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.) (KZ-43) Zone Asia/Qyzylorda 4:21:52 - LMT 1924 May 2 - 4:00 - +04 1930 Jun 21 - 5:00 - +05 1981 Apr 1 - 5:00 1:00 +06 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s - 4:00 RussiaAsia +04/+05 1991 Sep 29 2:00s - 5:00 RussiaAsia +05/+06 1992 Jan 19 2:00s - 6:00 RussiaAsia +06/+07 1992 Mar 29 2:00s - 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s - 6:00 - +06 2018 Dec 21 0:00 - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Apr 1 + 5:00 1:00 %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1991 Mar 31 2:00s + 4:00 RussiaAsia %z 1991 Sep 29 2:00s + 5:00 RussiaAsia %z 1992 Jan 19 2:00s + 6:00 RussiaAsia %z 1992 Mar 29 2:00s + 5:00 RussiaAsia %z 2004 Oct 31 2:00s + 6:00 - %z 2018 Dec 21 0:00 + 5:00 - %z # Qostanay (aka Kostanay, Kustanay) (KZ-39) # The 1991/2 rules are unclear partly because of the 1997 Turgai # reorganization. Zone Asia/Qostanay 4:14:28 - LMT 1924 May 2 - 4:00 - +04 1930 Jun 21 - 5:00 - +05 1981 Apr 1 - 5:00 1:00 +06 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s - 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s - 6:00 - +06 2024 Mar 1 0:00 - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Apr 1 + 5:00 1:00 %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1991 Mar 31 2:00s + 4:00 RussiaAsia %z 1992 Jan 19 2:00s + 5:00 RussiaAsia %z 2004 Oct 31 2:00s + 6:00 - %z 2024 Mar 1 0:00 + 5:00 - %z # Aqtöbe (aka Aktobe, formerly Aktyubinsk) (KZ-15) Zone Asia/Aqtobe 3:48:40 - LMT 1924 May 2 - 4:00 - +04 1930 Jun 21 - 5:00 - +05 1981 Apr 1 - 5:00 1:00 +06 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s - 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Apr 1 + 5:00 1:00 %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1991 Mar 31 2:00s + 4:00 RussiaAsia %z 1992 Jan 19 2:00s + 5:00 RussiaAsia %z 2004 Oct 31 2:00s + 5:00 - %z # Mangghystaū (KZ-47) # Aqtau was not founded until 1963, but it represents an inhabited region, # so include timestamps before 1963. Zone Asia/Aqtau 3:21:04 - LMT 1924 May 2 - 4:00 - +04 1930 Jun 21 - 5:00 - +05 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s - 5:00 RussiaAsia +05/+06 1994 Sep 25 2:00s - 4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1991 Mar 31 2:00s + 4:00 RussiaAsia %z 1992 Jan 19 2:00s + 5:00 RussiaAsia %z 1994 Sep 25 2:00s + 4:00 RussiaAsia %z 2004 Oct 31 2:00s + 5:00 - %z # Atyraū (KZ-23) is like Mangghystaū except it switched from # +04/+05 to +05/+06 in spring 1999, not fall 1994. Zone Asia/Atyrau 3:27:44 - LMT 1924 May 2 - 3:00 - +03 1930 Jun 21 - 5:00 - +05 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s - 5:00 RussiaAsia +05/+06 1999 Mar 28 2:00s - 4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s - 5:00 - +05 + 3:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1991 Mar 31 2:00s + 4:00 RussiaAsia %z 1992 Jan 19 2:00s + 5:00 RussiaAsia %z 1999 Mar 28 2:00s + 4:00 RussiaAsia %z 2004 Oct 31 2:00s + 5:00 - %z # West Kazakhstan (KZ-27) # From Paul Eggert (2016-03-18): # The 1989 transition is from USSR act No. 227 (1989-03-14). Zone Asia/Oral 3:25:24 - LMT 1924 May 2 # or Ural'sk - 3:00 - +03 1930 Jun 21 - 5:00 - +05 1981 Apr 1 - 5:00 1:00 +06 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1989 Mar 26 2:00s - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s - 5:00 RussiaAsia +05/+06 1992 Mar 29 2:00s - 4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s - 5:00 - +05 + 3:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Apr 1 + 5:00 1:00 %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1989 Mar 26 2:00s + 4:00 RussiaAsia %z 1992 Jan 19 2:00s + 5:00 RussiaAsia %z 1992 Mar 29 2:00s + 4:00 RussiaAsia %z 2004 Oct 31 2:00s + 5:00 - %z # Kyrgyzstan (Kirgizstan) # Transitions through 1991 are from Shanks & Pottenger. @@ -2598,11 +2605,11 @@ Rule Kyrgyz 1997 2005 - Mar lastSun 2:30 1:00 - Rule Kyrgyz 1997 2004 - Oct lastSun 2:30 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Bishkek 4:58:24 - LMT 1924 May 2 - 5:00 - +05 1930 Jun 21 - 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s - 5:00 RussiaAsia +05/+06 1991 Aug 31 2:00 - 5:00 Kyrgyz +05/+06 2005 Aug 12 - 6:00 - +06 + 5:00 - %z 1930 Jun 21 + 6:00 RussiaAsia %z 1991 Mar 31 2:00s + 5:00 RussiaAsia %z 1991 Aug 31 2:00 + 5:00 Kyrgyz %z 2005 Aug 12 + 6:00 - %z ############################################################################### @@ -2809,16 +2816,16 @@ Rule NBorneo 1935 1941 - Dec 14 0:00 0 - # and 1982 transition dates are from Mok Ly Yng. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Kuching 7:21:20 - LMT 1926 Mar - 7:30 - +0730 1933 - 8:00 NBorneo +08/+0820 1942 Feb 16 - 9:00 - +09 1945 Sep 12 - 8:00 - +08 + 7:30 - %z 1933 + 8:00 NBorneo %z 1942 Feb 16 + 9:00 - %z 1945 Sep 12 + 8:00 - %z # Maldives # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Indian/Maldives 4:54:00 - LMT 1880 # Malé 4:54:00 - MMT 1960 # Malé Mean Time - 5:00 - +05 + 5:00 - %z # Mongolia @@ -2920,9 +2927,37 @@ Zone Indian/Maldives 4:54:00 - LMT 1880 # Malé # From Arthur David Olson (2008-05-19): # Assume that Choibalsan is indeed offset by 8:00. -# XXX--in the absence of better information, assume that transition -# was at the start of 2008-03-31 (the day of Steffen Thorsen's report); -# this is almost surely wrong. + +# From Heitor David Pinto (2024-06-23): +# Sources about time zones in Mongolia seem to list one of two conflicting +# configurations. The first configuration, mentioned in a comment to the TZ +# database in 1999, citing a Mongolian government website, lists the provinces +# of Bayan-Ölgii, Khovd and Uvs in UTC+7, and the rest of the country in +# UTC+8. The second configuration, mentioned in a comment to the database in +# 2001, lists Bayan-Ölgii, Khovd, Uvs, Govi-Altai and Zavkhan in UTC+7, Dornod +# and Sükhbaatar in UTC+9, and the rest of the country in UTC+8. +# +# The first configuration is still mentioned by several Mongolian travel +# agencies: +# https://www.adventurerider.mn/en/page/about_mongolia +# http://www.naturetours.mn/nt/mongolia.php +# https://www.newjuulchin.mn/web/content/7506?unique=fa24a0f6e96e022a3578ee5195ac879638c734ce +# +# It also matches these flight schedules in 2013: +# http://web.archive.org/web/20130722023600/https://www.hunnuair.com/en/timetabled +# The flight times imply that the airports of Uliastai (Zavkhan), Choibalsan +# (Dornod) and Altai (Govi-Altai) are in the same time zone as Ulaanbaatar, +# and Khovd is one hour behind.... +# +# The second configuration was mentioned by an official of the Mongolian +# standards agency in an interview in 2014: https://ikon.mn/n/9v6 +# And it's still listed by the Mongolian aviation agency: +# https://ais.mn/files/aip/eAIP/2023-12-25/html/eSUP/ZM-eSUP-23-04-en-MN.html +# +# ... I believe that the first configuration is what is actually observed in +# Mongolia and has been so all along, at least since 1999. The second +# configuration closely matches the ideal time zone boundaries at 97.5° E and +# 112.5° E but it doesn't seem to be used in practice. # From Ganbold Tsagaankhuu (2015-03-10): # It seems like yesterday Mongolian Government meeting has concluded to use @@ -2961,25 +2996,18 @@ Rule Mongol 2015 2016 - Sep lastSat 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] # Hovd, a.k.a. Chovd, Dund-Us, Dzhargalant, Khovd, Jirgalanta Zone Asia/Hovd 6:06:36 - LMT 1905 Aug - 6:00 - +06 1978 - 7:00 Mongol +07/+08 + 6:00 - %z 1978 + 7:00 Mongol %z # Ulaanbaatar, a.k.a. Ulan Bataar, Ulan Bator, Urga Zone Asia/Ulaanbaatar 7:07:32 - LMT 1905 Aug - 7:00 - +07 1978 - 8:00 Mongol +08/+09 -# Choibalsan, a.k.a. Bajan Tümen, Bajan Tumen, Chojbalsan, -# Choybalsan, Sanbejse, Tchoibalsan -Zone Asia/Choibalsan 7:38:00 - LMT 1905 Aug - 7:00 - +07 1978 - 8:00 - +08 1983 Apr - 9:00 Mongol +09/+10 2008 Mar 31 - 8:00 Mongol +08/+09 + 7:00 - %z 1978 + 8:00 Mongol %z # Nepal # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Kathmandu 5:41:16 - LMT 1920 - 5:30 - +0530 1986 - 5:45 - +0545 + 5:30 - %z 1986 + 5:45 - %z # Pakistan @@ -3125,10 +3153,10 @@ Rule Pakistan 2009 only - Apr 15 0:00 1:00 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Karachi 4:28:12 - LMT 1907 - 5:30 - +0530 1942 Sep - 5:30 1:00 +0630 1945 Oct 15 - 5:30 - +0530 1951 Sep 30 - 5:00 - +05 1971 Mar 26 + 5:30 - %z 1942 Sep + 5:30 1:00 %z 1945 Oct 15 + 5:30 - %z 1951 Sep 30 + 5:00 - %z 1971 Mar 26 5:00 Pakistan PK%sT # Pakistan Time # Palestine @@ -3676,14 +3704,14 @@ Zone Asia/Hebron 2:20:23 - LMT 1900 Oct # Philippine Star 2014-08-05 # http://www.philstar.com/headlines/2014/08/05/1354152/pnoy-urged-declare-use-daylight-saving-time -# From Paul Goyette (2018-06-15): +# From Paul Goyette (2018-06-15) with URLs updated by Guy Harris (2024-02-15): # In the Philippines, there is a national law, Republic Act No. 10535 # which declares the official time here as "Philippine Standard Time". # The act [1] even specifies use of PST as the abbreviation, although # the FAQ provided by PAGASA [2] uses the "acronym PhST to distinguish # it from the Pacific Standard Time (PST)." -# [1] http://www.officialgazette.gov.ph/2013/05/15/republic-act-no-10535/ -# [2] https://www1.pagasa.dost.gov.ph/index.php/astronomy/philippine-standard-time#republic-act-10535 +# [1] https://www.officialgazette.gov.ph/2013/05/15/republic-act-no-10535/ +# [2] https://prsd.pagasa.dost.gov.ph/index.php/28-astronomy/302-philippine-standard-time # # From Paul Eggert (2018-06-19): # I surveyed recent news reports, and my impression is that "PST" is @@ -3716,8 +3744,8 @@ Zone Asia/Manila -15:56:00 - LMT 1844 Dec 31 # Qatar # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Qatar 3:26:08 - LMT 1920 # Al Dawhah / Doha - 4:00 - +04 1972 Jun - 3:00 - +03 + 4:00 - %z 1972 Jun + 3:00 - %z # Kuwait # Saudi Arabia @@ -3767,7 +3795,7 @@ Zone Asia/Qatar 3:26:08 - LMT 1920 # Al Dawhah / Doha # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Riyadh 3:06:52 - LMT 1947 Mar 14 - 3:00 - +03 + 3:00 - %z # Singapore # taken from Mok Ly Yng (2003-10-30) @@ -3775,13 +3803,13 @@ Zone Asia/Riyadh 3:06:52 - LMT 1947 Mar 14 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 6:55:25 - SMT 1905 Jun 1 # Singapore M.T. - 7:00 - +07 1933 Jan 1 - 7:00 0:20 +0720 1936 Jan 1 - 7:20 - +0720 1941 Sep 1 - 7:30 - +0730 1942 Feb 16 - 9:00 - +09 1945 Sep 12 - 7:30 - +0730 1981 Dec 31 16:00u - 8:00 - +08 + 7:00 - %z 1933 Jan 1 + 7:00 0:20 %z 1936 Jan 1 + 7:20 - %z 1941 Sep 1 + 7:30 - %z 1942 Feb 16 + 9:00 - %z 1945 Sep 12 + 7:30 - %z 1981 Dec 31 16:00u + 8:00 - %z # Spratly Is # no information @@ -3839,13 +3867,13 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Colombo 5:19:24 - LMT 1880 5:19:32 - MMT 1906 # Moratuwa Mean Time - 5:30 - +0530 1942 Jan 5 - 5:30 0:30 +06 1942 Sep - 5:30 1:00 +0630 1945 Oct 16 2:00 - 5:30 - +0530 1996 May 25 0:00 - 6:30 - +0630 1996 Oct 26 0:30 - 6:00 - +06 2006 Apr 15 0:30 - 5:30 - +0530 + 5:30 - %z 1942 Jan 5 + 5:30 0:30 %z 1942 Sep + 5:30 1:00 %z 1945 Oct 16 2:00 + 5:30 - %z 1996 May 25 0:00 + 6:30 - %z 1996 Oct 26 0:30 + 6:00 - %z 2006 Apr 15 0:30 + 5:30 - %z # Syria # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -4016,16 +4044,16 @@ Rule Syria 2009 2022 - Oct lastFri 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Damascus 2:25:12 - LMT 1920 # Dimashq 2:00 Syria EE%sT 2022 Oct 28 0:00 - 3:00 - +03 + 3:00 - %z # Tajikistan # From Shanks & Pottenger. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2 - 5:00 - +05 1930 Jun 21 - 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s - 5:00 1:00 +06 1991 Sep 9 2:00s - 5:00 - +05 + 5:00 - %z 1930 Jun 21 + 6:00 RussiaAsia %z 1991 Mar 31 2:00s + 5:00 1:00 %z 1991 Sep 9 2:00s + 5:00 - %z # Cambodia # Christmas I @@ -4035,16 +4063,16 @@ Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Bangkok 6:42:04 - LMT 1880 6:42:04 - BMT 1920 Apr # Bangkok Mean Time - 7:00 - +07 + 7:00 - %z # Turkmenistan # From Shanks & Pottenger. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad - 4:00 - +04 1930 Jun 21 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00 - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00 - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 RussiaAsia %z 1991 Mar 31 2:00 + 4:00 RussiaAsia %z 1992 Jan 19 2:00 + 5:00 - %z # Oman # Réunion @@ -4054,25 +4082,25 @@ Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad # The Crozet Is also observe Réunion time; see the 'antarctica' file. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Dubai 3:41:12 - LMT 1920 - 4:00 - +04 + 4:00 - %z # Uzbekistan # Byalokoz 1919 says Uzbekistan was 4:27:53. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Samarkand 4:27:53 - LMT 1924 May 2 - 4:00 - +04 1930 Jun 21 - 5:00 - +05 1981 Apr 1 - 5:00 1:00 +06 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1992 - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Apr 1 + 5:00 1:00 %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1992 + 5:00 - %z # Milne says Tashkent was 4:37:10.8. #STDOFF 4:37:10.8 Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 - 5:00 - +05 1930 Jun 21 - 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00 - 5:00 RussiaAsia +05/+06 1992 - 5:00 - +05 + 5:00 - %z 1930 Jun 21 + 6:00 RussiaAsia %z 1991 Mar 31 2:00 + 5:00 RussiaAsia %z 1992 + 5:00 - %z # Vietnam (southern) @@ -4130,7 +4158,7 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 # Võ Nguyên Giáp, Việt Nam Dân Quốc Công Báo, No. 1 (1945-09-29), page 13 # http://baochi.nlv.gov.vn/baochi/cgi-bin/baochi?a=d&d=JwvzO19450929.2.5&dliv=none # It says that on 1945-09-01 at 24:00, Vietnam moved back two hours, to +07. -# It also mentions a 1945-03-29 decree (by a Japanese Goveror-General) +# It also mentions a 1945-03-29 decree (by a Japanese Governor-General) # to set the time zone to +09, but does not say whether that decree # merely legalized an earlier change to +09. # @@ -4151,14 +4179,14 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 #STDOFF 7:06:30.13 Zone Asia/Ho_Chi_Minh 7:06:30 - LMT 1906 Jul 1 7:06:30 - PLMT 1911 May 1 # Phù Liễn MT - 7:00 - +07 1942 Dec 31 23:00 - 8:00 - +08 1945 Mar 14 23:00 - 9:00 - +09 1945 Sep 1 24:00 - 7:00 - +07 1947 Apr 1 - 8:00 - +08 1955 Jul 1 01:00 - 7:00 - +07 1959 Dec 31 23:00 - 8:00 - +08 1975 Jun 13 - 7:00 - +07 + 7:00 - %z 1942 Dec 31 23:00 + 8:00 - %z 1945 Mar 14 23:00 + 9:00 - %z 1945 Sep 1 24:00 + 7:00 - %z 1947 Apr 1 + 8:00 - %z 1955 Jul 1 01:00 + 7:00 - %z 1959 Dec 31 23:00 + 8:00 - %z 1975 Jun 13 + 7:00 - %z # From Paul Eggert (2019-02-19): # diff --git a/src/java.base/share/data/tzdata/australasia b/src/java.base/share/data/tzdata/australasia index 624735be652d2..09698826a4969 100644 --- a/src/java.base/share/data/tzdata/australasia +++ b/src/java.base/share/data/tzdata/australasia @@ -66,8 +66,8 @@ Zone Australia/Perth 7:43:24 - LMT 1895 Dec 8:00 Aus AW%sT 1943 Jul 8:00 AW AW%sT Zone Australia/Eucla 8:35:28 - LMT 1895 Dec - 8:45 Aus +0845/+0945 1943 Jul - 8:45 AW +0845/+0945 + 8:45 Aus %z 1943 Jul + 8:45 AW %z # Queensland # @@ -232,8 +232,8 @@ Rule LH 2008 max - Apr Sun>=1 2:00 0 - Rule LH 2008 max - Oct Sun>=1 2:00 0:30 - Zone Australia/Lord_Howe 10:36:20 - LMT 1895 Feb 10:00 - AEST 1981 Mar - 10:30 LH +1030/+1130 1985 Jul - 10:30 LH +1030/+11 + 10:30 LH %z 1985 Jul + 10:30 LH %z # Australian miscellany # @@ -439,16 +439,16 @@ Rule Fiji 2019 only - Nov Sun>=8 2:00 1:00 - Rule Fiji 2020 only - Dec 20 2:00 1:00 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Fiji 11:55:44 - LMT 1915 Oct 26 # Suva - 12:00 Fiji +12/+13 + 12:00 Fiji %z # French Polynesia # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Gambier -8:59:48 - LMT 1912 Oct 1 # Rikitea - -9:00 - -09 + -9:00 - %z Zone Pacific/Marquesas -9:18:00 - LMT 1912 Oct 1 - -9:30 - -0930 + -9:30 - %z Zone Pacific/Tahiti -9:58:16 - LMT 1912 Oct 1 # Papeete - -10:00 - -10 + -10:00 - %z # Clipperton (near North America) is administered from French Polynesia; # it is uninhabited. @@ -491,7 +491,7 @@ Rule Guam 1977 only - Aug 28 2:00 0 S Zone Pacific/Guam -14:21:00 - LMT 1844 Dec 31 9:39:00 - LMT 1901 # Agana 10:00 - GST 1941 Dec 10 # Guam - 9:00 - +09 1944 Jul 31 + 9:00 - %z 1944 Jul 31 10:00 Guam G%sT 2000 Dec 23 10:00 - ChST # Chamorro Standard Time @@ -503,30 +503,30 @@ Zone Pacific/Guam -14:21:00 - LMT 1844 Dec 31 # Wallis & Futuna # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Tarawa 11:32:04 - LMT 1901 # Bairiki - 12:00 - +12 + 12:00 - %z # Kiribati (except Gilbert Is) # See Pacific/Tarawa for the Gilbert Is. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Kanton 0 - -00 1937 Aug 31 - -12:00 - -12 1979 Oct - -11:00 - -11 1994 Dec 31 - 13:00 - +13 + -12:00 - %z 1979 Oct + -11:00 - %z 1994 Dec 31 + 13:00 - %z Zone Pacific/Kiritimati -10:29:20 - LMT 1901 - -10:40 - -1040 1979 Oct - -10:00 - -10 1994 Dec 31 - 14:00 - +14 + -10:40 - %z 1979 Oct + -10:00 - %z 1994 Dec 31 + 14:00 - %z # Marshall Is # See Pacific/Tarawa for most locations. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Kwajalein 11:09:20 - LMT 1901 - 11:00 - +11 1937 - 10:00 - +10 1941 Apr 1 - 9:00 - +09 1944 Feb 6 - 11:00 - +11 1969 Oct - -12:00 - -12 1993 Aug 20 24:00 - 12:00 - +12 + 11:00 - %z 1937 + 10:00 - %z 1941 Apr 1 + 9:00 - %z 1944 Feb 6 + 11:00 - %z 1969 Oct + -12:00 - %z 1993 Aug 20 24:00 + 12:00 - %z # Micronesia # For Chuuk and Yap see Pacific/Port_Moresby. @@ -534,22 +534,22 @@ Zone Pacific/Kwajalein 11:09:20 - LMT 1901 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Kosrae -13:08:04 - LMT 1844 Dec 31 10:51:56 - LMT 1901 - 11:00 - +11 1914 Oct - 9:00 - +09 1919 Feb 1 - 11:00 - +11 1937 - 10:00 - +10 1941 Apr 1 - 9:00 - +09 1945 Aug - 11:00 - +11 1969 Oct - 12:00 - +12 1999 - 11:00 - +11 + 11:00 - %z 1914 Oct + 9:00 - %z 1919 Feb 1 + 11:00 - %z 1937 + 10:00 - %z 1941 Apr 1 + 9:00 - %z 1945 Aug + 11:00 - %z 1969 Oct + 12:00 - %z 1999 + 11:00 - %z # Nauru # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Nauru 11:07:40 - LMT 1921 Jan 15 # Uaobe - 11:30 - +1130 1942 Aug 29 - 9:00 - +09 1945 Sep 8 - 11:30 - +1130 1979 Feb 10 2:00 - 12:00 - +12 + 11:30 - %z 1942 Aug 29 + 9:00 - %z 1945 Sep 8 + 11:30 - %z 1979 Feb 10 2:00 + 12:00 - %z # New Caledonia # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -560,7 +560,7 @@ Rule NC 1996 only - Dec 1 2:00s 1:00 - Rule NC 1997 only - Mar 2 2:00s 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Noumea 11:05:48 - LMT 1912 Jan 13 # Nouméa - 11:00 NC +11/+12 + 11:00 NC %z ############################################################################### @@ -604,8 +604,8 @@ Zone Pacific/Auckland 11:39:04 - LMT 1868 Nov 2 12:00 NZ NZ%sT Zone Pacific/Chatham 12:13:48 - LMT 1868 Nov 2 - 12:15 - +1215 1946 Jan 1 - 12:45 Chatham +1245/+1345 + 12:15 - %z 1946 Jan 1 + 12:45 Chatham %z # Auckland Is # uninhabited; Māori and Moriori, colonial settlers, pastoralists, sealers, @@ -658,8 +658,8 @@ Rule Cook 1979 1990 - Oct lastSun 0:00 0:30 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Rarotonga 13:20:56 - LMT 1899 Dec 26 # Avarua -10:39:04 - LMT 1952 Oct 16 - -10:30 - -1030 1978 Nov 12 - -10:00 Cook -10/-0930 + -10:30 - %z 1978 Nov 12 + -10:00 Cook %z ############################################################################### @@ -676,30 +676,30 @@ Zone Pacific/Rarotonga 13:20:56 - LMT 1899 Dec 26 # Avarua # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Niue -11:19:40 - LMT 1952 Oct 16 # Alofi - -11:20 - -1120 1964 Jul - -11:00 - -11 + -11:20 - %z 1964 Jul + -11:00 - %z # Norfolk # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Norfolk 11:11:52 - LMT 1901 # Kingston - 11:12 - +1112 1951 - 11:30 - +1130 1974 Oct 27 02:00s - 11:30 1:00 +1230 1975 Mar 2 02:00s - 11:30 - +1130 2015 Oct 4 02:00s - 11:00 - +11 2019 Jul - 11:00 AN +11/+12 + 11:12 - %z 1951 + 11:30 - %z 1974 Oct 27 02:00s + 11:30 1:00 %z 1975 Mar 2 02:00s + 11:30 - %z 2015 Oct 4 02:00s + 11:00 - %z 2019 Jul + 11:00 AN %z # Palau (Belau) # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Palau -15:02:04 - LMT 1844 Dec 31 # Koror 8:57:56 - LMT 1901 - 9:00 - +09 + 9:00 - %z # Papua New Guinea # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Port_Moresby 9:48:40 - LMT 1880 9:48:32 - PMMT 1895 # Port Moresby Mean Time - 10:00 - +10 + 10:00 - %z # # From Paul Eggert (2014-10-13): # Base the Bougainville entry on the Arawa-Kieta region, which appears to have @@ -720,16 +720,16 @@ Zone Pacific/Port_Moresby 9:48:40 - LMT 1880 # Zone Pacific/Bougainville 10:22:16 - LMT 1880 9:48:32 - PMMT 1895 - 10:00 - +10 1942 Jul - 9:00 - +09 1945 Aug 21 - 10:00 - +10 2014 Dec 28 2:00 - 11:00 - +11 + 10:00 - %z 1942 Jul + 9:00 - %z 1945 Aug 21 + 10:00 - %z 2014 Dec 28 2:00 + 11:00 - %z # Pitcairn # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Pitcairn -8:40:20 - LMT 1901 # Adamstown - -8:30 - -0830 1998 Apr 27 0:00 - -8:00 - -08 + -8:30 - %z 1998 Apr 27 0:00 + -8:00 - %z # American Samoa # Midway @@ -818,15 +818,15 @@ Rule WS 2012 2020 - Sep lastSun 3:00 1 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Apia 12:33:04 - LMT 1892 Jul 5 -11:26:56 - LMT 1911 - -11:30 - -1130 1950 - -11:00 WS -11/-10 2011 Dec 29 24:00 - 13:00 WS +13/+14 + -11:30 - %z 1950 + -11:00 WS %z 2011 Dec 29 24:00 + 13:00 WS %z # Solomon Is # excludes Bougainville, for which see Papua New Guinea # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct 1 # Honiara - 11:00 - +11 + 11:00 - %z # Tokelau # @@ -849,8 +849,8 @@ Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct 1 # Honiara # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Fakaofo -11:24:56 - LMT 1901 - -11:00 - -11 2011 Dec 30 - 13:00 - +13 + -11:00 - %z 2011 Dec 30 + 13:00 - %z # Tonga # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -862,9 +862,9 @@ Rule Tonga 2016 only - Nov Sun>=1 2:00 1:00 - Rule Tonga 2017 only - Jan Sun>=15 3:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Tongatapu 12:19:12 - LMT 1945 Sep 10 - 12:20 - +1220 1961 - 13:00 - +13 1999 - 13:00 Tonga +13/+14 + 12:20 - %z 1961 + 13:00 - %z 1999 + 13:00 Tonga %z # US minor outlying islands @@ -953,7 +953,7 @@ Rule Vanuatu 1992 1993 - Jan Sat>=22 24:00 0 - Rule Vanuatu 1992 only - Oct Sat>=22 24:00 1:00 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila - 11:00 Vanuatu +11/+12 + 11:00 Vanuatu %z ############################################################################### diff --git a/src/java.base/share/data/tzdata/backward b/src/java.base/share/data/tzdata/backward index 7ddc6cc3d93b0..cda2ccc0c66ec 100644 --- a/src/java.base/share/data/tzdata/backward +++ b/src/java.base/share/data/tzdata/backward @@ -21,12 +21,13 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -# tzdb links for backward compatibility +# Links and zones for backward compatibility # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # This file provides links from old or merged timezone names to current ones. +# It also provides a few zone entries for old naming conventions. # Many names changed in 1993 and in 1995, and many merged names moved here # in the period from 2013 through 2022. Several of these names are # also present in the file 'backzone', which has data important only @@ -67,6 +68,8 @@ Link America/Rio_Branco Brazil/Acre #= America/Porto_Acre Link America/Noronha Brazil/DeNoronha Link America/Sao_Paulo Brazil/East Link America/Manaus Brazil/West +Link Europe/Brussels CET +Link America/Chicago CST6CDT Link America/Halifax Canada/Atlantic Link America/Winnipeg Canada/Central # This line is commented out, as the name exceeded the 14-character limit @@ -81,6 +84,9 @@ Link America/Whitehorse Canada/Yukon Link America/Santiago Chile/Continental Link Pacific/Easter Chile/EasterIsland Link America/Havana Cuba +Link Europe/Athens EET +Link America/Panama EST +Link America/New_York EST5EDT Link Africa/Cairo Egypt Link Europe/Dublin Eire # Vanguard section, for most .zi parsers. @@ -119,6 +125,9 @@ Link America/Jamaica Jamaica Link Asia/Tokyo Japan Link Pacific/Kwajalein Kwajalein Link Africa/Tripoli Libya +Link Europe/Brussels MET +Link America/Phoenix MST +Link America/Denver MST7MDT Link America/Tijuana Mexico/BajaNorte Link America/Mazatlan Mexico/BajaSur Link America/Mexico_City Mexico/General @@ -298,6 +307,7 @@ Link America/Denver America/Shiprock Link America/Toronto America/Thunder_Bay Link America/Edmonton America/Yellowknife Link Pacific/Auckland Antarctica/South_Pole +Link Asia/Ulaanbaatar Asia/Choibalsan Link Asia/Shanghai Asia/Chongqing Link Asia/Shanghai Asia/Harbin Link Asia/Urumqi Asia/Kashgar @@ -312,6 +322,7 @@ Link Europe/Kyiv Europe/Zaporozhye Link Pacific/Kanton Pacific/Enderbury Link Pacific/Honolulu Pacific/Johnston Link Pacific/Port_Moresby Pacific/Yap +Link Europe/Lisbon WET # Alternate names for the same location @@ -337,5 +348,7 @@ Link Europe/Kyiv Europe/Kiev # Classically, Cyprus is in Asia; e.g. see Herodotus, Histories, I.72. # However, for various reasons many users expect to find it under Europe. Link Asia/Nicosia Europe/Nicosia +Link Pacific/Honolulu HST +Link America/Los_Angeles PST8PDT Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk diff --git a/src/java.base/share/data/tzdata/etcetera b/src/java.base/share/data/tzdata/etcetera index 27147715ef6a5..780c835819def 100644 --- a/src/java.base/share/data/tzdata/etcetera +++ b/src/java.base/share/data/tzdata/etcetera @@ -28,7 +28,7 @@ # These entries are for uses not otherwise covered by the tz database. # Their main practical use is for platforms like Android that lack -# support for POSIX.1-2017-style TZ strings. On such platforms these entries +# support for POSIX proleptic TZ strings. On such platforms these entries # can be useful if the timezone database is wrong or if a ship or # aircraft at sea is not in a timezone. @@ -74,29 +74,29 @@ Link Etc/GMT GMT # so we moved the names into the Etc subdirectory. # Also, the time zone abbreviations are now compatible with %z. -Zone Etc/GMT-14 14 - +14 -Zone Etc/GMT-13 13 - +13 -Zone Etc/GMT-12 12 - +12 -Zone Etc/GMT-11 11 - +11 -Zone Etc/GMT-10 10 - +10 -Zone Etc/GMT-9 9 - +09 -Zone Etc/GMT-8 8 - +08 -Zone Etc/GMT-7 7 - +07 -Zone Etc/GMT-6 6 - +06 -Zone Etc/GMT-5 5 - +05 -Zone Etc/GMT-4 4 - +04 -Zone Etc/GMT-3 3 - +03 -Zone Etc/GMT-2 2 - +02 -Zone Etc/GMT-1 1 - +01 -Zone Etc/GMT+1 -1 - -01 -Zone Etc/GMT+2 -2 - -02 -Zone Etc/GMT+3 -3 - -03 -Zone Etc/GMT+4 -4 - -04 -Zone Etc/GMT+5 -5 - -05 -Zone Etc/GMT+6 -6 - -06 -Zone Etc/GMT+7 -7 - -07 -Zone Etc/GMT+8 -8 - -08 -Zone Etc/GMT+9 -9 - -09 -Zone Etc/GMT+10 -10 - -10 -Zone Etc/GMT+11 -11 - -11 -Zone Etc/GMT+12 -12 - -12 +Zone Etc/GMT-14 14 - %z +Zone Etc/GMT-13 13 - %z +Zone Etc/GMT-12 12 - %z +Zone Etc/GMT-11 11 - %z +Zone Etc/GMT-10 10 - %z +Zone Etc/GMT-9 9 - %z +Zone Etc/GMT-8 8 - %z +Zone Etc/GMT-7 7 - %z +Zone Etc/GMT-6 6 - %z +Zone Etc/GMT-5 5 - %z +Zone Etc/GMT-4 4 - %z +Zone Etc/GMT-3 3 - %z +Zone Etc/GMT-2 2 - %z +Zone Etc/GMT-1 1 - %z +Zone Etc/GMT+1 -1 - %z +Zone Etc/GMT+2 -2 - %z +Zone Etc/GMT+3 -3 - %z +Zone Etc/GMT+4 -4 - %z +Zone Etc/GMT+5 -5 - %z +Zone Etc/GMT+6 -6 - %z +Zone Etc/GMT+7 -7 - %z +Zone Etc/GMT+8 -8 - %z +Zone Etc/GMT+9 -9 - %z +Zone Etc/GMT+10 -10 - %z +Zone Etc/GMT+11 -11 - %z +Zone Etc/GMT+12 -12 - %z diff --git a/src/java.base/share/data/tzdata/europe b/src/java.base/share/data/tzdata/europe index 18865f33b6c59..df203f218d118 100644 --- a/src/java.base/share/data/tzdata/europe +++ b/src/java.base/share/data/tzdata/europe @@ -753,14 +753,6 @@ Rule Russia 1996 2010 - Oct lastSun 2:00s 0 - # Take "abolishing daylight saving time" to mean that time is now considered # to be standard. -# These are for backward compatibility with older versions. - -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone WET 0:00 EU WE%sT -Zone CET 1:00 C-Eur CE%sT -Zone MET 1:00 C-Eur ME%sT -Zone EET 2:00 EU EE%sT - # Previous editions of this database used abbreviations like MET DST # for Central European Summer Time, but this didn't agree with common usage. @@ -894,7 +886,7 @@ Zone Europe/Minsk 1:50:16 - LMT 1880 3:00 Russia MSK/MSD 1990 3:00 - MSK 1991 Mar 31 2:00s 2:00 Russia EE%sT 2011 Mar 27 2:00s - 3:00 - +03 + 3:00 - %z # Belgium # Luxembourg @@ -1199,22 +1191,22 @@ Rule Thule 2007 max - Nov Sun>=1 2:00 0 S # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Danmarkshavn -1:14:40 - LMT 1916 Jul 28 - -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 1996 + -3:00 - %z 1980 Apr 6 2:00 + -3:00 EU %z 1996 0:00 - GMT # # Use the old name Scoresbysund, as the current name Ittoqqortoormiit # exceeds tzdb's 14-letter limit and has no common English abbreviation. Zone America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 # Ittoqqortoormiit - -2:00 - -02 1980 Apr 6 2:00 - -2:00 C-Eur -02/-01 1981 Mar 29 - -1:00 EU -01/+00 2024 Mar 31 - -2:00 EU -02/-01 + -2:00 - %z 1980 Apr 6 2:00 + -2:00 C-Eur %z 1981 Mar 29 + -1:00 EU %z 2024 Mar 31 + -2:00 EU %z Zone America/Nuuk -3:26:56 - LMT 1916 Jul 28 # Godthåb - -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 2023 Mar 26 1:00u - -2:00 - -02 2023 Oct 29 1:00u - -2:00 EU -02/-01 + -3:00 - %z 1980 Apr 6 2:00 + -3:00 EU %z 2023 Mar 26 1:00u + -2:00 - %z 2023 Oct 29 1:00u + -2:00 EU %z Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik -4:00 Thule A%sT @@ -2086,10 +2078,39 @@ Zone Europe/Warsaw 1:24:00 - LMT 1880 # Portugal -# From Paul Eggert (2014-08-11), after a heads-up from Stephen Colebourne: -# According to a Portuguese decree (1911-05-26) -# https://dre.pt/application/dir/pdf1sdip/1911/05/12500/23132313.pdf -# Lisbon was at -0:36:44.68, but switched to GMT on 1912-01-01 at 00:00. +# From Tim Parenti (2024-07-01), per Alois Treindl (2021-02-07) and Michael +# Deckers (2021-02-10): +# http://oal.ul.pt/documentos/2018/01/hl1911a2018.pdf/ +# The Astronomical Observatory of Lisbon has published a list detailing the +# historical transitions in legal time within continental Portugal. It +# directly references many decrees and ordinances which are, in turn, +# referenced below. They can be viewed in the public archives of the Diário da +# República (until 1976-04-09 known as the Diário do Govêrno) at +# https://dre.pt/ (in Portuguese). +# +# Most of the Rules below have been updated simply to match the Observatory's +# listing for continental (mainland) Portugal. Although there are over 50 +# referenced decrees and ordinances, only the handful with comments below have +# been verified against the text, typically to provide additional confidence +# wherever dates provided by Whitman and Shanks & Pottenger had disagreed. +# See further below for the Azores and Madeira. + +# From Tim Parenti (2024-07-01), per Paul Eggert (2014-08-11), after a +# heads-up from Stephen Colebourne: +# According to a 1911-05-24 Portuguese decree, Lisbon was at -0:36:44.68, but +# switched to GMT on 1912-01-01 at 00:00. +# https://dre.pt/dr/detalhe/decreto/593090 +# https://dre.pt/application/conteudo/593090 +# The decree made legal time throughout Portugal and her possessions +# "subordinate to the Greenwich meridian, according to the principle adopted at +# the Washington Convention in 1884" and eliminated the "difference of five +# minutes between the internal and external clocks of railway stations". +# +# The decree was gazetted in the 1911-05-30 issue of Diário do Govêrno, and is +# considered to be dated 1911-05-24 by that issue's summary; however, the text +# of the decree itself is dated 1911-05-26. The Diário da República website +# notes the discrepancy, but later laws and the Observatory all seem to refer +# to this decree by the 1911-05-24 date. # # From Michael Deckers (2018-02-15): # article 5 [of the 1911 decree; Deckers's translation] ...: @@ -2097,37 +2118,62 @@ Zone Europe/Warsaw 1:24:00 - LMT 1880 # according to the 2nd article, the civil day January 1, 1912 begins, # all clocks therefore having to be advanced or set back correspondingly ... -# From Rui Pedro Salgueiro (1992-11-12): -# Portugal has recently (September, 27) changed timezone -# (from WET to MET or CET) to harmonize with EEC. -# -# Martin Bruckmann (1996-02-29) reports via Peter Ilieve -# that Portugal is reverting to 0:00 by not moving its clocks this spring. -# The new Prime Minister was fed up with getting up in the dark in the winter. -# -# From Paul Eggert (1996-11-12): -# IATA SSIM (1991-09) reports several 1991-09 and 1992-09 transitions -# at 02:00u, not 01:00u. Assume that these are typos. -# IATA SSIM (1991/1992) reports that the Azores were at -1:00. -# IATA SSIM (1993-02) says +0:00; later issues (through 1996-09) say -1:00. -# Guess that the Azores changed to EU rules in 1992 (since that's when Portugal -# harmonized with EU rules), and that they stayed +0:00 that winter. -# # Rule NAME FROM TO - IN ON AT SAVE LETTER/S -# DSH writes that despite Decree 1,469 (1915), the change to the clocks was not -# done every year, depending on what Spain did, because of railroad schedules. -# Go with Shanks & Pottenger. +# From Tim Parenti (2024-07-01), per Paul Eggert (1999-01-30): +# DSH writes in their history that Decreto 1469 of 1915-03-30 established +# summer time and that, "despite" this, the change to the clocks was not done +# every year, depending on what Spain did, because of railroad schedules. +# In fact, that decree had nothing to do with DST; rather, it regulated the +# sending of time signals. But we do see linkage to Spain in the 1920s below. +# https://dre.pt/dr/detalhe/decreto/1469-1915-285721 +# https://dre.pt/application/conteudo/285721 +# +# According to the Observatory, standard time was first advanced by Decreto +# 2433 of 1916-06-09 and restored by Decreto 2712 of 1916-10-28. While Whitman +# gives 1916-10-31 for the latter transition, Shanks & Pottenger agrees more +# closely with the decree, which stated that its provision "will start sixty +# minutes after the end of 31 October, according to the current time," i.e., +# 01:00 on 1 November. +# https://dre.pt/dr/detalhe/decreto/2433-1916-267192 +# https://dre.pt/application/conteudo/267192 +# https://dre.pt/dr/detalhe/decreto/2712-1916-590937 +# https://dre.pt/application/conteudo/590937 Rule Port 1916 only - Jun 17 23:00 1:00 S -# Whitman gives 1916 Oct 31; go with Shanks & Pottenger. Rule Port 1916 only - Nov 1 1:00 0 - -Rule Port 1917 only - Feb 28 23:00s 1:00 S -Rule Port 1917 1921 - Oct 14 23:00s 0 - -Rule Port 1918 only - Mar 1 23:00s 1:00 S -Rule Port 1919 only - Feb 28 23:00s 1:00 S -Rule Port 1920 only - Feb 29 23:00s 1:00 S -Rule Port 1921 only - Feb 28 23:00s 1:00 S +# From Tim Parenti (2024-07-01): +# Article 7 of Decreto 2922 of 1916-12-30 stated that "the legal time will be +# advanced by sixty minutes from 1 March to 31 October." Per Article 15, this +# came into force from 1917-01-01. Just before the first fall back, Decreto +# 3446 of 1917-10-11 changed the annual end date to 14 October. +# https://dre.pt/dr/detalhe/decreto/2922-1916-261894 +# https://dre.pt/application/conteudo/261894 +# https://dre.pt/dr/detalhe/decreto/3446-1917-495161 +# https://dre.pt/application/conteudo/495161 +# This annual change was revoked by Decreto 8038 of 1922-02-18. +# https://dre.pt/dr/detalhe/decreto/8038-1922-569751 +# https://dre.pt/application/conteudo/569751 +Rule Port 1917 1921 - Mar 1 0:00 1:00 S +Rule Port 1917 1921 - Oct 14 24:00 0 - +# From Tim Parenti (2024-07-01): +# Decreto 9592 of 1924-04-14 noted that "France maintains the advance of legal +# time in the summer and Spain has now adopted it for the first time" and +# considered "that the absence of similar measures would cause serious +# difficulties for international rail connections with consequent repercussions +# on domestic service hours..." along with "inconvenient analogues...for postal +# and telegraph services." Summer time would be in effect from 17 April to 4 +# October, with the spring change explicitly specified by bringing clocks +# forward from 16 April 23:00. +# https://dre.pt/dr/detalhe/decreto/9592-1924-652133 +# https://dre.pt/application/conteudo/652133 +# +# Decreto 10700, issued 1925-04-16, noted that Spain had not continued summer +# time, declared that "the current legal hour prior to 17 April remains +# unchanged from that day forward", and revoked legislation to the contrary, +# just a day before summer time would have otherwise resumed. +# https://dre.pt/dr/detalhe/decreto/10700-1925-437826 +# https://dre.pt/application/conteudo/437826 Rule Port 1924 only - Apr 16 23:00s 1:00 S -Rule Port 1924 only - Oct 14 23:00s 0 - +Rule Port 1924 only - Oct 4 23:00s 0 - Rule Port 1926 only - Apr 17 23:00s 1:00 S Rule Port 1926 1929 - Oct Sat>=1 23:00s 0 - Rule Port 1927 only - Apr 9 23:00s 1:00 S @@ -2139,6 +2185,8 @@ Rule Port 1931 1932 - Oct Sat>=1 23:00s 0 - Rule Port 1932 only - Apr 2 23:00s 1:00 S Rule Port 1934 only - Apr 7 23:00s 1:00 S # Whitman gives 1934 Oct 5; go with Shanks & Pottenger. +# Note: The 1935 law specified 10-06 00:00, not 10-05 24:00, but the following +# is equivalent and more succinct. Rule Port 1934 1938 - Oct Sat>=1 23:00s 0 - # Shanks & Pottenger give 1935 Apr 30; go with Whitman. Rule Port 1935 only - Mar 30 23:00s 1:00 S @@ -2149,10 +2197,19 @@ Rule Port 1938 only - Mar 26 23:00s 1:00 S Rule Port 1939 only - Apr 15 23:00s 1:00 S # Whitman gives 1939 Oct 7; go with Shanks & Pottenger. Rule Port 1939 only - Nov 18 23:00s 0 - +# From Tim Parenti (2024-07-01): +# Portaria 9465 of 1940-02-17 advanced clocks from Saturday 1940-02-24 23:00. +# The clocks were restored by Portaria 9658, issued Monday 1940-10-07, +# effective from 24:00 that very night, which agrees with Shanks & Pottenger; +# Whitman gives Saturday 1940-10-05 instead. +# https://dre.pt/dr/detalhe/portaria/9465-1940-189096 +# https://dre.pt/application/conteudo/189096 +# https://dre.pt/dr/detalhe/portaria/9658-1940-196729 +# https://dre.pt/application/conteudo/196729 Rule Port 1940 only - Feb 24 23:00s 1:00 S -# Shanks & Pottenger give 1940 Oct 7; go with Whitman. -Rule Port 1940 1941 - Oct 5 23:00s 0 - +Rule Port 1940 only - Oct 7 23:00s 0 - Rule Port 1941 only - Apr 5 23:00s 1:00 S +Rule Port 1941 only - Oct 5 23:00s 0 - Rule Port 1942 1945 - Mar Sat>=8 23:00s 1:00 S Rule Port 1942 only - Apr 25 22:00s 2:00 M # Midsummer Rule Port 1942 only - Aug 15 22:00s 1:00 S @@ -2162,66 +2219,195 @@ Rule Port 1943 1945 - Aug Sat>=25 22:00s 1:00 S Rule Port 1944 1945 - Apr Sat>=21 22:00s 2:00 M Rule Port 1946 only - Apr Sat>=1 23:00s 1:00 S Rule Port 1946 only - Oct Sat>=1 23:00s 0 - -# Whitman says DST was not observed in 1950; go with Shanks & Pottenger. -# Whitman gives Oct lastSun for 1952 on; go with Shanks & Pottenger. -Rule Port 1947 1965 - Apr Sun>=1 2:00s 1:00 S +# From Tim Parenti (2024-07-01), per Alois Treindl (2021-02-07): +# The Astronomical Observatory of Lisbon cites Portaria 11767 of 1947-03-28 for +# 1947 and Portaria 12286 of 1948-02-19 for 1948. +# https://dre.pt/dr/detalhe/portaria/11767-1947-414787 +# https://dre.pt/application/conteudo/414787 +# https://dre.pt/dr/detalhe/portaria/12286-1948-152953 +# https://dre.pt/application/conteudo/152953 +# +# Although the latter ordinance explicitly had the 1948-10-03 transition +# scheduled for 02:00 rather than 03:00 as had been used in 1947, Decreto-Lei +# 37048 of 1948-09-07 recognized "that it is advisable to definitely set...the +# 'summer time' regime", and fixed the fall transition at 03:00 moving forward. +# https://dre.pt/dr/detalhe/decreto-lei/37048-1948-373810 +# https://dre.pt/application/conteudo/373810 +# While the Observatory only cites this act for 1949-1965 and not for 1948, it +# does not appear to have had any provision delaying its effect, so assume that +# it overrode the prior ordinance for 1948-10-03. +# +# Whitman says DST was not observed in 1950 and gives Oct lastSun for 1952 on. +# The Observatory, however, agrees with Shanks & Pottenger that 1950 was not an +# exception and that Oct Sun>=1 was maintained through 1965. +Rule Port 1947 1966 - Apr Sun>=1 2:00s 1:00 S Rule Port 1947 1965 - Oct Sun>=1 2:00s 0 - -Rule Port 1977 only - Mar 27 0:00s 1:00 S -Rule Port 1977 only - Sep 25 0:00s 0 - -Rule Port 1978 1979 - Apr Sun>=1 0:00s 1:00 S -Rule Port 1978 only - Oct 1 0:00s 0 - -Rule Port 1979 1982 - Sep lastSun 1:00s 0 - -Rule Port 1980 only - Mar lastSun 0:00s 1:00 S -Rule Port 1981 1982 - Mar lastSun 1:00s 1:00 S -Rule Port 1983 only - Mar lastSun 2:00s 1:00 S +# From Tim Parenti (2024-07-01): +# Decreto-Lei 47233 of 1966-10-01 considered that the "duality" in time was +# "the cause of serious disturbances" and noted that "the countries with which +# we have the most frequent contacts...have already adopted" a solution +# coinciding with the extant "summer time". It established that the former +# "summer time" would apply year-round on the mainland and adjacent islands +# with immediate effect, as the fall back would have otherwise occurred later +# that evening. +# https://dre.pt/dr/detalhe/decreto-lei/47233-1966-293729 +# Model this by changing zones without changing clocks at the +# previously-appointed fall back time. +# +# Decreto-Lei 309/76 of 1976-04-27 acknowledged that those international +# contacts had returned to adopting seasonal times, and considered that the +# year-round advancement "entails considerable sacrifices for the vast majority +# of the working population during the winter months", including morning +# visibility concerns for schoolchildren. It specified, beginning 1976-09-26 +# 01:00, an annual return to UT+00 on the mainland from 00:00 UT on Sep lastSun +# to 00:00 UT on Mar lastSun (unless the latter date fell on Easter, in which +# case it was to be brought forward to the preceding Sunday). It also assigned +# the Permanent Time Commission to study and propose revisions for the Azores +# and Madeira, neither of which resumed DST until 1982 (as described further +# below). +# https://dre.pt/dr/detalhe/decreto-lei/309-1976-502063 +Rule Port 1976 only - Sep lastSun 1:00 0 - +Rule Port 1977 only - Mar lastSun 0:00s 1:00 S +Rule Port 1977 only - Sep lastSun 0:00s 0 - +# From Tim Parenti (2024-07-01): +# Beginning in 1978, rather than triggering the Easter rule of the 1976 decree +# (Easter fell on 1978-03-26), Article 5 was used instead, which allowed DST +# dates to be changed by order of the Minister of Education and Scientific +# Research, upon consultation with the Permanent Time Commission, "whenever +# considered convenient." As such, a series of one-off ordinances were +# promulgated for the mainland in 1978 through 1980, after which the 1976 +# decree naturally came back into force from 1981. +Rule Port 1978 1980 - Apr Sun>=1 1:00s 1:00 S +Rule Port 1978 only - Oct 1 1:00s 0 - +Rule Port 1979 1980 - Sep lastSun 1:00s 0 - +Rule Port 1981 1986 - Mar lastSun 0:00s 1:00 S +Rule Port 1981 1985 - Sep lastSun 0:00s 0 - +# From Tim Parenti (2024-07-01): +# Decreto-Lei 44-B/86 of 1986-03-07 switched mainland Portugal's transition +# times from 0:00s to 1:00u to harmonize with the EEC from 1986-03-30. +# https://dre.pt/dr/detalhe/decreto-lei/44-b-1986-628280 +# (Transitions of 1:00s as previously reported and used by the W-Eur rules, +# though equivalent, appear to have been fiction here.) Madeira continued to +# use 0:00s for spring 1986 before joining with the mainland using 1:00u in the +# fall; meanwhile, in the Azores the two were equivalent, so the law specifying +# 0:00s wasn't touched until 1992. (See below for more on the islands.) +# +# From Rui Pedro Salgueiro (1992-11-12): +# Portugal has recently (September, 27) changed timezone +# (from WET to MET or CET) to harmonize with EEC. +# +# Martin Bruckmann (1996-02-29) reports via Peter Ilieve +# that Portugal is reverting to 0:00 by not moving its clocks this spring. +# The new Prime Minister was fed up with getting up in the dark in the winter. +# +# From Paul Eggert (1996-11-12): +# IATA SSIM (1991-09) reports several 1991-09 and 1992-09 transitions +# at 02:00u, not 01:00u. Assume that these are typos. # # Zone NAME STDOFF RULES FORMAT [UNTIL] #STDOFF -0:36:44.68 Zone Europe/Lisbon -0:36:45 - LMT 1884 -0:36:45 - LMT 1912 Jan 1 0:00u # Lisbon MT - 0:00 Port WE%sT 1966 Apr 3 2:00 + 0:00 Port WE%sT 1966 Oct 2 2:00s 1:00 - CET 1976 Sep 26 1:00 - 0:00 Port WE%sT 1983 Sep 25 1:00s - 0:00 W-Eur WE%sT 1992 Sep 27 1:00s + 0:00 Port WE%sT 1986 + 0:00 EU WE%sT 1992 Sep 27 1:00u 1:00 EU CE%sT 1996 Mar 31 1:00u 0:00 EU WE%sT + +# From Tim Parenti (2024-07-01): +# For the Azores and Madeira, legislation was followed from the laws currently +# in force as listed at: +# https://oal.ul.pt/hora-legal/legislacao/ +# working backward through references of revocation and abrogation to +# Decreto-Lei 47233 of 1966-10-01, the last time DST was abolished across the +# mainland and its adjacent islands. Because of that reference, it is +# therefore assumed that DST rules in the islands prior to 1966 were like that +# of the mainland, though most legislation of the time didn't explicitly +# specify DST practices for the islands. Zone Atlantic/Azores -1:42:40 - LMT 1884 # Ponta Delgada -1:54:32 - HMT 1912 Jan 1 2:00u # Horta MT # Vanguard section, for zic and other parsers that support %z. -# -2:00 Port %z 1966 Apr 3 2:00 -# -1:00 Port %z 1983 Sep 25 1:00s -# -1:00 W-Eur %z 1992 Sep 27 1:00s + -2:00 Port %z 1966 Oct 2 2:00s +# From Tim Parenti (2024-07-01): +# While Decreto-Lei 309/76 of 1976-04-27 reintroduced DST on the mainland by +# falling back on 1976-09-26, it assigned the Permanent Time Commission to +# study and propose revisions for the Azores and Madeira. Decreto Regional +# 9/77/A of 1977-05-17 affirmed that "the legal time remained unchanged in the +# Azores" at UT-1, and would remain there year-round. +# https://dre.pt/dr/detalhe/decreto-regional/9-1977-252066 +# +# Decreto Regional 2/82/A, published 1982-03-02, adopted DST in the same +# fashion as the mainland used at the time. +# https://dre.pt/dr/detalhe/decreto-regional/2-1982-599965 +# Though transitions in the Azores officially remained at 0:00s through 1992, +# this was equivalent to the EU-style 1:00u adopted by the mainland in 1986, so +# model it as such. + -1:00 - %z 1982 Mar 28 0:00s + -1:00 Port %z 1986 # Rearguard section, for parsers lacking %z; see ziguard.awk. - -2:00 Port -02/-01 1942 Apr 25 22:00s - -2:00 Port +00 1942 Aug 15 22:00s - -2:00 Port -02/-01 1943 Apr 17 22:00s - -2:00 Port +00 1943 Aug 28 22:00s - -2:00 Port -02/-01 1944 Apr 22 22:00s - -2:00 Port +00 1944 Aug 26 22:00s - -2:00 Port -02/-01 1945 Apr 21 22:00s - -2:00 Port +00 1945 Aug 25 22:00s - -2:00 Port -02/-01 1966 Apr 3 2:00 - -1:00 Port -01/+00 1983 Sep 25 1:00s - -1:00 W-Eur -01/+00 1992 Sep 27 1:00s +# -2:00 Port -02/-01 1942 Apr 25 22:00s +# -2:00 Port +00 1942 Aug 15 22:00s +# -2:00 Port -02/-01 1943 Apr 17 22:00s +# -2:00 Port +00 1943 Aug 28 22:00s +# -2:00 Port -02/-01 1944 Apr 22 22:00s +# -2:00 Port +00 1944 Aug 26 22:00s +# -2:00 Port -02/-01 1945 Apr 21 22:00s +# -2:00 Port +00 1945 Aug 25 22:00s +# -2:00 Port -02/-01 1966 Oct 2 2:00s +# -1:00 - -01 1982 Mar 28 0:00s +# -1:00 Port -01/+00 1986 # End of rearguard section. - 0:00 EU WE%sT 1993 Mar 28 1:00u - -1:00 EU -01/+00 +# +# From Paul Eggert (1996-11-12): +# IATA SSIM (1991/1992) reports that the Azores were at -1:00. +# IATA SSIM (1993-02) says +0:00; later issues (through 1996-09) say -1:00. +# +# From Tim Parenti (2024-07-01): +# After mainland Portugal had shifted forward an hour from 1992-09-27, Decreto +# Legislativo Regional 29/92/A of 1992-12-23 sought to "reduce the time +# difference" by shifting the Azores forward as well from 1992-12-27. Just six +# months later, this was revoked by Decreto Legislativo Regional 9/93/A, citing +# "major changes in work habits and way of life." Though the revocation didn't +# give a transition time, it was signed Wednesday 1993-06-16; assume it took +# effect later that evening, and that an EU-style spring forward (to +01) was +# still observed in the interim on 1993-03-28. +# https://dre.pt/dr/detalhe/decreto-legislativo-regional/29-1992-621553 +# https://dre.pt/dr/detalhe/decreto-legislativo-regional/9-1993-389633 + -1:00 EU %z 1992 Dec 27 1:00s + 0:00 EU WE%sT 1993 Jun 17 1:00u + -1:00 EU %z + Zone Atlantic/Madeira -1:07:36 - LMT 1884 # Funchal -1:07:36 - FMT 1912 Jan 1 1:00u # Funchal MT # Vanguard section, for zic and other parsers that support %z. -# -1:00 Port %z 1966 Apr 3 2:00 + -1:00 Port %z 1966 Oct 2 2:00s # Rearguard section, for parsers lacking %z; see ziguard.awk. - -1:00 Port -01/+00 1942 Apr 25 22:00s - -1:00 Port +01 1942 Aug 15 22:00s - -1:00 Port -01/+00 1943 Apr 17 22:00s - -1:00 Port +01 1943 Aug 28 22:00s - -1:00 Port -01/+00 1944 Apr 22 22:00s - -1:00 Port +01 1944 Aug 26 22:00s - -1:00 Port -01/+00 1945 Apr 21 22:00s - -1:00 Port +01 1945 Aug 25 22:00s - -1:00 Port -01/+00 1966 Apr 3 2:00 +# -1:00 Port -01/+00 1942 Apr 25 22:00s +# -1:00 Port +01 1942 Aug 15 22:00s +# -1:00 Port -01/+00 1943 Apr 17 22:00s +# -1:00 Port +01 1943 Aug 28 22:00s +# -1:00 Port -01/+00 1944 Apr 22 22:00s +# -1:00 Port +01 1944 Aug 26 22:00s +# -1:00 Port -01/+00 1945 Apr 21 22:00s +# -1:00 Port +01 1945 Aug 25 22:00s +# -1:00 Port -01/+00 1966 Oct 2 2:00s # End of rearguard section. - 0:00 Port WE%sT 1983 Sep 25 1:00s +# +# From Tim Parenti (2024-07-01): +# Decreto Regional 5/82/M, published 1982-04-03, established DST transitions at +# 0:00u, which for Madeira is equivalent to the mainland's rules (0:00s) at the +# time. It came into effect the day following its publication, Sunday +# 1982-04-04, thus resuming Madeira's DST practice about a week later than the +# mainland and the Azores. +# https://dre.pt/dr/detalhe/decreto-regional/5-1982-608273 +# +# Decreto Legislativo Regional 18/86/M, published 1986-10-01, adopted EU-style +# rules (1:00u) and entered into immediate force after being signed on +# 1986-07-31. +# https://dre.pt/dr/detalhe/decreto-legislativo-regional/18-1986-221705 + 0:00 - WET 1982 Apr 4 + 0:00 Port WE%sT 1986 Jul 31 0:00 EU WE%sT # Romania @@ -2433,7 +2619,7 @@ Zone Europe/Kaliningrad 1:22:00 - LMT 1893 Apr 2:00 Poland EE%sT 1946 Apr 7 3:00 Russia MSK/MSD 1989 Mar 26 2:00s 2:00 Russia EE%sT 2011 Mar 27 2:00s - 3:00 - +03 2014 Oct 26 2:00s + 3:00 - %z 2014 Oct 26 2:00s 2:00 - EET @@ -2683,14 +2869,14 @@ Zone Europe/Simferopol 2:16:24 - LMT 1880 # http://publication.pravo.gov.ru/Document/View/0001201602150056 Zone Europe/Astrakhan 3:12:12 - LMT 1924 May - 3:00 - +03 1930 Jun 21 - 4:00 Russia +04/+05 1989 Mar 26 2:00s - 3:00 Russia +03/+04 1991 Mar 31 2:00s - 4:00 - +04 1992 Mar 29 2:00s - 3:00 Russia +03/+04 2011 Mar 27 2:00s - 4:00 - +04 2014 Oct 26 2:00s - 3:00 - +03 2016 Mar 27 2:00s - 4:00 - +04 + 3:00 - %z 1930 Jun 21 + 4:00 Russia %z 1989 Mar 26 2:00s + 3:00 Russia %z 1991 Mar 31 2:00s + 4:00 - %z 1992 Mar 29 2:00s + 3:00 Russia %z 2011 Mar 27 2:00s + 4:00 - %z 2014 Oct 26 2:00s + 3:00 - %z 2016 Mar 27 2:00s + 4:00 - %z # From Paul Eggert (2016-11-11): # Europe/Volgograd covers: @@ -2720,15 +2906,15 @@ Zone Europe/Astrakhan 3:12:12 - LMT 1924 May # http://publication.pravo.gov.ru/Document/View/0001202012220002 Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3 - 3:00 - +03 1930 Jun 21 - 4:00 - +04 1961 Nov 11 - 4:00 Russia +04/+05 1988 Mar 27 2:00s + 3:00 - %z 1930 Jun 21 + 4:00 - %z 1961 Nov 11 + 4:00 Russia %z 1988 Mar 27 2:00s 3:00 Russia MSK/MSD 1991 Mar 31 2:00s - 4:00 - +04 1992 Mar 29 2:00s + 4:00 - %z 1992 Mar 29 2:00s 3:00 Russia MSK/MSD 2011 Mar 27 2:00s 4:00 - MSK 2014 Oct 26 2:00s 3:00 - MSK 2018 Oct 28 2:00s - 4:00 - +04 2020 Dec 27 2:00s + 4:00 - %z 2020 Dec 27 2:00s 3:00 - MSK # From Paul Eggert (2016-11-11): @@ -2743,14 +2929,14 @@ Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3 # http://publication.pravo.gov.ru/Document/View/0001201611220031 Zone Europe/Saratov 3:04:18 - LMT 1919 Jul 1 0:00u - 3:00 - +03 1930 Jun 21 - 4:00 Russia +04/+05 1988 Mar 27 2:00s - 3:00 Russia +03/+04 1991 Mar 31 2:00s - 4:00 - +04 1992 Mar 29 2:00s - 3:00 Russia +03/+04 2011 Mar 27 2:00s - 4:00 - +04 2014 Oct 26 2:00s - 3:00 - +03 2016 Dec 4 2:00s - 4:00 - +04 + 3:00 - %z 1930 Jun 21 + 4:00 Russia %z 1988 Mar 27 2:00s + 3:00 Russia %z 1991 Mar 31 2:00s + 4:00 - %z 1992 Mar 29 2:00s + 3:00 Russia %z 2011 Mar 27 2:00s + 4:00 - %z 2014 Oct 26 2:00s + 3:00 - %z 2016 Dec 4 2:00s + 4:00 - %z # From Paul Eggert (2016-03-18): # Europe/Kirov covers: @@ -2758,10 +2944,10 @@ Zone Europe/Saratov 3:04:18 - LMT 1919 Jul 1 0:00u # The 1989 transition is from USSR act No. 227 (1989-03-14). # Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0:00u - 3:00 - +03 1930 Jun 21 - 4:00 Russia +04/+05 1989 Mar 26 2:00s + 3:00 - %z 1930 Jun 21 + 4:00 Russia %z 1989 Mar 26 2:00s 3:00 Russia MSK/MSD 1991 Mar 31 2:00s - 4:00 - +04 1992 Mar 29 2:00s + 4:00 - %z 1992 Mar 29 2:00s 3:00 Russia MSK/MSD 2011 Mar 27 2:00s 4:00 - MSK 2014 Oct 26 2:00s 3:00 - MSK @@ -2776,15 +2962,15 @@ Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0:00u # The 1989 transition is from USSR act No. 227 (1989-03-14). Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 0:00u - 3:00 - +03 1930 Jun 21 - 4:00 - +04 1935 Jan 27 - 4:00 Russia +04/+05 1989 Mar 26 2:00s - 3:00 Russia +03/+04 1991 Mar 31 2:00s - 2:00 Russia +02/+03 1991 Sep 29 2:00s - 3:00 - +03 1991 Oct 20 3:00 - 4:00 Russia +04/+05 2010 Mar 28 2:00s - 3:00 Russia +03/+04 2011 Mar 27 2:00s - 4:00 - +04 + 3:00 - %z 1930 Jun 21 + 4:00 - %z 1935 Jan 27 + 4:00 Russia %z 1989 Mar 26 2:00s + 3:00 Russia %z 1991 Mar 31 2:00s + 2:00 Russia %z 1991 Sep 29 2:00s + 3:00 - %z 1991 Oct 20 3:00 + 4:00 Russia %z 2010 Mar 28 2:00s + 3:00 Russia %z 2011 Mar 27 2:00s + 4:00 - %z # From Paul Eggert (2016-03-18): # Europe/Ulyanovsk covers: @@ -2800,14 +2986,14 @@ Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 0:00u # http://publication.pravo.gov.ru/Document/View/0001201603090051 Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0:00u - 3:00 - +03 1930 Jun 21 - 4:00 Russia +04/+05 1989 Mar 26 2:00s - 3:00 Russia +03/+04 1991 Mar 31 2:00s - 2:00 Russia +02/+03 1992 Jan 19 2:00s - 3:00 Russia +03/+04 2011 Mar 27 2:00s - 4:00 - +04 2014 Oct 26 2:00s - 3:00 - +03 2016 Mar 27 2:00s - 4:00 - +04 + 3:00 - %z 1930 Jun 21 + 4:00 Russia %z 1989 Mar 26 2:00s + 3:00 Russia %z 1991 Mar 31 2:00s + 2:00 Russia %z 1992 Jan 19 2:00s + 3:00 Russia %z 2011 Mar 27 2:00s + 4:00 - %z 2014 Oct 26 2:00s + 3:00 - %z 2016 Mar 27 2:00s + 4:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): # Asia/Yekaterinburg covers... @@ -2832,12 +3018,12 @@ Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0:00u #STDOFF 4:02:32.9 Zone Asia/Yekaterinburg 4:02:33 - LMT 1916 Jul 3 3:45:05 - PMT 1919 Jul 15 4:00 - 4:00 - +04 1930 Jun 21 - 5:00 Russia +05/+06 1991 Mar 31 2:00s - 4:00 Russia +04/+05 1992 Jan 19 2:00s - 5:00 Russia +05/+06 2011 Mar 27 2:00s - 6:00 - +06 2014 Oct 26 2:00s - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 Russia %z 1991 Mar 31 2:00s + 4:00 Russia %z 1992 Jan 19 2:00s + 5:00 Russia %z 2011 Mar 27 2:00s + 6:00 - %z 2014 Oct 26 2:00s + 5:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -2847,12 +3033,12 @@ Zone Asia/Yekaterinburg 4:02:33 - LMT 1916 Jul 3 # Byalokoz 1919 says Omsk was 4:53:30. Zone Asia/Omsk 4:53:30 - LMT 1919 Nov 14 - 5:00 - +05 1930 Jun 21 - 6:00 Russia +06/+07 1991 Mar 31 2:00s - 5:00 Russia +05/+06 1992 Jan 19 2:00s - 6:00 Russia +06/+07 2011 Mar 27 2:00s - 7:00 - +07 2014 Oct 26 2:00s - 6:00 - +06 + 5:00 - %z 1930 Jun 21 + 6:00 Russia %z 1991 Mar 31 2:00s + 5:00 Russia %z 1992 Jan 19 2:00s + 6:00 Russia %z 2011 Mar 27 2:00s + 7:00 - %z 2014 Oct 26 2:00s + 6:00 - %z # From Paul Eggert (2016-02-22): # Asia/Barnaul covers: @@ -2885,14 +3071,14 @@ Zone Asia/Omsk 4:53:30 - LMT 1919 Nov 14 # http://publication.pravo.gov.ru/Document/View/0001201603090038 Zone Asia/Barnaul 5:35:00 - LMT 1919 Dec 10 - 6:00 - +06 1930 Jun 21 - 7:00 Russia +07/+08 1991 Mar 31 2:00s - 6:00 Russia +06/+07 1992 Jan 19 2:00s - 7:00 Russia +07/+08 1995 May 28 - 6:00 Russia +06/+07 2011 Mar 27 2:00s - 7:00 - +07 2014 Oct 26 2:00s - 6:00 - +06 2016 Mar 27 2:00s - 7:00 - +07 + 6:00 - %z 1930 Jun 21 + 7:00 Russia %z 1991 Mar 31 2:00s + 6:00 Russia %z 1992 Jan 19 2:00s + 7:00 Russia %z 1995 May 28 + 6:00 Russia %z 2011 Mar 27 2:00s + 7:00 - %z 2014 Oct 26 2:00s + 6:00 - %z 2016 Mar 27 2:00s + 7:00 - %z # From Paul Eggert (2016-03-18): # Asia/Novosibirsk covers: @@ -2906,14 +3092,14 @@ Zone Asia/Barnaul 5:35:00 - LMT 1919 Dec 10 # http://publication.pravo.gov.ru/Document/View/0001201607040064 Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00 - 6:00 - +06 1930 Jun 21 - 7:00 Russia +07/+08 1991 Mar 31 2:00s - 6:00 Russia +06/+07 1992 Jan 19 2:00s - 7:00 Russia +07/+08 1993 May 23 # say Shanks & P. - 6:00 Russia +06/+07 2011 Mar 27 2:00s - 7:00 - +07 2014 Oct 26 2:00s - 6:00 - +06 2016 Jul 24 2:00s - 7:00 - +07 + 6:00 - %z 1930 Jun 21 + 7:00 Russia %z 1991 Mar 31 2:00s + 6:00 Russia %z 1992 Jan 19 2:00s + 7:00 Russia %z 1993 May 23 # say Shanks & P. + 6:00 Russia %z 2011 Mar 27 2:00s + 7:00 - %z 2014 Oct 26 2:00s + 6:00 - %z 2016 Jul 24 2:00s + 7:00 - %z # From Paul Eggert (2016-03-18): # Asia/Tomsk covers: @@ -2958,14 +3144,14 @@ Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00 # http://publication.pravo.gov.ru/Document/View/0001201604260048 Zone Asia/Tomsk 5:39:51 - LMT 1919 Dec 22 - 6:00 - +06 1930 Jun 21 - 7:00 Russia +07/+08 1991 Mar 31 2:00s - 6:00 Russia +06/+07 1992 Jan 19 2:00s - 7:00 Russia +07/+08 2002 May 1 3:00 - 6:00 Russia +06/+07 2011 Mar 27 2:00s - 7:00 - +07 2014 Oct 26 2:00s - 6:00 - +06 2016 May 29 2:00s - 7:00 - +07 + 6:00 - %z 1930 Jun 21 + 7:00 Russia %z 1991 Mar 31 2:00s + 6:00 Russia %z 1992 Jan 19 2:00s + 7:00 Russia %z 2002 May 1 3:00 + 6:00 Russia %z 2011 Mar 27 2:00s + 7:00 - %z 2014 Oct 26 2:00s + 6:00 - %z 2016 May 29 2:00s + 7:00 - %z # From Tim Parenti (2014-07-03): @@ -2996,12 +3182,12 @@ Zone Asia/Tomsk 5:39:51 - LMT 1919 Dec 22 # realigning itself with KRAT. Zone Asia/Novokuznetsk 5:48:48 - LMT 1924 May 1 - 6:00 - +06 1930 Jun 21 - 7:00 Russia +07/+08 1991 Mar 31 2:00s - 6:00 Russia +06/+07 1992 Jan 19 2:00s - 7:00 Russia +07/+08 2010 Mar 28 2:00s - 6:00 Russia +06/+07 2011 Mar 27 2:00s - 7:00 - +07 + 6:00 - %z 1930 Jun 21 + 7:00 Russia %z 1991 Mar 31 2:00s + 6:00 Russia %z 1992 Jan 19 2:00s + 7:00 Russia %z 2010 Mar 28 2:00s + 6:00 Russia %z 2011 Mar 27 2:00s + 7:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): # Asia/Krasnoyarsk covers... @@ -3015,12 +3201,12 @@ Zone Asia/Novokuznetsk 5:48:48 - LMT 1924 May 1 # Byalokoz 1919 says Krasnoyarsk was 6:11:26. Zone Asia/Krasnoyarsk 6:11:26 - LMT 1920 Jan 6 - 6:00 - +06 1930 Jun 21 - 7:00 Russia +07/+08 1991 Mar 31 2:00s - 6:00 Russia +06/+07 1992 Jan 19 2:00s - 7:00 Russia +07/+08 2011 Mar 27 2:00s - 8:00 - +08 2014 Oct 26 2:00s - 7:00 - +07 + 6:00 - %z 1930 Jun 21 + 7:00 Russia %z 1991 Mar 31 2:00s + 6:00 Russia %z 1992 Jan 19 2:00s + 7:00 Russia %z 2011 Mar 27 2:00s + 8:00 - %z 2014 Oct 26 2:00s + 7:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -3037,12 +3223,12 @@ Zone Asia/Krasnoyarsk 6:11:26 - LMT 1920 Jan 6 Zone Asia/Irkutsk 6:57:05 - LMT 1880 6:57:05 - IMT 1920 Jan 25 # Irkutsk Mean Time - 7:00 - +07 1930 Jun 21 - 8:00 Russia +08/+09 1991 Mar 31 2:00s - 7:00 Russia +07/+08 1992 Jan 19 2:00s - 8:00 Russia +08/+09 2011 Mar 27 2:00s - 9:00 - +09 2014 Oct 26 2:00s - 8:00 - +08 + 7:00 - %z 1930 Jun 21 + 8:00 Russia %z 1991 Mar 31 2:00s + 7:00 Russia %z 1992 Jan 19 2:00s + 8:00 Russia %z 2011 Mar 27 2:00s + 9:00 - %z 2014 Oct 26 2:00s + 8:00 - %z # From Tim Parenti (2014-07-06): @@ -3059,13 +3245,13 @@ Zone Asia/Irkutsk 6:57:05 - LMT 1880 # http://publication.pravo.gov.ru/Document/View/0001201512300107 Zone Asia/Chita 7:33:52 - LMT 1919 Dec 15 - 8:00 - +08 1930 Jun 21 - 9:00 Russia +09/+10 1991 Mar 31 2:00s - 8:00 Russia +08/+09 1992 Jan 19 2:00s - 9:00 Russia +09/+10 2011 Mar 27 2:00s - 10:00 - +10 2014 Oct 26 2:00s - 8:00 - +08 2016 Mar 27 2:00 - 9:00 - +09 + 8:00 - %z 1930 Jun 21 + 9:00 Russia %z 1991 Mar 31 2:00s + 8:00 Russia %z 1992 Jan 19 2:00s + 9:00 Russia %z 2011 Mar 27 2:00s + 10:00 - %z 2014 Oct 26 2:00s + 8:00 - %z 2016 Mar 27 2:00 + 9:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -3105,12 +3291,12 @@ Zone Asia/Chita 7:33:52 - LMT 1919 Dec 15 # Byalokoz 1919 says Yakutsk was 8:38:58. Zone Asia/Yakutsk 8:38:58 - LMT 1919 Dec 15 - 8:00 - +08 1930 Jun 21 - 9:00 Russia +09/+10 1991 Mar 31 2:00s - 8:00 Russia +08/+09 1992 Jan 19 2:00s - 9:00 Russia +09/+10 2011 Mar 27 2:00s - 10:00 - +10 2014 Oct 26 2:00s - 9:00 - +09 + 8:00 - %z 1930 Jun 21 + 9:00 Russia %z 1991 Mar 31 2:00s + 8:00 Russia %z 1992 Jan 19 2:00s + 9:00 Russia %z 2011 Mar 27 2:00s + 10:00 - %z 2014 Oct 26 2:00s + 9:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -3128,12 +3314,12 @@ Zone Asia/Yakutsk 8:38:58 - LMT 1919 Dec 15 # Go with Byalokoz. Zone Asia/Vladivostok 8:47:31 - LMT 1922 Nov 15 - 9:00 - +09 1930 Jun 21 - 10:00 Russia +10/+11 1991 Mar 31 2:00s - 9:00 Russia +09/+10 1992 Jan 19 2:00s - 10:00 Russia +10/+11 2011 Mar 27 2:00s - 11:00 - +11 2014 Oct 26 2:00s - 10:00 - +10 + 9:00 - %z 1930 Jun 21 + 10:00 Russia %z 1991 Mar 31 2:00s + 9:00 Russia %z 1992 Jan 19 2:00s + 10:00 Russia %z 2011 Mar 27 2:00s + 11:00 - %z 2014 Oct 26 2:00s + 10:00 - %z # From Tim Parenti (2014-07-03): @@ -3151,14 +3337,14 @@ Zone Asia/Vladivostok 8:47:31 - LMT 1922 Nov 15 # This transition is no doubt wrong, but we have no better info. Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15 - 8:00 - +08 1930 Jun 21 - 9:00 Russia +09/+10 1991 Mar 31 2:00s - 8:00 Russia +08/+09 1992 Jan 19 2:00s - 9:00 Russia +09/+10 2004 - 10:00 Russia +10/+11 2011 Mar 27 2:00s - 11:00 - +11 2011 Sep 13 0:00s # Decree 725? - 10:00 - +10 2014 Oct 26 2:00s - 9:00 - +09 + 8:00 - %z 1930 Jun 21 + 9:00 Russia %z 1991 Mar 31 2:00s + 8:00 Russia %z 1992 Jan 19 2:00s + 9:00 Russia %z 2004 + 10:00 Russia %z 2011 Mar 27 2:00s + 11:00 - %z 2011 Sep 13 0:00s # Decree 725? + 10:00 - %z 2014 Oct 26 2:00s + 9:00 - %z # From Tim Parenti (2014-07-03): @@ -3174,14 +3360,14 @@ Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15 # The Zone name should be Asia/Yuzhno-Sakhalinsk, but that's too long. Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23 - 9:00 - +09 1945 Aug 25 - 11:00 Russia +11/+12 1991 Mar 31 2:00s # Sakhalin T - 10:00 Russia +10/+11 1992 Jan 19 2:00s - 11:00 Russia +11/+12 1997 Mar lastSun 2:00s - 10:00 Russia +10/+11 2011 Mar 27 2:00s - 11:00 - +11 2014 Oct 26 2:00s - 10:00 - +10 2016 Mar 27 2:00s - 11:00 - +11 + 9:00 - %z 1945 Aug 25 + 11:00 Russia %z 1991 Mar 31 2:00s # Sakhalin T + 10:00 Russia %z 1992 Jan 19 2:00s + 11:00 Russia %z 1997 Mar lastSun 2:00s + 10:00 Russia %z 2011 Mar 27 2:00s + 11:00 - %z 2014 Oct 26 2:00s + 10:00 - %z 2016 Mar 27 2:00s + 11:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -3204,13 +3390,13 @@ Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23 # http://publication.pravo.gov.ru/Document/View/0001201604050038 Zone Asia/Magadan 10:03:12 - LMT 1924 May 2 - 10:00 - +10 1930 Jun 21 # Magadan Time - 11:00 Russia +11/+12 1991 Mar 31 2:00s - 10:00 Russia +10/+11 1992 Jan 19 2:00s - 11:00 Russia +11/+12 2011 Mar 27 2:00s - 12:00 - +12 2014 Oct 26 2:00s - 10:00 - +10 2016 Apr 24 2:00s - 11:00 - +11 + 10:00 - %z 1930 Jun 21 # Magadan Time + 11:00 Russia %z 1991 Mar 31 2:00s + 10:00 Russia %z 1992 Jan 19 2:00s + 11:00 Russia %z 2011 Mar 27 2:00s + 12:00 - %z 2014 Oct 26 2:00s + 10:00 - %z 2016 Apr 24 2:00s + 11:00 - %z # From Tim Parenti (2014-07-06): @@ -3255,12 +3441,12 @@ Zone Asia/Magadan 10:03:12 - LMT 1924 May 2 # Go with Srednekolymsk. Zone Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 - 10:00 - +10 1930 Jun 21 - 11:00 Russia +11/+12 1991 Mar 31 2:00s - 10:00 Russia +10/+11 1992 Jan 19 2:00s - 11:00 Russia +11/+12 2011 Mar 27 2:00s - 12:00 - +12 2014 Oct 26 2:00s - 11:00 - +11 + 10:00 - %z 1930 Jun 21 + 11:00 Russia %z 1991 Mar 31 2:00s + 10:00 Russia %z 1992 Jan 19 2:00s + 11:00 Russia %z 2011 Mar 27 2:00s + 12:00 - %z 2014 Oct 26 2:00s + 11:00 - %z # From Tim Parenti (2014-07-03): @@ -3278,14 +3464,14 @@ Zone Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 # UTC+12 since at least then, too. Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15 - 8:00 - +08 1930 Jun 21 - 9:00 Russia +09/+10 1981 Apr 1 - 11:00 Russia +11/+12 1991 Mar 31 2:00s - 10:00 Russia +10/+11 1992 Jan 19 2:00s - 11:00 Russia +11/+12 2011 Mar 27 2:00s - 12:00 - +12 2011 Sep 13 0:00s # Decree 725? - 11:00 - +11 2014 Oct 26 2:00s - 10:00 - +10 + 8:00 - %z 1930 Jun 21 + 9:00 Russia %z 1981 Apr 1 + 11:00 Russia %z 1991 Mar 31 2:00s + 10:00 Russia %z 1992 Jan 19 2:00s + 11:00 Russia %z 2011 Mar 27 2:00s + 12:00 - %z 2011 Sep 13 0:00s # Decree 725? + 11:00 - %z 2014 Oct 26 2:00s + 10:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -3298,12 +3484,12 @@ Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15 # The Zone name should be Asia/Petropavlovsk-Kamchatski or perhaps # Asia/Petropavlovsk-Kamchatsky, but these are too long. Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10 - 11:00 - +11 1930 Jun 21 - 12:00 Russia +12/+13 1991 Mar 31 2:00s - 11:00 Russia +11/+12 1992 Jan 19 2:00s - 12:00 Russia +12/+13 2010 Mar 28 2:00s - 11:00 Russia +11/+12 2011 Mar 27 2:00s - 12:00 - +12 + 11:00 - %z 1930 Jun 21 + 12:00 Russia %z 1991 Mar 31 2:00s + 11:00 Russia %z 1992 Jan 19 2:00s + 12:00 Russia %z 2010 Mar 28 2:00s + 11:00 Russia %z 2011 Mar 27 2:00s + 12:00 - %z # From Tim Parenti (2014-07-03): @@ -3311,13 +3497,13 @@ Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10 # 87 RU-CHU Chukotka Autonomous Okrug Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2 - 12:00 - +12 1930 Jun 21 - 13:00 Russia +13/+14 1982 Apr 1 0:00s - 12:00 Russia +12/+13 1991 Mar 31 2:00s - 11:00 Russia +11/+12 1992 Jan 19 2:00s - 12:00 Russia +12/+13 2010 Mar 28 2:00s - 11:00 Russia +11/+12 2011 Mar 27 2:00s - 12:00 - +12 + 12:00 - %z 1930 Jun 21 + 13:00 Russia %z 1982 Apr 1 0:00s + 12:00 Russia %z 1991 Mar 31 2:00s + 11:00 Russia %z 1992 Jan 19 2:00s + 12:00 Russia %z 2010 Mar 28 2:00s + 11:00 Russia %z 2011 Mar 27 2:00s + 12:00 - %z # Bosnia & Herzegovina # Croatia @@ -3436,7 +3622,7 @@ Zone Africa/Ceuta -0:21:16 - LMT 1901 Jan 1 0:00u 1:00 - CET 1986 1:00 EU CE%sT Zone Atlantic/Canary -1:01:36 - LMT 1922 Mar # Las Palmas de Gran C. - -1:00 - -01 1946 Sep 30 1:00 + -1:00 - %z 1946 Sep 30 1:00 0:00 - WET 1980 Apr 6 0:00s 0:00 1:00 WEST 1980 Sep 28 1:00u 0:00 EU WE%sT @@ -3517,8 +3703,8 @@ Zone Atlantic/Canary -1:01:36 - LMT 1922 Mar # Las Palmas de Gran C. # but if no one is present after 11 at night, could be postponed until one # hour before the beginning of service. -# From Paul Eggert (2013-09-11): -# Round BMT to the nearest even second, 0:29:46. +# From Paul Eggert (2024-05-24): +# Express BMT as 0:29:45.500, approximately the same precision 7° 26' 22.50". # # We can find no reliable source for Shanks's assertion that all of Switzerland # except Geneva switched to Bern Mean Time at 00:00 on 1848-09-12. This book: @@ -3557,6 +3743,7 @@ Rule Swiss 1941 1942 - May Mon>=1 1:00 1:00 S Rule Swiss 1941 1942 - Oct Mon>=1 2:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16 # See above comment. + #STDOFF 0:29:45.500 0:29:46 - BMT 1894 Jun # Bern Mean Time 1:00 Swiss CE%sT 1981 1:00 EU CE%sT @@ -3754,7 +3941,7 @@ Rule Turkey 1996 2006 - Oct lastSun 1:00s 0 - Zone Europe/Istanbul 1:55:52 - LMT 1880 1:56:56 - IMT 1910 Oct # Istanbul Mean Time? 2:00 Turkey EE%sT 1978 Jun 29 - 3:00 Turkey +03/+04 1984 Nov 1 2:00 + 3:00 Turkey %z 1984 Nov 1 2:00 2:00 Turkey EE%sT 2007 2:00 EU EE%sT 2011 Mar 27 1:00u 2:00 - EET 2011 Mar 28 1:00u @@ -3763,7 +3950,7 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880 2:00 EU EE%sT 2015 Oct 25 1:00u 2:00 1:00 EEST 2015 Nov 8 1:00u 2:00 EU EE%sT 2016 Sep 7 - 3:00 - +03 + 3:00 - %z # Ukraine # diff --git a/src/java.base/share/data/tzdata/leapseconds b/src/java.base/share/data/tzdata/leapseconds index 8e7df3de984fb..63a76620dbfed 100644 --- a/src/java.base/share/data/tzdata/leapseconds +++ b/src/java.base/share/data/tzdata/leapseconds @@ -92,11 +92,11 @@ Leap 2016 Dec 31 23:59:60 + S # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2024 Dec 28 00:00:00 +#Expires 2025 Jun 28 00:00:00 # POSIX timestamps for the data in this file: -#updated 1704708379 (2024-01-08 10:06:19 UTC) -#expires 1735344000 (2024-12-28 00:00:00 UTC) +#updated 1720104763 (2024-07-04 14:52:43 UTC) +#expires 1751068800 (2025-06-28 00:00:00 UTC) # Updated through IERS Bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat) -# File expires on 28 December 2024 +# File expires on 28 June 2025 diff --git a/src/java.base/share/data/tzdata/northamerica b/src/java.base/share/data/tzdata/northamerica index a8b2ef3f7fa5f..c95e7d0e643e7 100644 --- a/src/java.base/share/data/tzdata/northamerica +++ b/src/java.base/share/data/tzdata/northamerica @@ -208,26 +208,6 @@ Rule US 1987 2006 - Apr Sun>=1 2:00 1:00 D Rule US 2007 max - Mar Sun>=8 2:00 1:00 D Rule US 2007 max - Nov Sun>=1 2:00 0 S -# From Arthur David Olson, 2005-12-19 -# We generate the files specified below to guard against old files with -# obsolete information being left in the time zone binary directory. -# We limit the list to names that have appeared in previous versions of -# this time zone package. -# We do these as separate Zones rather than as Links to avoid problems if -# a particular place changes whether it observes DST. -# We put these specifications here in the northamerica file both to -# increase the chances that they'll actually get compiled and to -# avoid the need to duplicate the US rules in another file. - -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone EST -5:00 - EST -Zone MST -7:00 - MST -Zone HST -10:00 - HST -Zone EST5EDT -5:00 US E%sT -Zone CST6CDT -6:00 US C%sT -Zone MST7MDT -7:00 US M%sT -Zone PST8PDT -8:00 US P%sT - # From U. S. Naval Observatory (1989-01-19): # USA EASTERN 5 H BEHIND UTC NEW YORK, WASHINGTON # USA EASTERN 4 H BEHIND UTC APR 3 - OCT 30 @@ -2396,6 +2376,81 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 # the researchers who prepared the Decrees page failed to find some of # the relevant documents. +# From Heitor David Pinto (2024-08-04): +# In 1931, the decree implementing DST specified that it would take +# effect on 30 April.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=192270&pagina=2&seccion=1 +# +# In 1981, the decree changing Campeche, Yucatán and Quintana Roo to UTC-5 +# specified that it would enter into force on 26 December 1981 at 2:00.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4705667&fecha=23/12/1981&cod_diario=202796 +# +# In 1982, the decree returning Campeche and Yucatán to UTC-6 specified that +# it would enter into force on 2 November 1982 at 2:00.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=205689&pagina=3&seccion=0 +# +# Quintana Roo changed to UTC-6 on 4 January 1983 at 0:00, and again +# to UTC-5 on 26 October 1997 at 2:00.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4787355&fecha=28/12/1982&cod_diario=206112 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=209559&pagina=15&seccion=0 +# +# Durango, Coahuila, Nuevo León and Tamaulipas were set to UTC-7 on 1 January +# 1922, and changed to UTC-6 on 10 June 1927. Then Durango, Coahuila and +# Nuevo León (but not Tamaulipas) returned to UTC-7 on 15 November 1930, +# observed DST in 1931, and changed again to UTC-6 on 1 April 1932.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4441846&fecha=29/12/1921&cod_diario=187468 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4541520&fecha=09/06/1927&cod_diario=193920 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4491963&fecha=15/11/1930&cod_diario=190835 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4418437&fecha=21/01/1932&cod_diario=185588 +# +# ... the ... 10 June 1927 ... decree only said 10 June 1927, without +# specifying a time, so I suppose that it should be considered at 0:00. +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4541520&fecha=09/06/1927&cod_diario=193920 +# +# In 1942, the decree changing Baja California, Baja California Sur, Sonora, +# Sinaloa and Nayarit to UTC-7 was published on 24 April, but it said that it +# would apply from 1 April, so it's unclear when the change actually +# occurred. The database currently shows 24 April 1942. +# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=192203&pagina=2&seccion=1 +# +# Baja California Sur, Sonora, Sinaloa and Nayarit never used UTC-8. The ... +# 14 January 1949 ... change [to UTC-8] only occurred in Baja California. +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4515613&fecha=13/01/1949&cod_diario=192309 +# +# In 1945, the decree changing Baja California to UTC-8 specified that it +# would take effect on the third day from its publication. +# It was published on 12 November, so it would take effect on 15 November.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4555049&fecha=12/11/1945&cod_diario=194763 +# +# In 1948, the decree changing Baja California to UTC-7 specified that it +# would take effect on "this date". The decree was made on 13 March, +# but published on 5 April, so it's unclear when the change actually occurred. +# The database currently shows 5 April 1948. +# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=188624&pagina=2&seccion=0 +# +# In 1949, the decree changing Baja California to UTC-8 was published on 13 +# January, but it said that it would apply from 1 January, so it's unclear when +# the change actually occurred. The database currently shows 14 January 1949. +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4515613&fecha=13/01/1949&cod_diario=192309 +# +# Baja California also observed UTC-7 from 1 May to 24 September 1950, +# from 29 April to 30 September 1951 at 2:00, +# and from 27 April to 28 September 1952 at 2:00.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4600403&fecha=29/04/1950&cod_diario=197505 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4623553&fecha=23/09/1950&cod_diario=198805 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4469444&fecha=27/04/1951&cod_diario=189317 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4533868&fecha=10/03/1952&cod_diario=193465 +# +# All changes in Baja California from 1948 to 1952 match those in California, +# on the same dates or with a difference of one day. +# So it may be easier to implement these changes as DST with rule CA +# during this whole period. +# +# From Paul Eggert (2024-08-18): +# For now, maintain the slightly-different history for Baja California, +# as we have no information on whether 1948/1952 clocks in Tijuana followed +# the decrees or followed San Diego. + # From Alan Perry (1996-02-15): # A guy from our Mexico subsidiary finally found the Presidential Decree # outlining the timezone changes in Mexico. @@ -2599,7 +2654,7 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 # http://puentelibre.mx/noticia/ciudad_juarez_cambio_horario_noviembre_2022/ # Rule NAME FROM TO - IN ON AT SAVE LETTER/S -Rule Mexico 1931 only - May 1 23:00 1:00 D +Rule Mexico 1931 only - April 30 0:00 1:00 D Rule Mexico 1931 only - Oct 1 0:00 0 S Rule Mexico 1939 only - Feb 5 0:00 1:00 D Rule Mexico 1939 only - Jun 25 0:00 0 S @@ -2618,14 +2673,16 @@ Rule Mexico 2002 2022 - Oct lastSun 2:00 0 S # Zone NAME STDOFF RULES FORMAT [UNTIL] # Quintana Roo; represented by Cancún Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 6:00u - -6:00 - CST 1981 Dec 23 + -6:00 - CST 1981 Dec 26 2:00 + -5:00 - EST 1983 Jan 4 0:00 + -6:00 Mexico C%sT 1997 Oct 26 2:00 -5:00 Mexico E%sT 1998 Aug 2 2:00 -6:00 Mexico C%sT 2015 Feb 1 2:00 -5:00 - EST # Campeche, Yucatán; represented by Mérida Zone America/Merida -5:58:28 - LMT 1922 Jan 1 6:00u - -6:00 - CST 1981 Dec 23 - -5:00 - EST 1982 Dec 2 + -6:00 - CST 1981 Dec 26 2:00 + -5:00 - EST 1982 Nov 2 2:00 -6:00 Mexico C%sT # Coahuila, Nuevo León, Tamaulipas (near US border) # This includes the following municipios: @@ -2642,12 +2699,15 @@ Zone America/Matamoros -6:30:00 - LMT 1922 Jan 1 6:00u -6:00 US C%sT # Durango; Coahuila, Nuevo León, Tamaulipas (away from US border) Zone America/Monterrey -6:41:16 - LMT 1922 Jan 1 6:00u + -7:00 - MST 1927 Jun 10 + -6:00 - CST 1930 Nov 15 + -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1988 -6:00 US C%sT 1989 -6:00 Mexico C%sT # Central Mexico Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 Mexico C%sT 2001 Sep 30 2:00 @@ -2658,7 +2718,7 @@ Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u # Práxedis G Guerrero. # http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1996 @@ -2673,7 +2733,7 @@ Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u # Benavides. # http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1996 @@ -2685,7 +2745,7 @@ Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u -6:00 US C%sT # Chihuahua (away from US border) Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1996 @@ -2695,23 +2755,21 @@ Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u -6:00 - CST # Sonora Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1942 Apr 24 - -7:00 - MST 1949 Jan 14 - -8:00 - PST 1970 + -7:00 - MST 1996 -7:00 Mexico M%sT 1999 -7:00 - MST # Baja California Sur, Nayarit (except Bahía de Banderas), Sinaloa Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1942 Apr 24 - -7:00 - MST 1949 Jan 14 - -8:00 - PST 1970 + -7:00 - MST 1970 -7:00 Mexico M%sT # Bahía de Banderas @@ -2744,27 +2802,32 @@ Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u # Use "Bahia_Banderas" to keep the name to fourteen characters. Zone America/Bahia_Banderas -7:01:00 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1942 Apr 24 - -7:00 - MST 1949 Jan 14 - -8:00 - PST 1970 + -7:00 - MST 1970 -7:00 Mexico M%sT 2010 Apr 4 2:00 -6:00 Mexico C%sT # Baja California Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 7:00u -7:00 - MST 1924 - -8:00 - PST 1927 Jun 10 23:00 + -8:00 - PST 1927 Jun 10 -7:00 - MST 1930 Nov 15 -8:00 - PST 1931 Apr 1 -8:00 1:00 PDT 1931 Sep 30 -8:00 - PST 1942 Apr 24 -8:00 1:00 PWT 1945 Aug 14 23:00u - -8:00 1:00 PPT 1945 Nov 12 # Peace + -8:00 1:00 PPT 1945 Nov 15 # Peace -8:00 - PST 1948 Apr 5 -8:00 1:00 PDT 1949 Jan 14 + -8:00 - PST 1950 May 1 + -8:00 1:00 PDT 1950 Sep 24 + -8:00 - PST 1951 Apr 29 2:00 + -8:00 1:00 PDT 1951 Sep 30 2:00 + -8:00 - PST 1952 Apr 27 2:00 + -8:00 1:00 PDT 1952 Sep 28 2:00 -8:00 - PST 1954 -8:00 CA P%sT 1961 -8:00 - PST 1976 @@ -3573,8 +3636,8 @@ Zone America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12:00 # San Juan # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Miquelon -3:44:40 - LMT 1911 Jun 15 # St Pierre -4:00 - AST 1980 May - -3:00 - -03 1987 - -3:00 Canada -03/-02 + -3:00 - %z 1987 + -3:00 Canada %z # Turks and Caicos # diff --git a/src/java.base/share/data/tzdata/southamerica b/src/java.base/share/data/tzdata/southamerica index d77acc088570b..3824202546afa 100644 --- a/src/java.base/share/data/tzdata/southamerica +++ b/src/java.base/share/data/tzdata/southamerica @@ -425,11 +425,11 @@ Rule Arg 2008 only - Oct Sun>=15 0:00 1:00 - Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May # Córdoba Mean Time - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 Arg -03/-02 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 Arg %z # # Córdoba (CB), Santa Fe (SF), Entre Ríos (ER), Corrientes (CN), Misiones (MN), # Chaco (CC), Formosa (FM), Santiago del Estero (SE) @@ -444,120 +444,120 @@ Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 Zone America/Argentina/Cordoba -4:16:48 - LMT 1894 Oct 31 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 3 - -4:00 - -04 1991 Oct 20 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 Arg -03/-02 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 3 + -4:00 - %z 1991 Oct 20 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 Arg %z # # Salta (SA), La Pampa (LP), Neuquén (NQ), Rio Negro (RN) Zone America/Argentina/Salta -4:21:40 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 3 - -4:00 - -04 1991 Oct 20 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 3 + -4:00 - %z 1991 Oct 20 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # Tucumán (TM) Zone America/Argentina/Tucuman -4:20:52 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 3 - -4:00 - -04 1991 Oct 20 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 Jun 1 - -4:00 - -04 2004 Jun 13 - -3:00 Arg -03/-02 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 3 + -4:00 - %z 1991 Oct 20 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 Jun 1 + -4:00 - %z 2004 Jun 13 + -3:00 Arg %z # # La Rioja (LR) Zone America/Argentina/La_Rioja -4:27:24 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 1 - -4:00 - -04 1991 May 7 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 Jun 1 - -4:00 - -04 2004 Jun 20 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 1 + -4:00 - %z 1991 May 7 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 Jun 1 + -4:00 - %z 2004 Jun 20 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # San Juan (SJ) Zone America/Argentina/San_Juan -4:34:04 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 1 - -4:00 - -04 1991 May 7 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 May 31 - -4:00 - -04 2004 Jul 25 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 1 + -4:00 - %z 1991 May 7 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 May 31 + -4:00 - %z 2004 Jul 25 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # Jujuy (JY) Zone America/Argentina/Jujuy -4:21:12 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1990 Mar 4 - -4:00 - -04 1990 Oct 28 - -4:00 1:00 -03 1991 Mar 17 - -4:00 - -04 1991 Oct 6 - -3:00 1:00 -02 1992 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1990 Mar 4 + -4:00 - %z 1990 Oct 28 + -4:00 1:00 %z 1991 Mar 17 + -4:00 - %z 1991 Oct 6 + -3:00 1:00 %z 1992 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # Catamarca (CT), Chubut (CH) Zone America/Argentina/Catamarca -4:23:08 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 3 - -4:00 - -04 1991 Oct 20 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 Jun 1 - -4:00 - -04 2004 Jun 20 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 3 + -4:00 - %z 1991 Oct 20 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 Jun 1 + -4:00 - %z 2004 Jun 20 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # Mendoza (MZ) Zone America/Argentina/Mendoza -4:35:16 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1990 Mar 4 - -4:00 - -04 1990 Oct 15 - -4:00 1:00 -03 1991 Mar 1 - -4:00 - -04 1991 Oct 15 - -4:00 1:00 -03 1992 Mar 1 - -4:00 - -04 1992 Oct 18 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 May 23 - -4:00 - -04 2004 Sep 26 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1990 Mar 4 + -4:00 - %z 1990 Oct 15 + -4:00 1:00 %z 1991 Mar 1 + -4:00 - %z 1991 Oct 15 + -4:00 1:00 %z 1992 Mar 1 + -4:00 - %z 1992 Oct 18 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 May 23 + -4:00 - %z 2004 Sep 26 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # San Luis (SL) @@ -567,53 +567,53 @@ Rule SanLuis 2007 2008 - Oct Sun>=8 0:00 1:00 - Zone America/Argentina/San_Luis -4:25:24 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1990 - -3:00 1:00 -02 1990 Mar 14 - -4:00 - -04 1990 Oct 15 - -4:00 1:00 -03 1991 Mar 1 - -4:00 - -04 1991 Jun 1 - -3:00 - -03 1999 Oct 3 - -4:00 1:00 -03 2000 Mar 3 - -3:00 - -03 2004 May 31 - -4:00 - -04 2004 Jul 25 - -3:00 Arg -03/-02 2008 Jan 21 - -4:00 SanLuis -04/-03 2009 Oct 11 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1990 + -3:00 1:00 %z 1990 Mar 14 + -4:00 - %z 1990 Oct 15 + -4:00 1:00 %z 1991 Mar 1 + -4:00 - %z 1991 Jun 1 + -3:00 - %z 1999 Oct 3 + -4:00 1:00 %z 2000 Mar 3 + -3:00 - %z 2004 May 31 + -4:00 - %z 2004 Jul 25 + -3:00 Arg %z 2008 Jan 21 + -4:00 SanLuis %z 2009 Oct 11 + -3:00 - %z # # Santa Cruz (SC) Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 Jun 1 - -4:00 - -04 2004 Jun 20 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 Jun 1 + -4:00 - %z 2004 Jun 20 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # Tierra del Fuego, Antártida e Islas del Atlántico Sur (TF) Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 May 30 - -4:00 - -04 2004 Jun 20 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 May 30 + -4:00 - %z 2004 Jun 20 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # Bolivia # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/La_Paz -4:32:36 - LMT 1890 -4:32:36 - CMT 1931 Oct 15 # Calamarca MT -4:32:36 1:00 BST 1932 Mar 21 # Bolivia ST - -4:00 - -04 + -4:00 - %z # Brazil @@ -984,12 +984,12 @@ Rule Brazil 2018 only - Nov Sun>=1 0:00 1:00 - # # Fernando de Noronha (administratively part of PE) Zone America/Noronha -2:09:40 - LMT 1914 - -2:00 Brazil -02/-01 1990 Sep 17 - -2:00 - -02 1999 Sep 30 - -2:00 Brazil -02/-01 2000 Oct 15 - -2:00 - -02 2001 Sep 13 - -2:00 Brazil -02/-01 2002 Oct 1 - -2:00 - -02 + -2:00 Brazil %z 1990 Sep 17 + -2:00 - %z 1999 Sep 30 + -2:00 Brazil %z 2000 Oct 15 + -2:00 - %z 2001 Sep 13 + -2:00 Brazil %z 2002 Oct 1 + -2:00 - %z # Other Atlantic islands have no permanent settlement. # These include Trindade and Martim Vaz (administratively part of ES), # Rocas Atoll (RN), and the St Peter and St Paul Archipelago (PE). @@ -1002,119 +1002,119 @@ Zone America/Noronha -2:09:40 - LMT 1914 # In the north a very small part from the river Javary (now Jari I guess, # the border with Amapá) to the Amazon, then to the Xingu. Zone America/Belem -3:13:56 - LMT 1914 - -3:00 Brazil -03/-02 1988 Sep 12 - -3:00 - -03 + -3:00 Brazil %z 1988 Sep 12 + -3:00 - %z # # west Pará (PA) # West Pará includes Altamira, Óbidos, Prainha, Oriximiná, and Santarém. Zone America/Santarem -3:38:48 - LMT 1914 - -4:00 Brazil -04/-03 1988 Sep 12 - -4:00 - -04 2008 Jun 24 0:00 - -3:00 - -03 + -4:00 Brazil %z 1988 Sep 12 + -4:00 - %z 2008 Jun 24 0:00 + -3:00 - %z # # Maranhão (MA), Piauí (PI), Ceará (CE), Rio Grande do Norte (RN), # Paraíba (PB) Zone America/Fortaleza -2:34:00 - LMT 1914 - -3:00 Brazil -03/-02 1990 Sep 17 - -3:00 - -03 1999 Sep 30 - -3:00 Brazil -03/-02 2000 Oct 22 - -3:00 - -03 2001 Sep 13 - -3:00 Brazil -03/-02 2002 Oct 1 - -3:00 - -03 + -3:00 Brazil %z 1990 Sep 17 + -3:00 - %z 1999 Sep 30 + -3:00 Brazil %z 2000 Oct 22 + -3:00 - %z 2001 Sep 13 + -3:00 Brazil %z 2002 Oct 1 + -3:00 - %z # # Pernambuco (PE) (except Atlantic islands) Zone America/Recife -2:19:36 - LMT 1914 - -3:00 Brazil -03/-02 1990 Sep 17 - -3:00 - -03 1999 Sep 30 - -3:00 Brazil -03/-02 2000 Oct 15 - -3:00 - -03 2001 Sep 13 - -3:00 Brazil -03/-02 2002 Oct 1 - -3:00 - -03 + -3:00 Brazil %z 1990 Sep 17 + -3:00 - %z 1999 Sep 30 + -3:00 Brazil %z 2000 Oct 15 + -3:00 - %z 2001 Sep 13 + -3:00 Brazil %z 2002 Oct 1 + -3:00 - %z # # Tocantins (TO) Zone America/Araguaina -3:12:48 - LMT 1914 - -3:00 Brazil -03/-02 1990 Sep 17 - -3:00 - -03 1995 Sep 14 - -3:00 Brazil -03/-02 2003 Sep 24 - -3:00 - -03 2012 Oct 21 - -3:00 Brazil -03/-02 2013 Sep - -3:00 - -03 + -3:00 Brazil %z 1990 Sep 17 + -3:00 - %z 1995 Sep 14 + -3:00 Brazil %z 2003 Sep 24 + -3:00 - %z 2012 Oct 21 + -3:00 Brazil %z 2013 Sep + -3:00 - %z # # Alagoas (AL), Sergipe (SE) Zone America/Maceio -2:22:52 - LMT 1914 - -3:00 Brazil -03/-02 1990 Sep 17 - -3:00 - -03 1995 Oct 13 - -3:00 Brazil -03/-02 1996 Sep 4 - -3:00 - -03 1999 Sep 30 - -3:00 Brazil -03/-02 2000 Oct 22 - -3:00 - -03 2001 Sep 13 - -3:00 Brazil -03/-02 2002 Oct 1 - -3:00 - -03 + -3:00 Brazil %z 1990 Sep 17 + -3:00 - %z 1995 Oct 13 + -3:00 Brazil %z 1996 Sep 4 + -3:00 - %z 1999 Sep 30 + -3:00 Brazil %z 2000 Oct 22 + -3:00 - %z 2001 Sep 13 + -3:00 Brazil %z 2002 Oct 1 + -3:00 - %z # # Bahia (BA) # There are too many Salvadors elsewhere, so use America/Bahia instead # of America/Salvador. Zone America/Bahia -2:34:04 - LMT 1914 - -3:00 Brazil -03/-02 2003 Sep 24 - -3:00 - -03 2011 Oct 16 - -3:00 Brazil -03/-02 2012 Oct 21 - -3:00 - -03 + -3:00 Brazil %z 2003 Sep 24 + -3:00 - %z 2011 Oct 16 + -3:00 Brazil %z 2012 Oct 21 + -3:00 - %z # # Goiás (GO), Distrito Federal (DF), Minas Gerais (MG), # Espírito Santo (ES), Rio de Janeiro (RJ), São Paulo (SP), Paraná (PR), # Santa Catarina (SC), Rio Grande do Sul (RS) Zone America/Sao_Paulo -3:06:28 - LMT 1914 - -3:00 Brazil -03/-02 1963 Oct 23 0:00 - -3:00 1:00 -02 1964 - -3:00 Brazil -03/-02 + -3:00 Brazil %z 1963 Oct 23 0:00 + -3:00 1:00 %z 1964 + -3:00 Brazil %z # # Mato Grosso do Sul (MS) Zone America/Campo_Grande -3:38:28 - LMT 1914 - -4:00 Brazil -04/-03 + -4:00 Brazil %z # # Mato Grosso (MT) Zone America/Cuiaba -3:44:20 - LMT 1914 - -4:00 Brazil -04/-03 2003 Sep 24 - -4:00 - -04 2004 Oct 1 - -4:00 Brazil -04/-03 + -4:00 Brazil %z 2003 Sep 24 + -4:00 - %z 2004 Oct 1 + -4:00 Brazil %z # # Rondônia (RO) Zone America/Porto_Velho -4:15:36 - LMT 1914 - -4:00 Brazil -04/-03 1988 Sep 12 - -4:00 - -04 + -4:00 Brazil %z 1988 Sep 12 + -4:00 - %z # # Roraima (RR) Zone America/Boa_Vista -4:02:40 - LMT 1914 - -4:00 Brazil -04/-03 1988 Sep 12 - -4:00 - -04 1999 Sep 30 - -4:00 Brazil -04/-03 2000 Oct 15 - -4:00 - -04 + -4:00 Brazil %z 1988 Sep 12 + -4:00 - %z 1999 Sep 30 + -4:00 Brazil %z 2000 Oct 15 + -4:00 - %z # # east Amazonas (AM): Boca do Acre, Jutaí, Manaus, Floriano Peixoto # The great circle line from Tabatinga to Porto Acre divides # east from west Amazonas. Zone America/Manaus -4:00:04 - LMT 1914 - -4:00 Brazil -04/-03 1988 Sep 12 - -4:00 - -04 1993 Sep 28 - -4:00 Brazil -04/-03 1994 Sep 22 - -4:00 - -04 + -4:00 Brazil %z 1988 Sep 12 + -4:00 - %z 1993 Sep 28 + -4:00 Brazil %z 1994 Sep 22 + -4:00 - %z # # west Amazonas (AM): Atalaia do Norte, Boca do Maoco, Benjamin Constant, # Eirunepé, Envira, Ipixuna Zone America/Eirunepe -4:39:28 - LMT 1914 - -5:00 Brazil -05/-04 1988 Sep 12 - -5:00 - -05 1993 Sep 28 - -5:00 Brazil -05/-04 1994 Sep 22 - -5:00 - -05 2008 Jun 24 0:00 - -4:00 - -04 2013 Nov 10 - -5:00 - -05 + -5:00 Brazil %z 1988 Sep 12 + -5:00 - %z 1993 Sep 28 + -5:00 Brazil %z 1994 Sep 22 + -5:00 - %z 2008 Jun 24 0:00 + -4:00 - %z 2013 Nov 10 + -5:00 - %z # # Acre (AC) Zone America/Rio_Branco -4:31:12 - LMT 1914 - -5:00 Brazil -05/-04 1988 Sep 12 - -5:00 - -05 2008 Jun 24 0:00 - -4:00 - -04 2013 Nov 10 - -5:00 - -05 + -5:00 Brazil %z 1988 Sep 12 + -5:00 - %z 2008 Jun 24 0:00 + -4:00 - %z 2013 Nov 10 + -5:00 - %z # Chile @@ -1382,36 +1382,36 @@ Rule Chile 2023 max - Sep Sun>=2 4:00u 1:00 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Santiago -4:42:45 - LMT 1890 -4:42:45 - SMT 1910 Jan 10 # Santiago Mean Time - -5:00 - -05 1916 Jul 1 + -5:00 - %z 1916 Jul 1 -4:42:45 - SMT 1918 Sep 10 - -4:00 - -04 1919 Jul 1 + -4:00 - %z 1919 Jul 1 -4:42:45 - SMT 1927 Sep 1 - -5:00 Chile -05/-04 1932 Sep 1 - -4:00 - -04 1942 Jun 1 - -5:00 - -05 1942 Aug 1 - -4:00 - -04 1946 Jul 14 24:00 - -4:00 1:00 -03 1946 Aug 28 24:00 # central CL - -5:00 1:00 -04 1947 Mar 31 24:00 - -5:00 - -05 1947 May 21 23:00 - -4:00 Chile -04/-03 + -5:00 Chile %z 1932 Sep 1 + -4:00 - %z 1942 Jun 1 + -5:00 - %z 1942 Aug 1 + -4:00 - %z 1946 Jul 14 24:00 + -4:00 1:00 %z 1946 Aug 28 24:00 # central CL + -5:00 1:00 %z 1947 Mar 31 24:00 + -5:00 - %z 1947 May 21 23:00 + -4:00 Chile %z Zone America/Punta_Arenas -4:43:40 - LMT 1890 -4:42:45 - SMT 1910 Jan 10 - -5:00 - -05 1916 Jul 1 + -5:00 - %z 1916 Jul 1 -4:42:45 - SMT 1918 Sep 10 - -4:00 - -04 1919 Jul 1 + -4:00 - %z 1919 Jul 1 -4:42:45 - SMT 1927 Sep 1 - -5:00 Chile -05/-04 1932 Sep 1 - -4:00 - -04 1942 Jun 1 - -5:00 - -05 1942 Aug 1 - -4:00 - -04 1946 Aug 28 24:00 - -5:00 1:00 -04 1947 Mar 31 24:00 - -5:00 - -05 1947 May 21 23:00 - -4:00 Chile -04/-03 2016 Dec 4 - -3:00 - -03 + -5:00 Chile %z 1932 Sep 1 + -4:00 - %z 1942 Jun 1 + -5:00 - %z 1942 Aug 1 + -4:00 - %z 1946 Aug 28 24:00 + -5:00 1:00 %z 1947 Mar 31 24:00 + -5:00 - %z 1947 May 21 23:00 + -4:00 Chile %z 2016 Dec 4 + -3:00 - %z Zone Pacific/Easter -7:17:28 - LMT 1890 -7:17:28 - EMT 1932 Sep # Easter Mean Time - -7:00 Chile -07/-06 1982 Mar 14 3:00u # Easter Time - -6:00 Chile -06/-05 + -7:00 Chile %z 1982 Mar 14 3:00u # Easter Time + -6:00 Chile %z # # Salas y Gómez Island is uninhabited. # Other Chilean locations, including Juan Fernández Is, Desventuradas Is, @@ -1431,10 +1431,10 @@ Zone Pacific/Easter -7:17:28 - LMT 1890 # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Palmer 0 - -00 1965 - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1982 May - -4:00 Chile -04/-03 2016 Dec 4 - -3:00 - -03 + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1982 May + -4:00 Chile %z 2016 Dec 4 + -3:00 - %z # Colombia @@ -1453,7 +1453,7 @@ Rule CO 1993 only - Feb 6 24:00 0 - #STDOFF -4:56:16.4 Zone America/Bogota -4:56:16 - LMT 1884 Mar 13 -4:56:16 - BMT 1914 Nov 23 # Bogotá Mean Time - -5:00 CO -05/-04 + -5:00 CO %z # Malpelo, Providencia, San Andres # no information; probably like America/Bogota @@ -1484,10 +1484,10 @@ Rule Ecuador 1993 only - Feb 5 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Guayaquil -5:19:20 - LMT 1890 -5:14:00 - QMT 1931 # Quito Mean Time - -5:00 Ecuador -05/-04 + -5:00 Ecuador %z Zone Pacific/Galapagos -5:58:24 - LMT 1931 # Puerto Baquerizo Moreno - -5:00 - -05 1986 - -6:00 Ecuador -06/-05 + -5:00 - %z 1986 + -6:00 Ecuador %z # Falklands @@ -1587,10 +1587,10 @@ Rule Falk 2001 2010 - Sep Sun>=1 2:00 1:00 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Atlantic/Stanley -3:51:24 - LMT 1890 -3:51:24 - SMT 1912 Mar 12 # Stanley Mean Time - -4:00 Falk -04/-03 1983 May - -3:00 Falk -03/-02 1985 Sep 15 - -4:00 Falk -04/-03 2010 Sep 5 2:00 - -3:00 - -03 + -4:00 Falk %z 1983 May + -3:00 Falk %z 1985 Sep 15 + -4:00 Falk %z 2010 Sep 5 2:00 + -3:00 - %z # French Guiana # For the 1911/1912 establishment of standard time in French possessions, see: @@ -1598,8 +1598,8 @@ Zone Atlantic/Stanley -3:51:24 - LMT 1890 # page 752, 18b. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Cayenne -3:29:20 - LMT 1911 Jul 1 - -4:00 - -04 1967 Oct - -3:00 - -03 + -4:00 - %z 1967 Oct + -3:00 - %z # Guyana @@ -1633,10 +1633,10 @@ Zone America/Cayenne -3:29:20 - LMT 1911 Jul 1 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Guyana -3:52:39 - LMT 1911 Aug 1 # Georgetown - -4:00 - -04 1915 Mar 1 - -3:45 - -0345 1975 Aug 1 - -3:00 - -03 1992 Mar 29 1:00 - -4:00 - -04 + -4:00 - %z 1915 Mar 1 + -3:45 - %z 1975 Aug 1 + -3:00 - %z 1992 Mar 29 1:00 + -4:00 - %z # Paraguay # @@ -1734,9 +1734,9 @@ Rule Para 2013 max - Mar Sun>=22 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Asuncion -3:50:40 - LMT 1890 -3:50:40 - AMT 1931 Oct 10 # Asunción Mean Time - -4:00 - -04 1972 Oct - -3:00 - -03 1974 Apr - -4:00 Para -04/-03 + -4:00 - %z 1972 Oct + -3:00 - %z 1974 Apr + -4:00 Para %z # Peru # @@ -1763,12 +1763,12 @@ Rule Peru 1994 only - Apr 1 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Lima -5:08:12 - LMT 1890 -5:08:36 - LMT 1908 Jul 28 # Lima Mean Time? - -5:00 Peru -05/-04 + -5:00 Peru %z # South Georgia # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Atlantic/South_Georgia -2:26:08 - LMT 1890 # Grytviken - -2:00 - -02 + -2:00 - %z # South Sandwich Is # uninhabited; scientific personnel have wintered @@ -1778,8 +1778,8 @@ Zone Atlantic/South_Georgia -2:26:08 - LMT 1890 # Grytviken Zone America/Paramaribo -3:40:40 - LMT 1911 -3:40:52 - PMT 1935 # Paramaribo Mean Time -3:40:36 - PMT 1945 Oct # The capital moved? - -3:30 - -0330 1984 Oct - -3:00 - -03 + -3:30 - %z 1984 Oct + -3:00 - %z # Uruguay # From Paul Eggert (1993-11-18): @@ -1994,15 +1994,15 @@ Rule Uruguay 2006 2014 - Oct Sun>=1 2:00 1:00 - # This Zone can be simplified once we assume zic %z. Zone America/Montevideo -3:44:51 - LMT 1908 Jun 10 -3:44:51 - MMT 1920 May 1 # Montevideo MT - -4:00 - -04 1923 Oct 1 - -3:30 Uruguay -0330/-03 1942 Dec 14 - -3:00 Uruguay -03/-0230 1960 - -3:00 Uruguay -03/-02 1968 - -3:00 Uruguay -03/-0230 1970 - -3:00 Uruguay -03/-02 1974 - -3:00 Uruguay -03/-0130 1974 Mar 10 - -3:00 Uruguay -03/-0230 1974 Dec 22 - -3:00 Uruguay -03/-02 + -4:00 - %z 1923 Oct 1 + -3:30 Uruguay %z 1942 Dec 14 + -3:00 Uruguay %z 1960 + -3:00 Uruguay %z 1968 + -3:00 Uruguay %z 1970 + -3:00 Uruguay %z 1974 + -3:00 Uruguay %z 1974 Mar 10 + -3:00 Uruguay %z 1974 Dec 22 + -3:00 Uruguay %z # Venezuela # @@ -2036,7 +2036,7 @@ Zone America/Montevideo -3:44:51 - LMT 1908 Jun 10 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Caracas -4:27:44 - LMT 1890 -4:27:40 - CMT 1912 Feb 12 # Caracas Mean Time? - -4:30 - -0430 1965 Jan 1 0:00 - -4:00 - -04 2007 Dec 9 3:00 - -4:30 - -0430 2016 May 1 2:30 - -4:00 - -04 + -4:30 - %z 1965 Jan 1 0:00 + -4:00 - %z 2007 Dec 9 3:00 + -4:30 - %z 2016 May 1 2:30 + -4:00 - %z diff --git a/src/java.base/share/data/tzdata/zone.tab b/src/java.base/share/data/tzdata/zone.tab index 0a01e8777dd25..b90ab4e4b25fb 100644 --- a/src/java.base/share/data/tzdata/zone.tab +++ b/src/java.base/share/data/tzdata/zone.tab @@ -287,8 +287,7 @@ MK +4159+02126 Europe/Skopje ML +1239-00800 Africa/Bamako MM +1647+09610 Asia/Yangon MN +4755+10653 Asia/Ulaanbaatar most of Mongolia -MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan -MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar +MN +4801+09139 Asia/Hovd Bayan-Olgii, Hovd, Uvs MO +221150+1133230 Asia/Macau MP +1512+14545 Pacific/Saipan MQ +1436-06105 America/Martinique diff --git a/src/java.base/share/lib/security/default.policy b/src/java.base/share/lib/security/default.policy index aa67bd6b53e66..d9bfdede97857 100644 --- a/src/java.base/share/lib/security/default.policy +++ b/src/java.base/share/lib/security/default.policy @@ -167,10 +167,6 @@ grant codeBase "jrt:/jdk.graal.compiler" { permission java.security.AllPermission; }; -grant codeBase "jrt:/jdk.jsobject" { - permission java.security.AllPermission; -}; - grant codeBase "jrt:/jdk.localedata" { permission java.lang.RuntimePermission "accessClassInPackage.sun.text.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.util.*"; diff --git a/src/java.base/share/native/libjava/ClassLoader.c b/src/java.base/share/native/libjava/ClassLoader.c index 927432d15091a..4519a4777f84f 100644 --- a/src/java.base/share/native/libjava/ClassLoader.c +++ b/src/java.base/share/native/libjava/ClassLoader.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,7 +114,7 @@ Java_java_lang_ClassLoader_defineClass1(JNIEnv *env, (*env)->GetByteArrayRegion(env, data, offset, length, body); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { goto free_body; } @@ -259,7 +259,7 @@ Java_java_lang_ClassLoader_defineClass0(JNIEnv *env, (*env)->GetByteArrayRegion(env, data, offset, length, body); - if ((*env)->ExceptionOccurred(env)) + if ((*env)->ExceptionCheck(env)) goto free_body; if (name != NULL) { diff --git a/src/java.base/share/native/libjava/FileInputStream.c b/src/java.base/share/native/libjava/FileInputStream.c index e22499828f5d0..7db2ec4c20871 100644 --- a/src/java.base/share/native/libjava/FileInputStream.c +++ b/src/java.base/share/native/libjava/FileInputStream.c @@ -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 @@ -141,3 +141,9 @@ Java_java_io_FileInputStream_available0(JNIEnv *env, jobject this) { JNU_ThrowIOExceptionWithLastError(env, NULL); return 0; } + +JNIEXPORT jboolean JNICALL +Java_java_io_FileInputStream_isRegularFile0(JNIEnv *env, jobject this, jobject fdo) { + FD fd = getFD(env, this, fis_fd); + return IO_IsRegularFile(env, fd); +} diff --git a/src/java.base/share/native/libjava/PhantomReference.c b/src/java.base/share/native/libjava/PhantomReference.c index b6d6e7297f104..54d4b7681dd51 100644 --- a/src/java.base/share/native/libjava/PhantomReference.c +++ b/src/java.base/share/native/libjava/PhantomReference.c @@ -31,3 +31,9 @@ Java_java_lang_ref_PhantomReference_refersTo0(JNIEnv *env, jobject ref, jobject { return JVM_PhantomReferenceRefersTo(env, ref, o); } + +JNIEXPORT void JNICALL +Java_java_lang_ref_PhantomReference_clear0(JNIEnv *env, jobject ref) +{ + JVM_ReferenceClear(env, ref); +} diff --git a/src/java.base/share/native/libjava/System.c b/src/java.base/share/native/libjava/System.c index 098b943cc40b8..7b038a6a9d59b 100644 --- a/src/java.base/share/native/libjava/System.c +++ b/src/java.base/share/native/libjava/System.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2022, 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 @@ -70,7 +70,7 @@ Java_java_lang_System_identityHashCode(JNIEnv *env, jobject this, jobject x) if (jval == NULL) \ return NULL; \ (*env)->SetObjectArrayElement(env, array, jdk_internal_util_SystemProps_Raw_##prop_index, jval); \ - if ((*env)->ExceptionOccurred(env)) \ + if ((*env)->ExceptionCheck(env)) \ return NULL; \ (*env)->DeleteLocalRef(env, jval); \ } @@ -86,7 +86,7 @@ Java_java_lang_System_identityHashCode(JNIEnv *env, jobject this, jobject x) if (jval == NULL) \ return NULL; \ (*env)->SetObjectArrayElement(env, array, jdk_internal_util_SystemProps_Raw_##prop_index, jval); \ - if ((*env)->ExceptionOccurred(env)) \ + if ((*env)->ExceptionCheck(env)) \ return NULL; \ (*env)->DeleteLocalRef(env, jval); \ } diff --git a/src/java.base/share/native/libjava/VirtualThread.c b/src/java.base/share/native/libjava/VirtualThread.c index 94dbe0b7e376e..f9d1d4996fcc7 100644 --- a/src/java.base/share/native/libjava/VirtualThread.c +++ b/src/java.base/share/native/libjava/VirtualThread.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,6 @@ static JNINativeMethod methods[] = { { "notifyJvmtiEnd", "()V", (void *)&JVM_VirtualThreadEnd }, { "notifyJvmtiMount", "(Z)V", (void *)&JVM_VirtualThreadMount }, { "notifyJvmtiUnmount", "(Z)V", (void *)&JVM_VirtualThreadUnmount }, - { "notifyJvmtiHideFrames", "(Z)V", (void *)&JVM_VirtualThreadHideFrames }, { "notifyJvmtiDisableSuspend", "(Z)V", (void *)&JVM_VirtualThreadDisableSuspend }, }; diff --git a/src/java.base/share/native/libjava/io_util.c b/src/java.base/share/native/libjava/io_util.c index 3fb7675d2771e..76ff58ec632be 100644 --- a/src/java.base/share/native/libjava/io_util.c +++ b/src/java.base/share/native/libjava/io_util.c @@ -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 @@ -175,7 +175,7 @@ writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, (*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf); - if (!(*env)->ExceptionOccurred(env)) { + if (!(*env)->ExceptionCheck(env)) { off = 0; while (len > 0) { fd = getFD(env, this, fid); diff --git a/src/java.base/share/native/libjava/jni_util.c b/src/java.base/share/native/libjava/jni_util.c index 3d9004d969cb8..ce23d16043068 100644 --- a/src/java.base/share/native/libjava/jni_util.c +++ b/src/java.base/share/native/libjava/jni_util.c @@ -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 @@ -117,7 +117,7 @@ JNU_ThrowByNameWithLastError(JNIEnv *env, const char *name, (*env)->Throw(env, x); } } - if (!(*env)->ExceptionOccurred(env)) { + if (!(*env)->ExceptionCheck(env)) { JNU_ThrowByName(env, name, defaultDetail); } } @@ -166,7 +166,7 @@ JNU_ThrowByNameWithMessageAndLastError } } - if (!(*env)->ExceptionOccurred(env)) { + if (!(*env)->ExceptionCheck(env)) { if (messagelen > 0) { JNU_ThrowByName(env, name, message); } else { diff --git a/src/hotspot/os_cpu/linux_ppc/gc/x/xSyscall_linux_ppc.hpp b/src/java.base/share/native/libjava/ub.h similarity index 66% rename from src/hotspot/os_cpu/linux_ppc/gc/x/xSyscall_linux_ppc.hpp rename to src/java.base/share/native/libjava/ub.h index 22d51cd58f542..cf7f491ca453e 100644 --- a/src/hotspot/os_cpu/linux_ppc/gc/x/xSyscall_linux_ppc.hpp +++ b/src/java.base/share/native/libjava/ub.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021 SAP SE. All rights reserved. + * 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 @@ -20,23 +20,23 @@ * Please 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 OS_CPU_LINUX_PPC_GC_X_XSYSCALL_LINUX_PPC_HPP -#define OS_CPU_LINUX_PPC_GC_X_XSYSCALL_LINUX_PPC_HPP - -#include - -// -// Support for building on older Linux systems -// - +#ifndef _UB_H_ +#define _UB_H_ -#ifndef SYS_memfd_create -#define SYS_memfd_create 360 +/* ATTRIBUTE_NO_UBSAN - Function attribute which informs the compiler to disable UBSan checks in the + * following function or method. + */ +#ifdef UNDEFINED_BEHAVIOR_SANITIZER +#if defined(__clang__) || defined(__GNUC__) +#define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined"))) +#endif #endif -#ifndef SYS_fallocate -#define SYS_fallocate 309 + +#ifndef ATTRIBUTE_NO_UBSAN +#define ATTRIBUTE_NO_UBSAN #endif -#endif // OS_CPU_LINUX_PPC_GC_X_XSYSCALL_LINUX_PPC_HPP +#endif diff --git a/src/java.base/share/native/libjli/emessages.h b/src/java.base/share/native/libjli/emessages.h index 342b116bfc70c..6fb7cf4ce9082 100644 --- a/src/java.base/share/native/libjli/emessages.h +++ b/src/java.base/share/native/libjli/emessages.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,60 +62,33 @@ #define JVM_ERROR1 "Error: Could not create the Java Virtual Machine.\n" GEN_ERROR #define JVM_ERROR2 "Error: Could not detach main thread.\n" JNI_ERROR -#define JAR_ERROR1 "Error: Failed to load Main-Class manifest attribute from\n%s\n%s" #define JAR_ERROR2 "Error: Unable to access jarfile %s" #define JAR_ERROR3 "Error: Invalid or corrupt jarfile %s" -#define CLS_ERROR1 "Error: Could not find the main class %s.\n" JNI_ERROR -#define CLS_ERROR2 "Error: Failed to load Main Class: %s\n%s" -#define CLS_ERROR3 "Error: No main method found in specified class.\n" GEN_ERROR -#define CLS_ERROR4 "Error: Main method not public\n" GEN_ERROR -#define CLS_ERROR5 "Error: main-class: attribute exceeds system limits of %d bytes\n" GEN_ERROR - #define CFG_WARN1 "Warning: %s VM not supported; %s VM will be used" #define CFG_WARN2 "Warning: No leading - on line %d of `%s'" #define CFG_WARN3 "Warning: Missing VM type on line %d of `%s'" -#define CFG_WARN4 "Warning: Missing server class VM on line %d of `%s'" #define CFG_WARN5 "Warning: Unknown VM type on line %d of `%s'" #define CFG_ERROR1 "Error: Corrupt jvm.cfg file; cycle in alias list." #define CFG_ERROR2 "Error: Unable to resolve VM alias %s" #define CFG_ERROR3 "Error: %s VM not supported" -#define CFG_ERROR4 "Error: Unable to locate JRE meeting specification \"%s\"" #define CFG_ERROR5 "Error: Could not determine application home." #define CFG_ERROR6 "Error: could not open `%s'" #define CFG_ERROR7 "Error: no known VMs. (check for corrupt jvm.cfg file)" -#define CFG_ERROR8 "Error: missing `%s' JVM at `%s'.\nPlease install or use the JRE or JDK that contains these missing components." +#define CFG_ERROR8 "Error: missing `%s' JVM at `%s'.\nPlease install a JDK that contains these missing components." #define CFG_ERROR9 "Error: could not determine JVM type." #define CFG_ERROR10 "Error: Argument file size should not be larger than %lu." -#define JRE_ERROR1 "Error: Could not find Java SE Runtime Environment." -#define JRE_ERROR2 "Error: This Java instance does not support a %d-bit JVM.\nPlease install the desired version." -#define JRE_ERROR3 "Error: Improper value at line %d." -#define JRE_ERROR4 "Error: trying to exec %s.\nCheck if file exists and permissions are set correctly." -#define JRE_ERROR5 "Error: Failed to start a %d-bit JVM process from a %d-bit JVM." -#define JRE_ERROR6 "Error: Verify all necessary Java SE components have been installed." -#define JRE_ERROR7 "Error: Either 64-bit processes are not supported by this platform\nor the 64-bit components have not been installed." -#define JRE_ERROR8 "Error: could not find " -#define JRE_ERROR9 "Error: Unable to resolve %s" -#define JRE_ERROR10 "Error: Unable to resolve current executable" -#define JRE_ERROR11 "Error: Path length exceeds maximum length (PATH_MAX)" -#define JRE_ERROR12 "Error: Exec of %s failed" -#define JRE_ERROR13 "Error: String processing operation failed" +#define LAUNCHER_ERROR1 "Error: Could not find Java SE Runtime Environment." +#define LAUNCHER_ERROR2 "Error: could not find " +#define LAUNCHER_ERROR3 "Error: Path length exceeds maximum length (PATH_MAX)" +#define LAUNCHER_ERROR4 "Error: trying to exec %s.\nCheck if file exists and permissions are set correctly." +#define LAUNCHER_ERROR5 "Error: String processing operation failed" #define DLL_ERROR1 "Error: dl failure on line %d" #define DLL_ERROR2 "Error: failed %s, because %s" #define DLL_ERROR3 "Error: could not find executable %s" #define DLL_ERROR4 "Error: Failed to load %s" -#define REG_ERROR1 "Error: opening registry key '%s'" -#define REG_ERROR2 "Error: Failed reading value of registry key:\n\t%s\\CurrentVersion" -#define REG_ERROR3 "Error: Registry key '%s'\\CurrentVersion'\nhas value '%s', but '%s' is required." -#define REG_ERROR4 "Failed reading value of registry key:\n\t%s\\%s\\JavaHome" - -#define SYS_ERROR1 "Error: CreateProcess(%s, ...) failed:" -#define SYS_ERROR2 "Error: WaitForSingleObject() failed." - - - #endif /* _EMESSAGES_H */ diff --git a/src/java.base/share/native/libjli/java.c b/src/java.base/share/native/libjli/java.c index d4e20fb21fe75..0bb1daed28a1a 100644 --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c @@ -236,7 +236,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ InvocationFunctions ifn; jlong start = 0, end = 0; char jvmpath[MAXPATHLEN]; - char jrepath[MAXPATHLEN]; + char jdkroot[MAXPATHLEN]; char jvmcfg[MAXPATHLEN]; _fVersion = fullversion; @@ -265,9 +265,9 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ } CreateExecutionEnvironment(&argc, &argv, - jrepath, sizeof(jrepath), + jdkroot, sizeof(jdkroot), jvmpath, sizeof(jvmpath), - jvmcfg, sizeof(jvmcfg)); + jvmcfg, sizeof(jvmcfg)); ifn.CreateJavaVM = 0; ifn.GetDefaultJavaVMInitArgs = 0; @@ -351,7 +351,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ #define CHECK_EXCEPTION_NULL_LEAVE(CENL_exception) \ do { \ - if ((*env)->ExceptionOccurred(env)) { \ + if ((*env)->ExceptionCheck(env)) { \ JLI_ReportExceptionDescription(env); \ LEAVE(); \ } \ @@ -363,7 +363,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ #define CHECK_EXCEPTION_LEAVE(CEL_return_value) \ do { \ - if ((*env)->ExceptionOccurred(env)) { \ + if ((*env)->ExceptionCheck(env)) { \ JLI_ReportExceptionDescription(env); \ ret = (CEL_return_value); \ LEAVE(); \ @@ -1522,7 +1522,7 @@ NewPlatformString(JNIEnv *env, char *s) if (ary != 0) { jstring str = 0; (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s); - if (!(*env)->ExceptionOccurred(env)) { + if (!(*env)->ExceptionCheck(env)) { if (makePlatformStringMID == NULL) { NULL_CHECK0(makePlatformStringMID = (*env)->GetStaticMethodID(env, cls, "makePlatformString", "(Z[B)Ljava/lang/String;")); @@ -2023,7 +2023,7 @@ PrintUsage(JNIEnv* env, jboolean doXUsage) * JVM on the command line. * * The intent of the jvm.cfg file is to allow several JVM libraries to - * be installed in different subdirectories of a single JRE installation, + * be installed in different subdirectories of a single JDK installation, * for space-savings and convenience in testing. * The intent is explicitly not to provide a full aliasing or predicate * mechanism. diff --git a/src/java.base/share/native/libjli/java.h b/src/java.base/share/native/libjli/java.h index ce5224a7da346..f39e923cab81b 100644 --- a/src/java.base/share/native/libjli/java.h +++ b/src/java.base/share/native/libjli/java.h @@ -111,15 +111,15 @@ GetApplicationHomeFromDll(char *buf, jint bufsize); * Different platforms will implement this, here * pargc is a pointer to the original argc, * pargv is a pointer to the original argv, - * jrepath is an accessible path to the jre as determined by the call - * so_jrepath is the length of the buffer jrepath + * jdkroot is an accessible path to the JDK installation root as determined by the call + * so_jdkroot is the length of the buffer jdkroot * jvmpath is an accessible path to the jvm as determined by the call * so_jvmpath is the length of the buffer jvmpath */ void CreateExecutionEnvironment(int *argc, char ***argv, - char *jrepath, jint so_jrepath, + char *jdkroot, jint so_jdkroot, char *jvmpath, jint so_jvmpath, - char *jvmcfg, jint so_jvmcfg); + char *jvmcfg, jint so_jvmcfg); /* Reports an error message to stderr or a window as appropriate. */ JNIEXPORT void JNICALL @@ -246,14 +246,14 @@ typedef struct { #define CHECK_EXCEPTION_RETURN_VALUE(CER_value) \ do { \ - if ((*env)->ExceptionOccurred(env)) { \ + if ((*env)->ExceptionCheck(env)) { \ return CER_value; \ } \ } while (JNI_FALSE) #define CHECK_EXCEPTION_RETURN() \ do { \ - if ((*env)->ExceptionOccurred(env)) { \ + if ((*env)->ExceptionCheck(env)) { \ return; \ } \ } while (JNI_FALSE) diff --git a/src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java b/src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java deleted file mode 100644 index 291b6d06d8e3f..0000000000000 --- a/src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.net.www.protocol.jar; - -import java.io.IOException; -import java.io.FileNotFoundException; -import java.net.URL; -import java.net.URLConnection; -import java.util.HashMap; -import java.util.jar.JarFile; -import java.security.Permission; -import sun.net.util.URLUtil; - -/* A factory for cached JAR file. This class is used to both retrieve - * and cache Jar files. - * - * @author Benjamin Renaud - * @since 1.2 - */ -class JarFileFactory implements URLJarFile.URLJarFileCloseController { - - /* the url to file cache */ - private static final HashMap fileCache = new HashMap<>(); - - /* the file to url cache */ - private static final HashMap urlCache = new HashMap<>(); - - private static final JarFileFactory instance = new JarFileFactory(); - - private JarFileFactory() { } - - public static JarFileFactory getInstance() { - return instance; - } - - URLConnection getConnection(JarFile jarFile) throws IOException { - URL u; - synchronized (instance) { - u = urlCache.get(jarFile); - } - if (u != null) - return u.openConnection(); - - return null; - } - - public JarFile get(URL url) throws IOException { - return get(url, true); - } - - /** - * Get or create a {@code JarFile} for the given {@code url}. - * If {@code useCaches} is true, this method attempts to find - * a jar file in the cache, and if so, returns it. - * If no jar file is found in the cache, or {@code useCaches} - * is false, the method creates a new jar file. - * If the URL points to a local file, the returned jar file - * will not be put in the cache yet. - * The caller should then call {@link #cacheIfAbsent(URL, JarFile)} - * with the returned jar file, if updating the cache is desired. - * @param url the jar file url - * @param useCaches whether the cache should be used - * @return a new or cached jar file. - * @throws IOException if the jar file couldn't be created - */ - JarFile getOrCreate(URL url, boolean useCaches) throws IOException { - if (useCaches == false) { - return get(url, false); - } - - if (!URLJarFile.isFileURL(url)) { - // A temporary file will be created, we can prepopulate - // the cache in this case. - return get(url, useCaches); - } - - // We have a local file. Do not prepopulate the cache. - JarFile result; - synchronized (instance) { - result = getCachedJarFile(url); - } - if (result == null) { - result = URLJarFile.getJarFile(url, this); - } - if (result == null) - throw new FileNotFoundException(url.toString()); - return result; - } - - /** - * Close the given jar file if it isn't present in the cache. - * Otherwise, does nothing. - * @param url the jar file URL - * @param jarFile the jar file to close - * @return true if the jar file has been closed, false otherwise. - * @throws IOException if an error occurs while closing the jar file. - */ - boolean closeIfNotCached(URL url, JarFile jarFile) throws IOException { - JarFile result; - synchronized (instance) { - result = getCachedJarFile(url); - } - if (result != jarFile) jarFile.close(); - return result != jarFile; - } - - boolean cacheIfAbsent(URL url, JarFile jarFile) { - JarFile cached; - synchronized (instance) { - String key = urlKey(url); - cached = fileCache.get(key); - if (cached == null) { - fileCache.put(key, jarFile); - urlCache.put(jarFile, url); - } - } - return cached == null || cached == jarFile; - } - - JarFile get(URL url, boolean useCaches) throws IOException { - - JarFile result; - JarFile local_result; - - if (useCaches) { - synchronized (instance) { - result = getCachedJarFile(url); - } - if (result == null) { - local_result = URLJarFile.getJarFile(url, this); - synchronized (instance) { - result = getCachedJarFile(url); - if (result == null) { - fileCache.put(urlKey(url), local_result); - urlCache.put(local_result, url); - result = local_result; - } else { - if (local_result != null) { - local_result.close(); - } - } - } - } - } else { - result = URLJarFile.getJarFile(url, this); - } - if (result == null) - throw new FileNotFoundException(url.toString()); - - return result; - } - - /** - * Callback method of the URLJarFileCloseController to - * indicate that the JarFile is closed. This way we can - * remove the JarFile from the cache - */ - public void close(JarFile jarFile) { - synchronized (instance) { - URL urlRemoved = urlCache.remove(jarFile); - if (urlRemoved != null) - fileCache.remove(urlKey(urlRemoved)); - } - } - - private JarFile getCachedJarFile(URL url) { - assert Thread.holdsLock(instance); - JarFile result = fileCache.get(urlKey(url)); - - /* if the JAR file is cached, the permission will always be there */ - if (result != null) { - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - Permission perm = getPermission(result); - if (perm != null) { - try { - sm.checkPermission(perm); - } catch (SecurityException se) { - // fallback to checkRead/checkConnect for pre 1.2 - // security managers - if ((perm instanceof java.io.FilePermission) && - perm.getActions().contains("read")) { - sm.checkRead(perm.getName()); - } else if ((perm instanceof - java.net.SocketPermission) && - perm.getActions().contains("connect")) { - sm.checkConnect(url.getHost(), url.getPort()); - } else { - throw se; - } - } - } - } - } - return result; - } - - private String urlKey(URL url) { - String urlstr = URLUtil.urlNoFragString(url); - if ("runtime".equals(url.getRef())) urlstr += "#runtime"; - return urlstr; - } - - private Permission getPermission(JarFile jarFile) { - try { - URLConnection uc = getConnection(jarFile); - if (uc != null) - return uc.getPermission(); - } catch (IOException ioe) { - // gulp - } - - return null; - } -} diff --git a/src/java.base/unix/classes/sun/nio/ch/UnixFileDispatcherImpl.java b/src/java.base/unix/classes/sun/nio/ch/UnixFileDispatcherImpl.java index 15295bbd35c02..e9f8cb637fb86 100644 --- a/src/java.base/unix/classes/sun/nio/ch/UnixFileDispatcherImpl.java +++ b/src/java.base/unix/classes/sun/nio/ch/UnixFileDispatcherImpl.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 @@ -93,6 +93,14 @@ long size(FileDescriptor fd) throws IOException { return size0(fd); } + int available(FileDescriptor fd) throws IOException { + return available0(fd); + } + + boolean isOther(FileDescriptor fd) throws IOException { + return isOther0(fd); + } + int lock(FileDescriptor fd, boolean blocking, long pos, long size, boolean shared) throws IOException { @@ -196,6 +204,10 @@ static native int truncate0(FileDescriptor fd, long size) static native long size0(FileDescriptor fd) throws IOException; + static native int available0(FileDescriptor fd) throws IOException; + + static native boolean isOther0(FileDescriptor fd) throws IOException; + static native int lock0(FileDescriptor fd, boolean blocking, long pos, long size, boolean shared) throws IOException; diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java index 3b09bd259ceec..2a036d22aed9d 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, 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 @@ -58,6 +58,7 @@ class UnixFileAttributes private long st_ctime_nsec; private long st_birthtime_sec; private long st_birthtime_nsec; + private boolean birthtime_available; // created lazily private volatile UserPrincipal owner; @@ -163,10 +164,10 @@ public FileTime lastAccessTime() { @Override public FileTime creationTime() { - if (UnixNativeDispatcher.birthtimeSupported()) { + if (UnixNativeDispatcher.birthtimeSupported() && birthtime_available) { return toFileTime(st_birthtime_sec, st_birthtime_nsec); } else { - // return last modified when birth time not supported + // return last modified when birth time unsupported or unavailable return lastModifiedTime(); } } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java index a069a9a04bac8..ab8975c6d120d 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java @@ -569,7 +569,7 @@ static boolean openatSupported() { } /** - * Supports futimes or futimesat + * Supports futimes */ static boolean futimesSupported() { return (capabilities & SUPPORTS_FUTIMES) != 0; diff --git a/src/java.base/unix/native/libjava/Console_md.c b/src/java.base/unix/native/libjava/Console_md.c index e5b760a149972..1e71ab3a6b20a 100644 --- a/src/java.base/unix/native/libjava/Console_md.c +++ b/src/java.base/unix/native/libjava/Console_md.c @@ -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 @@ -36,9 +36,3 @@ Java_java_io_Console_istty(JNIEnv *env, jclass cls) { return isatty(fileno(stdin)) && isatty(fileno(stdout)); } - -JNIEXPORT jstring JNICALL -Java_java_io_Console_encoding(JNIEnv *env, jclass cls) -{ - return NULL; -} diff --git a/src/java.base/unix/native/libjava/io_util_md.c b/src/java.base/unix/native/libjava/io_util_md.c index 28659b3a1c256..2e81cbd05c2e2 100644 --- a/src/java.base/unix/native/libjava/io_util_md.c +++ b/src/java.base/unix/native/libjava/io_util_md.c @@ -135,7 +135,7 @@ void fileDescriptorClose(JNIEnv *env, jobject this) { FD fd = (*env)->GetIntField(env, this, IO_fd_fdID); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return; } @@ -150,7 +150,7 @@ fileDescriptorClose(JNIEnv *env, jobject this) * taking extra precaution over here. */ (*env)->SetIntField(env, this, IO_fd_fdID, -1); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return; } /* @@ -264,3 +264,13 @@ handleGetLength(FD fd) #endif return sb.st_size; } + +jboolean +handleIsRegularFile(JNIEnv* env, FD fd) +{ + struct stat fbuf; + if (fstat(fd, &fbuf) == -1) + JNU_ThrowIOExceptionWithLastError(env, "fstat failed"); + + return S_ISREG(fbuf.st_mode) ? JNI_TRUE : JNI_FALSE; +} diff --git a/src/java.base/unix/native/libjava/io_util_md.h b/src/java.base/unix/native/libjava/io_util_md.h index 84e97b4ace5fe..5a8cb8655ef07 100644 --- a/src/java.base/unix/native/libjava/io_util_md.h +++ b/src/java.base/unix/native/libjava/io_util_md.h @@ -41,6 +41,7 @@ jint handleAvailable(FD fd, jlong *pbytes); jint handleSetLength(FD fd, jlong length); jlong handleGetLength(FD fd); FD handleOpen(const char *path, int oflag, int mode); +jboolean handleIsRegularFile(JNIEnv* env, FD fd); /* * Functions to get fd from the java.io.FileDescriptor field @@ -66,6 +67,7 @@ FD getFD(JNIEnv *env, jobject cur, jfieldID fid); #define IO_Available handleAvailable #define IO_SetLength handleSetLength #define IO_GetLength handleGetLength +#define IO_IsRegularFile handleIsRegularFile /* * On Solaris, the handle field is unused diff --git a/src/java.base/unix/native/libjli/java_md.c b/src/java.base/unix/native/libjli/java_md.c index 7f2f5638a6b83..c2d2ac93f361b 100644 --- a/src/java.base/unix/native/libjli/java_md.c +++ b/src/java.base/unix/native/libjli/java_md.c @@ -253,8 +253,8 @@ RequiresSetenv(const char *jvmpath) { /* * Prevent recursions. Since LD_LIBRARY_PATH is the one which will be set by - * previous versions of the JRE, thus it is the only path that matters here. - * So we check to see if the desired JRE is set. + * previous versions of the JDK, thus it is the only path that matters here. + * So we check to see if the desired JDK is set. */ JLI_StrNCpy(jpath, jvmpath, PATH_MAX); p = JLI_StrRChr(jpath, '/'); @@ -273,7 +273,7 @@ RequiresSetenv(const char *jvmpath) { void CreateExecutionEnvironment(int *pargc, char ***pargv, - char jrepath[], jint so_jrepath, + char jdkroot[], jint so_jdkroot, char jvmpath[], jint so_jvmpath, char jvmcfg[], jint so_jvmcfg) { @@ -294,13 +294,13 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, SetExecname(*pargv); /* Check to see if the jvmpath exists */ - /* Find out where the JRE is that we will be using. */ - if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE)) { - JLI_ReportErrorMessage(JRE_ERROR1); + /* Find out where the JDK is that we will be using. */ + if (!GetJDKInstallRoot(jdkroot, so_jdkroot, JNI_FALSE)) { + JLI_ReportErrorMessage(LAUNCHER_ERROR1); exit(2); } JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg", - jrepath, FILESEP, FILESEP); + jdkroot, FILESEP, FILESEP); /* Find the specified JVM type */ if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) { JLI_ReportErrorMessage(CFG_ERROR7); @@ -314,7 +314,7 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, exit(4); } - if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { + if (!GetJVMPath(jdkroot, jvmtype, jvmpath, so_jvmpath)) { JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } @@ -339,8 +339,8 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, * We will set the LD_LIBRARY_PATH as follows: * * o $JVMPATH (directory portion only) - * o $JRE/lib - * o $JRE/../lib + * o $JDK/lib + * o $JDK/../lib * * followed by the user's previous effective LD_LIBRARY_PATH, if * any. @@ -352,7 +352,7 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, { /* New scope to declare local variable */ char *new_jvmpath = JLI_StringDup(jvmpath); new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) + - 2 * JLI_StrLen(jrepath) + + 2 * JLI_StrLen(jdkroot) + JLI_StrLen(new_jvmpath) + 52; new_runpath = JLI_MemAlloc(new_runpath_size); newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "="); @@ -372,8 +372,8 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, "%s/lib:" "%s/../lib", new_jvmpath, - jrepath, - jrepath + jdkroot, + jdkroot ); JLI_MemFree(new_jvmpath); @@ -402,7 +402,7 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, if (runpath != 0) { /* ensure storage for runpath + colon + NULL */ if ((JLI_StrLen(runpath) + 1 + 1) > new_runpath_size) { - JLI_ReportErrorMessageSys(JRE_ERROR11); + JLI_ReportErrorMessageSys(LAUNCHER_ERROR3); exit(1); } JLI_StrCat(new_runpath, ":"); @@ -437,14 +437,14 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, #else /* !SETENV_REQUIRED */ execv(newexec, argv); #endif /* SETENV_REQUIRED */ - JLI_ReportErrorMessageSys(JRE_ERROR4, newexec); + JLI_ReportErrorMessageSys(LAUNCHER_ERROR4, newexec); } exit(1); } static jboolean -GetJVMPath(const char *jrepath, const char *jvmtype, +GetJVMPath(const char *jdkroot, const char *jvmtype, char *jvmpath, jint jvmpathsize) { struct stat s; @@ -452,7 +452,7 @@ GetJVMPath(const char *jrepath, const char *jvmtype, if (JLI_StrChr(jvmtype, '/')) { JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype); } else { - JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype); + JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jdkroot, jvmtype); } JLI_TraceLauncher("Does `%s' exist ... ", jvmpath); @@ -467,31 +467,31 @@ GetJVMPath(const char *jrepath, const char *jvmtype, } /* - * Find path to JRE based on .exe's location or registry settings. + * Find path to the JDK installation root */ static jboolean -GetJREPath(char *path, jint pathsize, jboolean speculative) +GetJDKInstallRoot(char *path, jint pathsize, jboolean speculative) { char libjava[MAXPATHLEN]; struct stat s; - JLI_TraceLauncher("Attempt to get JRE path from launcher executable path\n"); + JLI_TraceLauncher("Attempt to get JDK installation root from launcher executable path\n"); if (GetApplicationHome(path, pathsize)) { - /* Is JRE co-located with the application? */ + /* Is JDK co-located with the application? */ JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path); if (access(libjava, F_OK) == 0) { - JLI_TraceLauncher("JRE path is %s\n", path); + JLI_TraceLauncher("JDK installation root path is %s\n", path); return JNI_TRUE; } } - JLI_TraceLauncher("Attempt to get JRE path from shared lib of the image\n"); + JLI_TraceLauncher("Attempt to get JDK installation root path from shared lib of the image\n"); if (GetApplicationHomeFromDll(path, pathsize)) { JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path); if (stat(libjava, &s) == 0) { - JLI_TraceLauncher("JRE path is %s\n", path); + JLI_TraceLauncher("JDK installation root path is %s\n", path); return JNI_TRUE; } } @@ -501,14 +501,14 @@ GetJREPath(char *path, jint pathsize, jboolean speculative) if (GetApplicationHomeFromLibpath(path, pathsize)) { JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path); if (stat(libjava, &s) == 0) { - JLI_TraceLauncher("JRE path is %s\n", path); + JLI_TraceLauncher("JDK installation root path is %s\n", path); return JNI_TRUE; } } #endif if (!speculative) - JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); + JLI_ReportErrorMessage(LAUNCHER_ERROR2 JAVA_DLL); return JNI_FALSE; } @@ -597,22 +597,22 @@ static void* hSplashLib = NULL; void* SplashProcAddress(const char* name) { if (!hSplashLib) { int ret; - char jrePath[MAXPATHLEN]; + char jdkRoot[MAXPATHLEN]; char splashPath[MAXPATHLEN]; - if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) { - JLI_ReportErrorMessage(JRE_ERROR1); + if (!GetJDKInstallRoot(jdkRoot, sizeof(jdkRoot), JNI_FALSE)) { + JLI_ReportErrorMessage(LAUNCHER_ERROR1); return NULL; } ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s", - jrePath, SPLASHSCREEN_SO); + jdkRoot, SPLASHSCREEN_SO); if (ret >= (int) sizeof(splashPath)) { - JLI_ReportErrorMessage(JRE_ERROR11); + JLI_ReportErrorMessage(LAUNCHER_ERROR3); return NULL; } if (ret < 0) { - JLI_ReportErrorMessage(JRE_ERROR13); + JLI_ReportErrorMessage(LAUNCHER_ERROR5); return NULL; } hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL); diff --git a/src/java.base/unix/native/libjli/java_md.h b/src/java.base/unix/native/libjli/java_md.h index acc75ab091d30..ef0740b18f08a 100644 --- a/src/java.base/unix/native/libjli/java_md.h +++ b/src/java.base/unix/native/libjli/java_md.h @@ -55,9 +55,9 @@ int UnsetEnv(char *name); char *FindExecName(char *program); const char *SetExecname(char **argv); const char *GetExecName(); -static jboolean GetJVMPath(const char *jrepath, const char *jvmtype, +static jboolean GetJVMPath(const char *jdkroot, const char *jvmtype, char *jvmpath, jint jvmpathsize); -static jboolean GetJREPath(char *path, jint pathsize, jboolean speculative); +static jboolean GetJDKInstallRoot(char *path, jint pathsize, jboolean speculative); #if defined(_AIX) jboolean GetApplicationHomeFromLibpath(char *buf, jint bufsize); diff --git a/src/java.base/unix/native/libjli/java_md_common.c b/src/java.base/unix/native/libjli/java_md_common.c index 453d605f71082..f67a50304d077 100644 --- a/src/java.base/unix/native/libjli/java_md_common.c +++ b/src/java.base/unix/native/libjli/java_md_common.c @@ -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 @@ -76,7 +76,7 @@ TruncatePath(char *buf, jboolean pathisdll) } /* - * Retrieves the path to the JRE home by locating the executable file + * Retrieves the path to the JDK home by locating the executable file * of the current process and then truncating the path to the executable */ jboolean @@ -93,7 +93,7 @@ GetApplicationHome(char *buf, jint bufsize) } /* - * Retrieves the path to the JRE home by locating the + * Retrieves the path to the JDK home by locating the * shared library and then truncating the path to it. */ jboolean @@ -124,7 +124,7 @@ LibjavaExists(const char *path) } /* - * Retrieves the path to the JRE home by locating libjava.so in + * Retrieves the path to the JDK home by locating libjava.so in * LIBPATH and then truncating the path to it. */ jboolean @@ -262,7 +262,7 @@ JLI_ReportExceptionDescription(JNIEnv * env) { /* * Since using the file system as a registry is a bit risky, perform * additional sanity checks on the identified directory to validate - * it as a valid jre/sdk. + * it as a valid JDK. * * Return 0 if the tests fail; otherwise return non-zero (true). * diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c index 0cd69399d9181..61267ec13d537 100644 --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -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 @@ -374,7 +374,7 @@ JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0 if (family == AF_INET) { sock = openSocket(env, AF_INET); - if (sock < 0 && (*env)->ExceptionOccurred(env)) { + if (sock < 0 && (*env)->ExceptionCheck(env)) { return JNI_FALSE; } @@ -383,7 +383,7 @@ JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0 ifs = enumIPv4Interfaces(env, sock, ifs); close(sock); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { goto cleanup; } } @@ -401,7 +401,7 @@ JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0 ifs = enumIPv6Interfaces(env, sock, ifs); close(sock); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { goto cleanup; } @@ -856,7 +856,7 @@ static netif *enumInterfaces(JNIEnv *env) { int sock; sock = openSocket(env, AF_INET); - if (sock < 0 && (*env)->ExceptionOccurred(env)) { + if (sock < 0 && (*env)->ExceptionCheck(env)) { return NULL; } @@ -865,7 +865,7 @@ static netif *enumInterfaces(JNIEnv *env) { ifs = enumIPv4Interfaces(env, sock, ifs); close(sock); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { freeif(ifs); return NULL; } @@ -884,7 +884,7 @@ static netif *enumInterfaces(JNIEnv *env) { ifs = enumIPv6Interfaces(env, sock, ifs); close(sock); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { freeif(ifs); return NULL; } @@ -1237,7 +1237,7 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { &addr, broadaddrP, AF_INET, prefix); // in case of exception, free interface list and buffer and return NULL - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { free(buf); freeif(ifs); return NULL; @@ -1281,7 +1281,7 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { NULL, AF_INET6, (short)prefix); // if an exception occurred then return the list as is - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { break; } } @@ -1478,7 +1478,7 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { &addr, broadaddrP, AF_INET, prefix); // in case of exception, free interface list and buffer and return NULL - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { free(buf); freeif(ifs); return NULL; @@ -1552,7 +1552,7 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { NULL, AF_INET6, prefix); // if an exception occurred then free the list - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { free(buf); freeif(ifs); return NULL; @@ -1717,7 +1717,7 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { ifa->ifa_netmask)); // if an exception occurred then free the list - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { freeifaddrs(origifa); freeif(ifs); return NULL; @@ -1757,7 +1757,7 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { ifa->ifa_netmask)); // if an exception occurred then free the list - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { freeifaddrs(origifa); freeif(ifs); return NULL; diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c index 6729170efb4cb..b56f16905fa23 100644 --- a/src/java.base/unix/native/libnet/SdpSupport.c +++ b/src/java.base/unix/native/libnet/SdpSupport.c @@ -106,7 +106,7 @@ Java_sun_net_sdp_SdpSupport_convert0(JNIEnv *env, jclass cls, int fd) if (res < 0) JNU_ThrowIOExceptionWithLastError(env, "dup2"); res = close(s); - if (res < 0 && !(*env)->ExceptionOccurred(env)) + if (res < 0 && !(*env)->ExceptionCheck(env)) JNU_ThrowIOExceptionWithLastError(env, "close"); } } diff --git a/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c b/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c index 73db22a917620..c43c3b9069529 100644 --- a/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c +++ b/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, sockl jbyteArray name = (*env)->NewByteArray(env, namelen); if (namelen != 0) { (*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return NULL; } } diff --git a/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c index 918d76bfc5374..0c6328c56905e 100644 --- a/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c @@ -23,6 +23,7 @@ * questions. */ +#include #include #include #include @@ -41,8 +42,10 @@ #include "nio.h" #include "nio_util.h" #include "sun_nio_ch_UnixFileDispatcherImpl.h" +#include "java_lang_Integer.h" #include "java_lang_Long.h" #include +#include "io_util_md.h" #if defined(_AIX) #define statvfs statvfs64 @@ -178,6 +181,57 @@ Java_sun_nio_ch_UnixFileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject return fbuf.st_size; } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_UnixFileDispatcherImpl_available0(JNIEnv *env, jobject this, jobject fdo) +{ + jint fd = fdval(env, fdo); + struct stat fbuf; + jlong size = -1; + + if (fstat(fd, &fbuf) != -1) { + int mode = fbuf.st_mode; + if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) { + int n = ioctl(fd, FIONREAD, &n); + if (n >= 0) { + return n; + } + } else if (S_ISREG(mode)) { + size = fbuf.st_size; + } + } + + jlong position; + if ((position = lseek(fd, 0, SEEK_CUR)) == -1) { + return 0; + } + + if (size < position) { + if ((size = lseek(fd, 0, SEEK_END)) == -1) + return 0; + else if (lseek(fd, position, SEEK_SET) == -1) + return 0; + } + + jlong available = size - position; + return available > java_lang_Integer_MAX_VALUE ? + java_lang_Integer_MAX_VALUE : (jint)available; +} + +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_UnixFileDispatcherImpl_isOther0(JNIEnv *env, jobject this, jobject fdo) +{ + jint fd = fdval(env, fdo); + struct stat fbuf; + + if (fstat(fd, &fbuf) == -1) + handle(env, -1, "isOther failed"); + + if (S_ISREG(fbuf.st_mode) || S_ISDIR(fbuf.st_mode) || S_ISLNK(fbuf.st_mode)) + return JNI_FALSE; + + return JNI_TRUE; +} + JNIEXPORT jint JNICALL Java_sun_nio_ch_UnixFileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, jboolean block, jlong pos, jlong size, diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index b91ab6f0cab92..9a68a12c2198e 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -184,6 +184,7 @@ static jfieldID attrs_st_birthtime_sec; #if defined(__linux__) // Linux has nsec granularity if supported static jfieldID attrs_st_birthtime_nsec; #endif +static jfieldID attrs_birthtime_available; static jfieldID attrs_f_frsize; static jfieldID attrs_f_blocks; @@ -203,7 +204,7 @@ typedef int openat_func(int, const char *, int, ...); typedef int fstatat_func(int, const char *, struct stat *, int); typedef int unlinkat_func(int, const char*, int); typedef int renameat_func(int, const char*, int, const char*); -typedef int futimesat_func(int, const char *, const struct timeval *); +typedef int futimes_func(int, const struct timeval *); typedef int futimens_func(int, const struct timespec *); typedef int lutimes_func(const char *, const struct timeval *); typedef DIR* fdopendir_func(int); @@ -216,7 +217,7 @@ static openat_func* my_openat_func = NULL; static fstatat_func* my_fstatat_func = NULL; static unlinkat_func* my_unlinkat_func = NULL; static renameat_func* my_renameat_func = NULL; -static futimesat_func* my_futimesat_func = NULL; +static futimes_func* my_futimes_func = NULL; static futimens_func* my_futimens_func = NULL; static lutimes_func* my_lutimes_func = NULL; static fdopendir_func* my_fdopendir_func = NULL; @@ -332,6 +333,8 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) attrs_st_birthtime_nsec = (*env)->GetFieldID(env, clazz, "st_birthtime_nsec", "J"); CHECK_NULL_RETURN(attrs_st_birthtime_nsec, 0); #endif + attrs_birthtime_available = (*env)->GetFieldID(env, clazz, "birthtime_available", "Z"); + CHECK_NULL_RETURN(attrs_birthtime_available, 0); clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes"); CHECK_NULL_RETURN(clazz, 0); @@ -360,8 +363,8 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) /* system calls that might not be available at run time */ #if defined(_ALLBSD_SOURCE) - my_openat_func = (openat_func*)dlsym(RTLD_DEFAULT, "openat"); - my_fstatat_func = (fstatat_func*)dlsym(RTLD_DEFAULT, "fstatat"); + my_openat_func = (openat_func*) openat; + my_fstatat_func = (fstatat_func*) fstatat; #else // Make sure we link to the 64-bit version of the functions my_openat_func = (openat_func*) dlsym(RTLD_DEFAULT, "openat64"); @@ -370,22 +373,22 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat"); my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat"); #if defined(__linux__) && defined(__arm__) - my_futimesat_func = (futimesat_func*) lookup_time_t_function("futimesat", - "__futimesat64"); + my_futimes_func = (futimes_func*) lookup_time_t_function("futimes", + "__futimes64"); my_lutimes_func = (lutimes_func*) lookup_time_t_function("lutimes", "__lutimes64"); my_futimens_func = (futimens_func*) lookup_time_t_function("futimens", "__futimens64"); #else -#ifndef _ALLBSD_SOURCE - my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat"); + my_futimes_func = (futimes_func*) dlsym(RTLD_DEFAULT, "futimes"); my_lutimes_func = (lutimes_func*) dlsym(RTLD_DEFAULT, "lutimes"); -#endif my_futimens_func = (futimens_func*) dlsym(RTLD_DEFAULT, "futimens"); #endif #if defined(_AIX) // Make sure we link to the 64-bit version of the function my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir64"); +#elif defined(_ALLBSD_SOURCE) + my_fdopendir_func = (fdopendir_func*) fdopendir; #else my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir"); #endif @@ -396,13 +399,13 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) my_fstatat_func = (fstatat_func*)&fstatat_wrapper; #endif - /* supports futimes or futimesat, futimens, and/or lutimes */ + /* supports futimes, futimens, and/or lutimes */ #ifdef _ALLBSD_SOURCE capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES; capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_LUTIMES; #else - if (my_futimesat_func != NULL) + if (my_futimes_func != NULL) capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES; if (my_lutimes_func != NULL) capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_LUTIMES; @@ -414,7 +417,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) if (my_openat_func != NULL && my_fstatat_func != NULL && my_unlinkat_func != NULL && my_renameat_func != NULL && - my_futimesat_func != NULL && my_fdopendir_func != NULL) + my_futimes_func != NULL && my_fdopendir_func != NULL) { capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_OPENAT; } @@ -620,19 +623,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); + + // Check mask for birth time and set flag accordingly. The birth time is + // filled in if and only if the STATX_BTIME bit is set in the mask. + // Although the statx system call might be supported by the operating + // system, the birth time is not necessarily supported by the file system. 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); + (*env)->SetBooleanField(env, attrs, attrs_birthtime_available, (jboolean)JNI_TRUE); + (*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)->SetBooleanField(env, attrs, attrs_birthtime_available, (jboolean)JNI_FALSE); } + (*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); @@ -661,7 +664,9 @@ static void copy_stat_attributes(JNIEnv* env, struct stat* buf, jobject attrs) { (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime); #ifdef _DARWIN_FEATURE_64_BIT_INODE + // birthtime_available defaults to 'false'; on Darwin, it is always true (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime); + (*env)->SetBooleanField(env, attrs, attrs_birthtime_available, (jboolean)JNI_TRUE); // rely on default value of 0 for st_birthtime_nsec field on Darwin #endif @@ -909,11 +914,11 @@ Java_sun_nio_fs_UnixNativeDispatcher_futimes0(JNIEnv* env, jclass this, jint fil #ifdef _ALLBSD_SOURCE RESTARTABLE(futimes(filedes, ×[0]), err); #else - if (my_futimesat_func == NULL) { - JNU_ThrowInternalError(env, "my_futimesat_func is NULL"); + if (my_futimes_func == NULL) { + JNU_ThrowInternalError(env, "my_futimes_func is NULL"); return; } - RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err); + RESTARTABLE((*my_futimes_func)(filedes, ×[0]), err); #endif if (err == -1) { throwUnixException(env, errno); diff --git a/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java b/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java index d53d9eb9e4bf7..6b7a81c2e85ff 100644 --- a/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.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 @@ -101,6 +101,14 @@ long size(FileDescriptor fd) throws IOException { return size0(fd); } + int available(FileDescriptor fd) throws IOException { + return available0(fd); + } + + boolean isOther(FileDescriptor fd) throws IOException { + return isOther0(fd); + } + int lock(FileDescriptor fd, boolean blocking, long pos, long size, boolean shared) throws IOException { @@ -223,6 +231,10 @@ static native int truncate0(FileDescriptor fd, long size) static native long size0(FileDescriptor fd) throws IOException; + static native int available0(FileDescriptor fd) throws IOException; + + static native boolean isOther0(FileDescriptor fd) throws IOException; + static native int lock0(FileDescriptor fd, boolean blocking, long pos, long size, boolean shared) throws IOException; diff --git a/src/java.base/windows/native/libjava/Console_md.c b/src/java.base/windows/native/libjava/Console_md.c index 9423f7d9e318f..f73e62f8e2603 100644 --- a/src/java.base/windows/native/libjava/Console_md.c +++ b/src/java.base/windows/native/libjava/Console_md.c @@ -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 @@ -49,17 +49,3 @@ Java_java_io_Console_istty(JNIEnv *env, jclass cls) return JNI_TRUE; } - -JNIEXPORT jstring JNICALL -Java_java_io_Console_encoding(JNIEnv *env, jclass cls) -{ - char buf[64]; - int cp = GetConsoleCP(); - if (cp >= 874 && cp <= 950) - snprintf(buf, sizeof(buf), "ms%d", cp); - else if (cp == 65001) - snprintf(buf, sizeof(buf), "UTF-8"); - else - snprintf(buf, sizeof(buf), "cp%d", cp); - return JNU_NewStringPlatform(env, buf); -} diff --git a/src/java.base/windows/native/libjava/io_util_md.c b/src/java.base/windows/native/libjava/io_util_md.c index a5f1ced36c5f8..6a8bd4342800a 100644 --- a/src/java.base/windows/native/libjava/io_util_md.c +++ b/src/java.base/windows/native/libjava/io_util_md.c @@ -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 @@ -595,3 +595,9 @@ handleGetLength(FD fd) { return -1; } } + +jboolean +handleIsRegularFile(JNIEnv* env, FD fd) +{ + return JNI_TRUE; +} diff --git a/src/java.base/windows/native/libjava/io_util_md.h b/src/java.base/windows/native/libjava/io_util_md.h index d9f239a25c5f3..82615cc822271 100644 --- a/src/java.base/windows/native/libjava/io_util_md.h +++ b/src/java.base/windows/native/libjava/io_util_md.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, 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 @@ -51,6 +51,7 @@ jint handleAppend(FD fd, const void *buf, jint len); void fileDescriptorClose(JNIEnv *env, jobject this); JNIEXPORT jlong JNICALL handleLseek(FD fd, jlong offset, jint whence); +jboolean handleIsRegularFile(JNIEnv* env, FD fd); /* * Returns an opaque handle to file named by "path". If an error occurs, @@ -82,6 +83,7 @@ FD getFD(JNIEnv *env, jobject cur, jfieldID fid); #define IO_Available handleAvailable #define IO_SetLength handleSetLength #define IO_GetLength handleGetLength +#define IO_IsRegularFile handleIsRegularFile /* * Setting the handle field in Java_java_io_FileDescriptor_set for diff --git a/src/java.base/windows/native/libjli/java_md.c b/src/java.base/windows/native/libjli/java_md.c index 6ff155bcb9b2a..a1012bcc4f938 100644 --- a/src/java.base/windows/native/libjli/java_md.c +++ b/src/java.base/windows/native/libjli/java_md.c @@ -45,9 +45,9 @@ /* * Prototypes. */ -static jboolean GetJVMPath(const char *jrepath, const char *jvmtype, +static jboolean GetJVMPath(const char *jdkroot, const char *jvmtype, char *jvmpath, jint jvmpathsize); -static jboolean GetJREPath(char *path, jint pathsize); +static jboolean GetJDKInstallRoot(char *path, jint pathsize); /* We supports warmup for UI stack that is performed in parallel * to VM initialization. @@ -152,7 +152,7 @@ IsJavaw() */ void CreateExecutionEnvironment(int *pargc, char ***pargv, - char *jrepath, jint so_jrepath, + char *jdkroot, jint so_jdkroot, char *jvmpath, jint so_jvmpath, char *jvmcfg, jint so_jvmcfg) { @@ -160,14 +160,14 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, int i = 0; char** argv = *pargv; - /* Find out where the JRE is that we will be using. */ - if (!GetJREPath(jrepath, so_jrepath)) { - JLI_ReportErrorMessage(JRE_ERROR1); + /* Find out where the JDK is that we will be using. */ + if (!GetJDKInstallRoot(jdkroot, so_jdkroot)) { + JLI_ReportErrorMessage(LAUNCHER_ERROR1); exit(2); } JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg", - jrepath, FILESEP, FILESEP); + jdkroot, FILESEP, FILESEP); /* Find the specified JVM type */ if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) { @@ -182,7 +182,7 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, } jvmpath[0] = '\0'; - if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { + if (!GetJVMPath(jdkroot, jvmtype, jvmpath, so_jvmpath)) { JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } @@ -223,18 +223,18 @@ LoadMSVCRT() if (!loaded) { /* - * The Microsoft C Runtime Library needs to be loaded first. A copy is - * assumed to be present in the "JRE path" directory. If it is not found - * there (or "JRE path" fails to resolve), skip the explicit load and let - * nature take its course, which is likely to be a failure to execute. - * The makefiles will provide the correct lib contained in quotes in the - * macro MSVCR_DLL_NAME. + * The Microsoft C Runtime Library needs to be loaded first. A copy is + * assumed to be present in the "bin" directory of the JDK installation root. + * If it is not found there (or the JDK installation root fails to resolve), + * skip the explicit load and let nature take its course, which is likely to + * be a failure to execute. The makefiles will provide the correct lib contained + * in quotes in the macro MSVCR_DLL_NAME. */ #ifdef MSVCR_DLL_NAME - if (GetJREPath(crtpath, MAXPATHLEN)) { + if (GetJDKInstallRoot(crtpath, MAXPATHLEN)) { if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + JLI_StrLen(MSVCR_DLL_NAME) >= MAXPATHLEN) { - JLI_ReportErrorMessage(JRE_ERROR11); + JLI_ReportErrorMessage(LAUNCHER_ERROR3); return JNI_FALSE; } (void)JLI_StrCat(crtpath, "\\bin\\" MSVCR_DLL_NAME); /* Add crt dll */ @@ -248,10 +248,10 @@ LoadMSVCRT() } #endif /* MSVCR_DLL_NAME */ #ifdef VCRUNTIME_1_DLL_NAME - if (GetJREPath(crtpath, MAXPATHLEN)) { + if (GetJDKInstallRoot(crtpath, MAXPATHLEN)) { if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + JLI_StrLen(VCRUNTIME_1_DLL_NAME) >= MAXPATHLEN) { - JLI_ReportErrorMessage(JRE_ERROR11); + JLI_ReportErrorMessage(LAUNCHER_ERROR3); return JNI_FALSE; } (void)JLI_StrCat(crtpath, "\\bin\\" VCRUNTIME_1_DLL_NAME); /* Add crt dll */ @@ -265,10 +265,10 @@ LoadMSVCRT() } #endif /* VCRUNTIME_1_DLL_NAME */ #ifdef MSVCP_DLL_NAME - if (GetJREPath(crtpath, MAXPATHLEN)) { + if (GetJDKInstallRoot(crtpath, MAXPATHLEN)) { if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + JLI_StrLen(MSVCP_DLL_NAME) >= MAXPATHLEN) { - JLI_ReportErrorMessage(JRE_ERROR11); + JLI_ReportErrorMessage(LAUNCHER_ERROR3); return JNI_FALSE; } (void)JLI_StrCat(crtpath, "\\bin\\" MSVCP_DLL_NAME); /* Add prt dll */ @@ -288,47 +288,47 @@ LoadMSVCRT() /* - * Find path to JRE based on .exe's location or registry settings. + * Find path to JDK installation root based on .exe's location */ jboolean -GetJREPath(char *path, jint pathsize) +GetJDKInstallRoot(char *path, jint pathsize) { char javadll[MAXPATHLEN]; struct stat s; - JLI_TraceLauncher("Attempt to get JRE path from launcher executable path\n"); + JLI_TraceLauncher("Attempt to get JDK installation root path from launcher executable path\n"); if (GetApplicationHome(path, pathsize)) { - /* Is JRE co-located with the application? */ + /* Is the JDK co-located with the application? */ JLI_Snprintf(javadll, sizeof(javadll), "%s\\bin\\" JAVA_DLL, path); if (stat(javadll, &s) == 0) { - JLI_TraceLauncher("JRE path is %s\n", path); + JLI_TraceLauncher("JDK installation root path is %s\n", path); return JNI_TRUE; } } - JLI_TraceLauncher("Attempt to get JRE path from shared lib of the image\n"); + JLI_TraceLauncher("Attempt to get JDK installation root path from shared lib of the image\n"); - /* Try getting path to JRE from path to JLI.DLL */ + /* Try getting path to JDK from path to JLI.DLL */ if (GetApplicationHomeFromDll(path, pathsize)) { JLI_Snprintf(javadll, sizeof(javadll), "%s\\bin\\" JAVA_DLL, path); if (stat(javadll, &s) == 0) { - JLI_TraceLauncher("JRE path is %s\n", path); + JLI_TraceLauncher("JDK installation root path is %s\n", path); return JNI_TRUE; } } - JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); + JLI_ReportErrorMessage(LAUNCHER_ERROR2 JAVA_DLL); return JNI_FALSE; } /* - * Given a JRE location and a JVM type, construct what the name the + * Given a JDK installation location and a JVM type, construct what the name the * JVM shared library will be. Return true, if such a library * exists, false otherwise. */ static jboolean -GetJVMPath(const char *jrepath, const char *jvmtype, +GetJVMPath(const char *jdkroot, const char *jvmtype, char *jvmpath, jint jvmpathsize) { struct stat s; @@ -336,7 +336,7 @@ GetJVMPath(const char *jrepath, const char *jvmtype, JLI_Snprintf(jvmpath, jvmpathsize, "%s\\" JVM_DLL, jvmtype); } else { JLI_Snprintf(jvmpath, jvmpathsize, "%s\\bin\\%s\\" JVM_DLL, - jrepath, jvmtype); + jdkroot, jvmtype); } if (stat(jvmpath, &s) == 0) { return JNI_TRUE; @@ -356,10 +356,11 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) JLI_TraceLauncher("JVM path is %s\n", jvmpath); /* - * The Microsoft C Runtime Library needs to be loaded first. A copy is - * assumed to be present in the "JRE path" directory. If it is not found - * there (or "JRE path" fails to resolve), skip the explicit load and let - * nature take its course, which is likely to be a failure to execute. + * The Microsoft C Runtime Library needs to be loaded first. A copy is + * assumed to be present within the JDK. If it is not found there + * (or the JDK installation root fails to resolve), skip the explicit + * load and let nature take its course, which is likely to be a failure + * to execute. * */ LoadMSVCRT(); @@ -403,7 +404,7 @@ TruncatePath(char *buf) } /* - * Retrieves the path to the JRE home by locating the executable file + * Retrieves the path to the JDK home by locating the executable file * of the current process and then truncating the path to the executable */ jboolean @@ -414,7 +415,7 @@ GetApplicationHome(char *buf, jint bufsize) } /* - * Retrieves the path to the JRE home by locating JLI.DLL and + * Retrieves the path to the JDK home by locating JLI.DLL and * then truncating the path to JLI.DLL */ jboolean @@ -424,7 +425,7 @@ GetApplicationHomeFromDll(char *buf, jint bufsize) DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; - if (GetModuleHandleEx(flags, (LPCSTR)&GetJREPath, &module) != 0) { + if (GetModuleHandleEx(flags, (LPCSTR)&GetJDKInstallRoot, &module) != 0) { if (GetModuleFileName(module, buf, bufsize) != 0) { return TruncatePath(buf); } @@ -659,7 +660,7 @@ static HMODULE hSplashLib = NULL; void* SplashProcAddress(const char* name) { char libraryPath[MAXPATHLEN]; /* some extra space for JLI_StrCat'ing SPLASHSCREEN_SO */ - if (!GetJREPath(libraryPath, MAXPATHLEN)) { + if (!GetJDKInstallRoot(libraryPath, MAXPATHLEN)) { return NULL; } if (JLI_StrLen(libraryPath)+JLI_StrLen(SPLASHSCREEN_SO) >= MAXPATHLEN) { @@ -830,7 +831,7 @@ int AWTPreload(const char *funcName) if (hPreloadAwt == NULL) { /* awt.dll is not loaded yet */ char libraryPath[MAXPATHLEN]; - size_t jrePathLen = 0; + size_t jdkRootPathLen = 0; HMODULE hJava = NULL; HMODULE hVerify = NULL; @@ -839,18 +840,18 @@ int AWTPreload(const char *funcName) * jvm.dll is already loaded, so we need only java.dll; * java.dll depends on MSVCRT lib & verify.dll. */ - if (!GetJREPath(libraryPath, MAXPATHLEN)) { + if (!GetJDKInstallRoot(libraryPath, MAXPATHLEN)) { break; } /* save path length */ - jrePathLen = JLI_StrLen(libraryPath); + jdkRootPathLen = JLI_StrLen(libraryPath); - if (jrePathLen + JLI_StrLen("\\bin\\verify.dll") >= MAXPATHLEN) { - /* jre path is too long, the library path will not fit there; + if (jdkRootPathLen + JLI_StrLen("\\bin\\verify.dll") >= MAXPATHLEN) { + /* path is too long, the library path will not fit there; * report and abort preloading */ - JLI_ReportErrorMessage(JRE_ERROR11); + JLI_ReportErrorMessage(LAUNCHER_ERROR3); break; } @@ -864,8 +865,8 @@ int AWTPreload(const char *funcName) break; } - /* restore jrePath */ - libraryPath[jrePathLen] = 0; + /* restore libraryPath */ + libraryPath[jdkRootPathLen] = 0; /* load java.dll */ JLI_StrCat(libraryPath, "\\bin\\" JAVA_DLL); hJava = LoadLibrary(libraryPath); @@ -873,8 +874,8 @@ int AWTPreload(const char *funcName) break; } - /* restore jrePath */ - libraryPath[jrePathLen] = 0; + /* restore libraryPath */ + libraryPath[jdkRootPathLen] = 0; /* load awt.dll */ JLI_StrCat(libraryPath, "\\bin\\awt.dll"); hPreloadAwt = LoadLibrary(libraryPath); diff --git a/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c index 91effcf0bd0fa..ef5c3e0792952 100644 --- a/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c @@ -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 @@ -24,6 +24,7 @@ */ #include +#include #include "jni.h" #include "jni_util.h" #include "jvm.h" @@ -33,6 +34,7 @@ #include "nio_util.h" #include "java_lang_Integer.h" #include "sun_nio_ch_FileDispatcherImpl.h" +#include "io_util_md.h" #include // Requires Mswsock.lib @@ -392,6 +394,75 @@ Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) return (jlong)size.QuadPart; } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_available0(JNIEnv *env, jobject this, jobject fdo) +{ + HANDLE handle = (HANDLE)(handleval(env, fdo)); + DWORD type = GetFileType(handle); + jlong available = 0; + + // Calculate the number of bytes available for a regular file, + // and return the default (zero) for other types. + if (type == FILE_TYPE_DISK) { + jlong current, end; + LARGE_INTEGER distance, pos, filesize; + distance.QuadPart = 0; + if (SetFilePointerEx(handle, distance, &pos, FILE_CURRENT) == 0) { + JNU_ThrowIOExceptionWithLastError(env, "Available failed"); + return IOS_THROWN; + } + current = (jlong)pos.QuadPart; + if (GetFileSizeEx(handle, &filesize) == 0) { + JNU_ThrowIOExceptionWithLastError(env, "Available failed"); + return IOS_THROWN; + } + end = (jlong)filesize.QuadPart; + available = end - current; + if (available > java_lang_Integer_MAX_VALUE) { + available = java_lang_Integer_MAX_VALUE; + } else if (available < 0) { + available = 0; + } + } + + return (jint)available; +} + + +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_FileDispatcherImpl_isOther0(JNIEnv *env, jobject this, jobject fdo) +{ + HANDLE handle = (HANDLE)(handleval(env, fdo)); + + BY_HANDLE_FILE_INFORMATION finfo; + if (!GetFileInformationByHandle(handle, &finfo)) + JNU_ThrowIOExceptionWithLastError(env, "isOther failed"); + DWORD fattr = finfo.dwFileAttributes; + + if ((fattr & FILE_ATTRIBUTE_DEVICE) != 0) + return (jboolean)JNI_TRUE; + + if ((fattr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; + void* lpOutBuffer = (void*)malloc(size*sizeof(char)); + if (lpOutBuffer == NULL) + JNU_ThrowOutOfMemoryError(env, "isOther failed"); + + DWORD bytesReturned; + if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, + lpOutBuffer, (DWORD)size, &bytesReturned, NULL)) { + free(lpOutBuffer); + JNU_ThrowIOExceptionWithLastError(env, "isOther failed"); + } + ULONG reparseTag = (*((PULONG)lpOutBuffer)); + free(lpOutBuffer); + return reparseTag == IO_REPARSE_TAG_SYMLINK ? + (jboolean)JNI_FALSE : (jboolean)JNI_TRUE; + } + + return (jboolean)JNI_FALSE; +} + JNIEXPORT jint JNICALL Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, jboolean block, jlong pos, jlong size, diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java index 5159ac26e3bfa..7f0b493572e0d 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java @@ -81,8 +81,8 @@ public interface Elements { * @implSpec The default implementation of this method returns * {@code null}. * - * @param name fully qualified package name, or an empty string for an unnamed package * @param module module relative to which the lookup should happen + * @param name fully qualified package name, or an empty string for an unnamed package * @return the specified package, or {@code null} if it cannot be found * @see #getAllPackageElements * @since 9 @@ -167,8 +167,8 @@ default Set getAllPackageElements(CharSequence name) { * @implSpec The default implementation of this method returns * {@code null}. * - * @param name the canonical name * @param module module relative to which the lookup should happen + * @param name the canonical name * @return the named type element, or {@code null} if it cannot be found * @see #getAllTypeElements * @since 9 diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java index ce83cda405862..951b56ed2149a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java @@ -206,7 +206,7 @@ public interface Types { * * @throws IllegalArgumentException if the given type has no * unboxing conversion. Only types for the {@linkplain - * java.lang##wrapperClasses wrapper classes} have an + * java.lang##wrapperClass wrapper classes} have an * unboxing conversion. * @jls 5.1.8 Unboxing Conversion */ @@ -263,7 +263,10 @@ public interface Types { * * @param componentType the component type * @throws IllegalArgumentException if the component type is not valid for - * an array, including executable, package, module, and wildcard types + * an array. All valid types are {@linkplain ReferenceType + * reference types} or {@linkplain PrimitiveType primitive types}. + * Invalid types include {@linkplain NullType null}, executable, package, + * module, and wildcard types. * @jls 10.1 Array Types */ ArrayType getArrayType(TypeMirror componentType); diff --git a/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java b/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java index dd4d17be3a17b..bc7124aa2ad03 100644 --- a/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java +++ b/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java @@ -31,20 +31,27 @@ import java.awt.geom.AffineTransform; import java.awt.image.ColorModel; +import sun.awt.image.SurfaceManager; import sun.java2d.SurfaceData; import sun.lwawt.LWGraphicsConfig; import sun.lwawt.macosx.CFRetainedResource; public abstract class CGraphicsConfig extends GraphicsConfiguration - implements LWGraphicsConfig { + implements LWGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig { private final CGraphicsDevice device; private ColorModel colorModel; + private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); protected CGraphicsConfig(CGraphicsDevice device) { this.device = device; } + @Override + public SurfaceManager.ProxyCache getSurfaceDataProxyCache() { + return surfaceDataProxyCache; + } + @Override public final Rectangle getBounds() { return device.getBounds(); diff --git a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java index 8a992361b9628..2b70c39146b24 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java +++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java @@ -29,7 +29,6 @@ import sun.awt.CGraphicsDevice; import sun.awt.image.OffScreenImage; import sun.awt.image.SunVolatileImage; -import sun.awt.image.SurfaceManager; import sun.java2d.Disposer; import sun.java2d.DisposerRecord; import sun.java2d.Surface; @@ -70,7 +69,7 @@ import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER; public final class MTLGraphicsConfig extends CGraphicsConfig - implements AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig + implements AccelGraphicsConfig { private static ImageCapabilities imageCaps = new MTLImageCaps(); @@ -112,11 +111,6 @@ private MTLGraphicsConfig(CGraphicsDevice device, new MTLGCDisposerRecord(pConfigInfo)); } - @Override - public Object getProxyKey() { - return this; - } - public SurfaceData createManagedSurface(int w, int h, int transparency) { return MTLSurfaceData.createData(this, w, h, getColorModel(transparency), diff --git a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java index 9204bffda6a39..edee1157806c6 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java +++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java @@ -156,7 +156,7 @@ private MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc, super(getCustomSurfaceType(type), cm); this.graphicsConfig = gc; this.type = type; - setBlitProxyKey(gc.getProxyKey()); + setBlitProxyCache(gc.getSurfaceDataProxyCache()); // TEXTURE shouldn't be scaled, it is used for managed BufferedImages. scale = type == TEXTURE ? 1 : gc.getDevice().getScaleFactor(); diff --git a/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java b/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java index bea5963383e34..f59d41b6b83d1 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java +++ b/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java @@ -105,11 +105,6 @@ private CGLGraphicsConfig(CGraphicsDevice device, long configInfo, new CGLGCDisposerRecord(pConfigInfo)); } - @Override - public Object getProxyKey() { - return this; - } - @Override public SurfaceData createManagedSurface(int w, int h, int transparency) { return CGLSurfaceData.createData(this, w, h, diff --git a/src/java.desktop/share/classes/java/awt/BorderLayout.java b/src/java.desktop/share/classes/java/awt/BorderLayout.java index e3b92a7996ae7..c5bb016b944ae 100644 --- a/src/java.desktop/share/classes/java/awt/BorderLayout.java +++ b/src/java.desktop/share/classes/java/awt/BorderLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2021, 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 @@ -554,12 +554,12 @@ public Component getLayoutComponent(Object constraints) { * The {@code Container}'s component orientation is used to determine the location of components * added with {@code LINE_START} and {@code LINE_END}. * - * @param constraints the desired absolute position, one of {@code CENTER}, - * {@code NORTH}, {@code SOUTH}, - * {@code EAST}, {@code WEST} * @param target the {@code Container} used to obtain * the constraint location based on the target * {@code Container}'s component orientation. + * @param constraints the desired absolute position, one of {@code CENTER}, + * {@code NORTH}, {@code SOUTH}, + * {@code EAST}, {@code WEST} * @return the component at the given location, or {@code null} if * the location is empty * @throws IllegalArgumentException if the constraint object is diff --git a/src/java.desktop/share/classes/java/awt/Graphics2D.java b/src/java.desktop/share/classes/java/awt/Graphics2D.java index 93d4fe2c9bca3..0f06fa48ad621 100644 --- a/src/java.desktop/share/classes/java/awt/Graphics2D.java +++ b/src/java.desktop/share/classes/java/awt/Graphics2D.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -564,9 +564,9 @@ public abstract boolean drawImage(Image img, * img1 = op.filter(img, null); * drawImage(img1, new AffineTransform(1f,0f,0f,1f,x,y), null); * - * @param op the filter to be applied to the image before rendering * @param img the specified {@code BufferedImage} to be rendered. * This method does nothing if {@code img} is null. + * @param op the filter to be applied to the image before rendering * @param x the x coordinate of the location in user space where * the upper left corner of the image is rendered * @param y the y coordinate of the location in user space where diff --git a/src/java.desktop/share/classes/java/awt/dnd/DragSource.java b/src/java.desktop/share/classes/java/awt/dnd/DragSource.java index e7c3840e206d5..01945662e4686 100644 --- a/src/java.desktop/share/classes/java/awt/dnd/DragSource.java +++ b/src/java.desktop/share/classes/java/awt/dnd/DragSource.java @@ -499,8 +499,8 @@ protected DragSourceContext createDragSourceContext(DragGestureEvent dgl, * * @param the type of {@code DragGestureRecognizer} to create * @param recognizerAbstractClass the requested abstract type - * @param actions the permitted source drag actions * @param c the {@code Component} target + * @param actions the permitted source drag actions * @param dgl the {@code DragGestureListener} to notify * * @return the new {@code DragGestureRecognizer} or {@code null} diff --git a/src/java.desktop/share/classes/java/awt/event/ActionEvent.java b/src/java.desktop/share/classes/java/awt/event/ActionEvent.java index 1a6707cbfe760..e9a4ad0ce5945 100644 --- a/src/java.desktop/share/classes/java/awt/event/ActionEvent.java +++ b/src/java.desktop/share/classes/java/awt/event/ActionEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,13 +206,13 @@ public ActionEvent(Object source, int id, String command, int modifiers) { * the class description for {@link ActionEvent} * @param command A string that may specify a command (possibly one * of several) associated with the event + * @param when A long that gives the time the event occurred. + * Passing negative or zero value + * is not recommended * @param modifiers The modifier keys down during event * (shift, ctrl, alt, meta). * Passing negative parameter is not recommended. * Zero value means that no modifiers were passed - * @param when A long that gives the time the event occurred. - * Passing negative or zero value - * is not recommended * @throws IllegalArgumentException if {@code source} is null * @see #getSource() * @see #getID() diff --git a/src/java.desktop/share/classes/java/awt/font/TextLayout.java b/src/java.desktop/share/classes/java/awt/font/TextLayout.java index 352d3c81df247..855097b6a26b0 100644 --- a/src/java.desktop/share/classes/java/awt/font/TextLayout.java +++ b/src/java.desktop/share/classes/java/awt/font/TextLayout.java @@ -2663,11 +2663,20 @@ static byte getBaselineFromGraphic(GraphicAttribute graphic) { */ public Shape getOutline(AffineTransform tx) { ensureCache(); - Shape result = textLine.getOutline(tx); + Shape result = textLine.getOutline(); LayoutPathImpl lp = textLine.getLayoutPath(); if (lp != null) { result = lp.mapShape(result); } + if (tx != null) { + if (result instanceof GeneralPath gp) { + // transform in place + gp.transform(tx); + } else { + // create a transformed copy + result = tx.createTransformedShape(result); + } + } return result; } diff --git a/src/java.desktop/share/classes/java/awt/font/TextLine.java b/src/java.desktop/share/classes/java/awt/font/TextLine.java index 9d5da23bfe76a..1e4b9c784a69c 100644 --- a/src/java.desktop/share/classes/java/awt/font/TextLine.java +++ b/src/java.desktop/share/classes/java/awt/font/TextLine.java @@ -864,19 +864,15 @@ public Rectangle2D getItalicBounds() { return new Rectangle2D.Float(left, top, right-left, bottom-top); } - public Shape getOutline(AffineTransform tx) { + public Shape getOutline() { GeneralPath dstShape = new GeneralPath(GeneralPath.WIND_NON_ZERO); for (int i=0, n = 0; i < fComponents.length; i++, n += 2) { TextLineComponent tlc = fComponents[getComponentLogicalIndex(i)]; - dstShape.append(tlc.getOutline(locs[n], locs[n+1]), false); } - if (tx != null) { - dstShape.transform(tx); - } return dstShape; } diff --git a/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java b/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java index fde67ba06a4fb..9abc55d8e6f2a 100644 --- a/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java +++ b/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2964,10 +2964,10 @@ public Point2D transform(Point2D ptSrc, Point2D ptDst) { * the original coordinates in that point are overwritten before * they can be converted. * @param ptSrc the array containing the source point objects - * @param ptDst the array into which the transform point objects are - * returned * @param srcOff the offset to the first point object to be * transformed in the source array + * @param ptDst the array into which the transform point objects are + * returned * @param dstOff the offset to the location of the first * transformed point object that is stored in the destination array * @param numPts the number of point objects to be transformed @@ -3038,11 +3038,11 @@ public void transform(Point2D[] ptSrc, int srcOff, * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. * @param srcPts the array containing the source point coordinates. * Each point is stored as a pair of x, y coordinates. + * @param srcOff the offset to the first point to be transformed + * in the source array * @param dstPts the array into which the transformed point coordinates * are returned. Each point is stored as a pair of x, y * coordinates. - * @param srcOff the offset to the first point to be transformed - * in the source array * @param dstOff the offset to the location of the first * transformed point that is stored in the destination array * @param numPts the number of points to be transformed @@ -3153,11 +3153,11 @@ public void transform(float[] srcPts, int srcOff, * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. * @param srcPts the array containing the source point coordinates. * Each point is stored as a pair of x, y coordinates. + * @param srcOff the offset to the first point to be transformed + * in the source array * @param dstPts the array into which the transformed point * coordinates are returned. Each point is stored as a pair of * x, y coordinates. - * @param srcOff the offset to the first point to be transformed - * in the source array * @param dstOff the offset to the location of the first * transformed point that is stored in the destination array * @param numPts the number of point objects to be transformed @@ -3264,11 +3264,11 @@ public void transform(double[] srcPts, int srcOff, * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. * @param srcPts the array containing the source point coordinates. * Each point is stored as a pair of x, y coordinates. + * @param srcOff the offset to the first point to be transformed + * in the source array * @param dstPts the array into which the transformed point coordinates * are returned. Each point is stored as a pair of x, y * coordinates. - * @param srcOff the offset to the first point to be transformed - * in the source array * @param dstOff the offset to the location of the first * transformed point that is stored in the destination array * @param numPts the number of points to be transformed @@ -3360,11 +3360,11 @@ public void transform(float[] srcPts, int srcOff, * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. * @param srcPts the array containing the source point coordinates. * Each point is stored as a pair of x, y coordinates. + * @param srcOff the offset to the first point to be transformed + * in the source array * @param dstPts the array into which the transformed point * coordinates are returned. Each point is stored as a pair of * x, y coordinates. - * @param srcOff the offset to the first point to be transformed - * in the source array * @param dstOff the offset to the location of the first * transformed point that is stored in the destination array * @param numPts the number of point objects to be transformed @@ -3542,11 +3542,11 @@ public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst) * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. * @param srcPts the array containing the source point coordinates. * Each point is stored as a pair of x, y coordinates. + * @param srcOff the offset to the first point to be transformed + * in the source array * @param dstPts the array into which the transformed point * coordinates are returned. Each point is stored as a pair of * x, y coordinates. - * @param srcOff the offset to the first point to be transformed - * in the source array * @param dstOff the offset to the location of the first * transformed point that is stored in the destination array * @param numPts the number of point objects to be transformed @@ -3755,11 +3755,11 @@ public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) { * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. * @param srcPts the array containing the source distance vectors. * Each vector is stored as a pair of relative x, y coordinates. + * @param srcOff the offset to the first vector to be transformed + * in the source array * @param dstPts the array into which the transformed distance vectors * are returned. Each vector is stored as a pair of relative * x, y coordinates. - * @param srcOff the offset to the first vector to be transformed - * in the source array * @param dstOff the offset to the location of the first * transformed vector that is stored in the destination array * @param numPts the number of vector coordinate pairs to be diff --git a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java index d81b0df3c876f..ed9444b83af42 100644 --- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java +++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -378,10 +378,10 @@ protected void addElement(String elementName, * Adds an existing element to the list of legal children for a * given parent node type. * - * @param parentName the name of the element that will be the - * new parent of the element. * @param elementName the name of the element to be added as a * child. + * @param parentName the name of the element that will be the + * new parent of the element. * * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this diff --git a/src/java.desktop/share/classes/javax/swing/GroupLayout.java b/src/java.desktop/share/classes/javax/swing/GroupLayout.java index 3a4a6d78ca6e4..2207a1ae877b0 100644 --- a/src/java.desktop/share/classes/javax/swing/GroupLayout.java +++ b/src/java.desktop/share/classes/javax/swing/GroupLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1777,9 +1777,9 @@ public SequentialGroup addGroup(Group group) { /** * Adds a {@code Group} to this {@code Group}. * - * @param group the {@code Group} to add * @param useAsBaseline whether the specified {@code Group} should * be used to calculate the baseline for this {@code Group} + * @param group the {@code Group} to add * @return this {@code Group} */ public SequentialGroup addGroup(boolean useAsBaseline, Group group) { @@ -2528,8 +2528,8 @@ public ParallelGroup addGroup(Alignment alignment, Group group) { * Adds a {@code Component} to this {@code ParallelGroup} with * the specified alignment. * - * @param alignment the alignment * @param component the {@code Component} to add + * @param alignment the alignment * @return this {@code Group} * @throws IllegalArgumentException if {@code alignment} is * {@code null} @@ -2544,8 +2544,8 @@ public ParallelGroup addComponent(Component component, * Adds a {@code Component} to this {@code ParallelGroup} with the * specified alignment and size. * - * @param alignment the alignment * @param component the {@code Component} to add + * @param alignment the alignment * @param min the minimum size * @param pref the preferred size * @param max the maximum size diff --git a/src/java.desktop/share/classes/javax/swing/JColorChooser.java b/src/java.desktop/share/classes/javax/swing/JColorChooser.java index 945c6f6069704..62c4fe8b0838a 100644 --- a/src/java.desktop/share/classes/javax/swing/JColorChooser.java +++ b/src/java.desktop/share/classes/javax/swing/JColorChooser.java @@ -175,7 +175,9 @@ public static Color showDialog(Component component, * @return the selected color or null if the user opted out * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. + * * @see java.awt.GraphicsEnvironment#isHeadless + * @since 9 */ @SuppressWarnings("deprecation") public static Color showDialog(Component component, String title, diff --git a/src/java.desktop/share/classes/javax/swing/LayoutStyle.java b/src/java.desktop/share/classes/javax/swing/LayoutStyle.java index e45777565a84d..f1c384db6e20d 100644 --- a/src/java.desktop/share/classes/javax/swing/LayoutStyle.java +++ b/src/java.desktop/share/classes/javax/swing/LayoutStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 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 @@ -165,13 +165,13 @@ public LayoutStyle() { * @param component1 the JComponent * component2 is being placed relative to * @param component2 the JComponent being placed + * @param type how the two components are being placed * @param position the position component2 is being placed * relative to component1; one of * SwingConstants.NORTH, * SwingConstants.SOUTH, * SwingConstants.EAST or * SwingConstants.WEST - * @param type how the two components are being placed * @param parent the parent of component2; this may differ * from the actual parent and it may be null * @return the amount of space to place between the two components diff --git a/src/java.desktop/share/classes/javax/swing/ProgressMonitorInputStream.java b/src/java.desktop/share/classes/javax/swing/ProgressMonitorInputStream.java index d82e2999b8b91..33e71d7bf515c 100644 --- a/src/java.desktop/share/classes/javax/swing/ProgressMonitorInputStream.java +++ b/src/java.desktop/share/classes/javax/swing/ProgressMonitorInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,10 +73,10 @@ public class ProgressMonitorInputStream extends FilterInputStream /** * Constructs an object to monitor the progress of an input stream. * - * @param message Descriptive text to be placed in the dialog box - * if one is popped up. * @param parentComponent The component triggering the operation * being monitored. + * @param message Descriptive text to be placed in the dialog box + * if one is popped up. * @param in The input stream to be monitored. */ public ProgressMonitorInputStream(Component parentComponent, diff --git a/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java b/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java index 9a42849251289..5664051cf6b61 100644 --- a/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java +++ b/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java @@ -229,6 +229,7 @@ void setSelectedColor(Color color) { * * @param b true if the transparency of a color can be selected * @see #isColorTransparencySelectionEnabled() + * @since 9 */ @BeanProperty(description = "Sets the transparency of a color selection on or off.") @@ -241,6 +242,7 @@ public void setColorTransparencySelectionEnabled(boolean b){ * * @return true if the transparency of a color can be selected * @see #setColorTransparencySelectionEnabled(boolean) + * @since 9 */ public boolean isColorTransparencySelectionEnabled(){ return true; diff --git a/src/java.desktop/share/classes/javax/swing/text/PlainView.java b/src/java.desktop/share/classes/javax/swing/text/PlainView.java index 0c245196d9954..6697ca4e2a39a 100644 --- a/src/java.desktop/share/classes/javax/swing/text/PlainView.java +++ b/src/java.desktop/share/classes/javax/swing/text/PlainView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -724,12 +724,12 @@ protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f) { /** * Repaint the given line range. * - * @param host the component hosting the view (used to call repaint) - * @param a the region allocated for the view to render into * @param line0 the starting line number to repaint. This must * be a valid line number in the model. * @param line1 the ending line number to repaint. This must * be a valid line number in the model. + * @param a the region allocated for the view to render into + * @param host the component hosting the view (used to call repaint) * @since 1.4 */ protected void damageLineRange(int line0, int line1, Shape a, Component host) { diff --git a/src/java.desktop/share/classes/javax/swing/text/TableView.java b/src/java.desktop/share/classes/javax/swing/text/TableView.java index 8573c9afe5995..702e79dd8fc69 100644 --- a/src/java.desktop/share/classes/javax/swing/text/TableView.java +++ b/src/java.desktop/share/classes/javax/swing/text/TableView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, 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 @@ -292,13 +292,13 @@ void addFill(int row, int col) { * * @param targetSpan the given span for total of all the table * columns + * @param offsets the return value of the offset from the + * origin for each column + * @param spans the return value of how much to allocated to + * each column * @param reqs the requirements desired for each column. This * is the column maximum of the cells minimum, preferred, and * maximum requested span - * @param spans the return value of how much to allocated to - * each column - * @param offsets the return value of the offset from the - * origin for each column */ protected void layoutColumns(int targetSpan, int[] offsets, int[] spans, SizeRequirements[] reqs) { diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java index 71a1096cfd5e5..f17804e624dcd 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.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 @@ -328,9 +328,9 @@ public void read(Reader in, Document doc, int pos) throws IOException, BadLocati * * @param doc the document to insert into * @param offset the offset to insert HTML at + * @param html the HTML string * @param popDepth the number of ElementSpec.EndTagTypes to generate * before inserting - * @param html the HTML string * @param pushDepth the number of ElementSpec.StartTagTypes with a direction * of ElementSpec.JoinNextDirection that should be generated * before inserting, but after the end tags have been generated diff --git a/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java b/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java index bb327889a8672..e81af32d05c42 100644 --- a/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java +++ b/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java @@ -31,8 +31,11 @@ import java.awt.ImageCapabilities; import java.awt.image.BufferedImage; import java.awt.image.VolatileImage; +import java.lang.ref.WeakReference; +import java.util.Collections; import java.util.Iterator; -import java.util.concurrent.ConcurrentHashMap; +import java.util.Map; +import java.util.WeakHashMap; import sun.java2d.InvalidPipeException; import sun.java2d.SurfaceData; @@ -89,47 +92,14 @@ public static void setManager(Image img, SurfaceManager mgr) { imgaccessor.setSurfaceManager(img, mgr); } - private volatile ConcurrentHashMap cacheMap; - - /** - * Return an arbitrary cached object for an arbitrary cache key. - * Other objects can use this mechanism to store cached data about - * the source image that will let them save time when using or - * manipulating the image in the future. - *

          - * Note that the cache is maintained as a simple Map with no - * attempts to keep it up to date or invalidate it so any data - * stored here must either not be dependent on the state of the - * image or it must be individually tracked to see if it is - * outdated or obsolete. - *

          - * The SurfaceData object of the primary (destination) surface - * has a StateTracker mechanism which can help track the validity - * and "currentness" of any data stored here. - * For convenience and expediency an object stored as cached - * data may implement the FlushableCacheData interface specified - * below so that it may be notified immediately if the flush() - * method is ever called. - */ - public Object getCacheData(Object key) { - return (cacheMap == null) ? null : cacheMap.get(key); - } - /** - * Store an arbitrary cached object for an arbitrary cache key. - * See the getCacheData() method for notes on tracking the - * validity of data stored using this mechanism. + * This map holds references to SurfaceDataProxy per given ProxyCache. + * Unlike ProxyCache, which contains SurfaceDataProxy objects per given SurfaceManager, + * this map does not prevent contained proxies from being garbage collected. + * Therefore, ProxyCache can be considered an "owning" container for the SurfaceDataProxy objects, + * and this map is just a weak mapping for the bookkeeping purposes. */ - public void setCacheData(Object key, Object value) { - if (cacheMap == null) { - synchronized (this) { - if (cacheMap == null) { - cacheMap = new ConcurrentHashMap<>(2); - } - } - } - cacheMap.put(key, value); - } + private final Map> weakCache = new WeakHashMap<>(2); /** * Returns the main SurfaceData object that "owns" the pixels for @@ -202,12 +172,10 @@ public boolean isAccelerated() { tmpGc = GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().getDefaultConfiguration(); } - if (tmpGc instanceof ProxiedGraphicsConfig) { - Object proxyKey = - ((ProxiedGraphicsConfig) tmpGc).getProxyKey(); - if (proxyKey != null) { - SurfaceDataProxy sdp = - (SurfaceDataProxy) getCacheData(proxyKey); + if (tmpGc instanceof ProxiedGraphicsConfig pgc) { + ProxyCache cache = pgc.getSurfaceDataProxyCache(); + if (cache != null) { + SurfaceDataProxy sdp = cache.get(SurfaceManager.this); return (sdp != null && sdp.isAccelerated()); } } @@ -222,13 +190,51 @@ public boolean isAccelerated() { * Implementing this interface facilitates the default * implementation of getImageCapabilities() above. */ - public static interface ProxiedGraphicsConfig { + public interface ProxiedGraphicsConfig { + /** - * Return the key that destination surfaces created on the + * Return the cache that destination surfaces created on the * given GraphicsConfiguration use to store SurfaceDataProxy * objects for their cached copies. */ - public Object getProxyKey(); + ProxyCache getSurfaceDataProxyCache(); + } + + public static class ProxyCache { + private final Map map = Collections.synchronizedMap(new WeakHashMap<>()); + + /** + * Return a cached SurfaceDataProxy object for a given SurfaceManager. + *

          + * Note that the cache is maintained as a simple Map with no + * attempts to keep it up to date or invalidate it so any data + * stored here must either not be dependent on the state of the + * image or it must be individually tracked to see if it is + * outdated or obsolete. + *

          + * The SurfaceData object of the primary (destination) surface + * has a StateTracker mechanism which can help track the validity + * and "currentness" of any data stored here. + * For convenience and expediency an object stored as cached + * data may implement the FlushableCacheData interface specified + * below so that it may be notified immediately if the flush() + * method is ever called. + */ + public SurfaceDataProxy get(SurfaceManager manager) { + return map.get(manager); + } + + /** + * Store a cached SurfaceDataProxy object for a given SurfaceManager. + * See the get() method for notes on tracking the + * validity of data stored using this mechanism. + */ + public void put(SurfaceManager manager, SurfaceDataProxy proxy) { + synchronized (manager.weakCache) { // Synchronize on weakCache first! + manager.weakCache.put(this, new WeakReference<>(proxy)); + map.put(manager, proxy); + } + } } /** @@ -244,15 +250,13 @@ public synchronized void flush() { flush(false); } - synchronized void flush(boolean deaccelerate) { - if (cacheMap != null) { - Iterator i = cacheMap.values().iterator(); + void flush(boolean deaccelerate) { + synchronized (weakCache) { + Iterator> i = weakCache.values().iterator(); while (i.hasNext()) { - Object o = i.next(); - if (o instanceof FlushableCacheData) { - if (((FlushableCacheData) o).flush(deaccelerate)) { - i.remove(); - } + SurfaceDataProxy sdp = i.next().get(); + if (sdp == null || sdp.flush(deaccelerate)) { + i.remove(); } } } diff --git a/src/java.desktop/share/classes/sun/font/HBShaper.java b/src/java.desktop/share/classes/sun/font/HBShaper.java index 70e95cdc27bbd..98c40035104e9 100644 --- a/src/java.desktop/share/classes/sun/font/HBShaper.java +++ b/src/java.desktop/share/classes/sun/font/HBShaper.java @@ -187,7 +187,6 @@ private static VarHandle getVarHandle(StructLayout struct, String name) { dispose_face_handle = tmp3; FunctionDescriptor shapeDesc = FunctionDescriptor.ofVoid( - //JAVA_INT, // return type JAVA_FLOAT, // ptSize ADDRESS, // matrix ADDRESS, // face @@ -470,7 +469,7 @@ static void shape( MemorySegment matrix = arena.allocateFrom(JAVA_FLOAT, mat); MemorySegment chars = arena.allocateFrom(JAVA_CHAR, text); - /*int ret =*/ jdk_hb_shape_handle.invokeExact( + jdk_hb_shape_handle.invokeExact( ptSize, matrix, hbface, chars, text.length, script, offset, limit, baseIndex, startX, startY, flags, slot, diff --git a/src/java.desktop/share/classes/sun/java2d/SurfaceData.java b/src/java.desktop/share/classes/sun/java2d/SurfaceData.java index 31091528c87c6..3e20631f682f0 100644 --- a/src/java.desktop/share/classes/sun/java2d/SurfaceData.java +++ b/src/java.desktop/share/classes/sun/java2d/SurfaceData.java @@ -113,7 +113,7 @@ public abstract class SurfaceData private static native void initIDs(); - private Object blitProxyKey; + private SurfaceManager.ProxyCache blitProxyCache; private StateTrackableDelegate stateDelegate; static { @@ -143,23 +143,21 @@ protected SurfaceData(State state) { } /** - * Subclasses can set a "blit proxy key" which will be used - * along with the SurfaceManager.getCacheData() mechanism to + * Subclasses can set a "blit proxy cache" which will be used + * along with the SurfaceManager to * store acceleration-compatible cached copies of source images. - * This key is a "tag" used to identify which cached copies - * are compatible with this destination SurfaceData. - * The getSourceSurfaceData() method uses this key to manage - * cached copies of a source image as described below. + * The getSourceSurfaceData() method uses this cache to manage + * copies of a source image as described below. *

          - * The Object used as this key should be as unique as it needs + * The cache used should be as unique as it needs * to be to ensure that multiple acceleratible destinations can - * each store their cached copies separately under different keys + * each store their cached copies separately into different caches * without interfering with each other or getting back the wrong * cached copy. *

          - * Many acceleratable SurfaceData objects can use their own - * GraphicsConfiguration as their proxy key as the GC object will - * typically be unique to a given screen and pixel format, but + * Many GraphicsConfiguration implementations have their own + * cache as the GC object is + * typically unique to a given screen and pixel format, but * other rendering destinations may have more or less stringent * sharing requirements. For instance, X11 pixmaps can be * shared on a given screen by any GraphicsConfiguration that @@ -168,14 +166,14 @@ protected SurfaceData(State state) { * a different cached proxy for each would be a waste. One can * imagine platforms where a single cached copy can be created * and shared across all screens and pixel formats - such - * implementations could use a single heavily shared key Object. + * implementations could use a single heavily shared cache object. */ - protected void setBlitProxyKey(Object key) { - // Caching is effectively disabled if we never have a proxy key + protected void setBlitProxyCache(SurfaceManager.ProxyCache cache) { + // Caching is effectively disabled if we never have a proxy cache // since the getSourceSurfaceData() method only does caching - // if the key is not null. + // if the cache is not null. if (SurfaceDataProxy.isCachingAllowed()) { - this.blitProxyKey = key; + this.blitProxyCache = cache; } } @@ -192,7 +190,7 @@ protected void setBlitProxyKey(Object key) { * appropriate SurfaceDataProxy instance. * The parameters describe the type of imaging operation being performed. *

          - * If a blitProxyKey was supplied by the subclass then it is + * If a blitProxyCache was supplied by the subclass then it is * used to potentially override the choice of source SurfaceData. * The outline of this process is: *

            @@ -201,8 +199,8 @@ protected void setBlitProxyKey(Object key) { *
          1. destSD gets the SurfaceManager of the source Image * and first retrieves the default SD from it using * getPrimarySurfaceData() - *
          2. destSD uses its "blit proxy key" (if set) to look for - * some cached data stored in the source SurfaceManager + *
          3. destSD uses its "blit proxy cache" (if set) to look for + * some cached data corresponding to the the source SurfaceManager *
          4. If the cached data is null then makeProxyFor() is used * to create some cached data which is stored back in the * source SurfaceManager under the same key for future uses. @@ -219,18 +217,15 @@ public SurfaceData getSourceSurfaceData(Image img, { SurfaceManager srcMgr = SurfaceManager.getManager(img); SurfaceData srcData = srcMgr.getPrimarySurfaceData(); - if (img.getAccelerationPriority() > 0.0f && - blitProxyKey != null) - { - SurfaceDataProxy sdp = - (SurfaceDataProxy) srcMgr.getCacheData(blitProxyKey); + if (img.getAccelerationPriority() > 0.0f && blitProxyCache != null) { + SurfaceDataProxy sdp = blitProxyCache.get(srcMgr); if (sdp == null || !sdp.isValid()) { if (srcData.getState() == State.UNTRACKABLE) { sdp = SurfaceDataProxy.UNCACHED; } else { sdp = makeProxyFor(srcData); } - srcMgr.setCacheData(blitProxyKey, sdp); + blitProxyCache.put(srcMgr, sdp); } srcData = sdp.replaceData(srcData, txtype, comp, bgColor); } diff --git a/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java b/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java index 0372f0b016a90..2f27515c20410 100644 --- a/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java +++ b/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java @@ -232,7 +232,7 @@ protected OGLSurfaceData(OGLGraphicsConfig gc, super(getCustomSurfaceType(type), cm); this.graphicsConfig = gc; this.type = type; - setBlitProxyKey(gc.getProxyKey()); + setBlitProxyCache(gc.getSurfaceDataProxyCache()); } @Override diff --git a/src/java.desktop/share/native/libawt/java2d/loops/IntRgb.c b/src/java.desktop/share/native/libawt/java2d/loops/IntRgb.c index 7155f70b472d3..aec11d17c890b 100644 --- a/src/java.desktop/share/native/libawt/java2d/loops/IntRgb.c +++ b/src/java.desktop/share/native/libawt/java2d/loops/IntRgb.c @@ -34,6 +34,8 @@ #include "ByteGray.h" #include "Index12Gray.h" +#include "ub.h" + /* * This file declares, registers, and defines the various graphics * primitive loops to manipulate surfaces of type "IntRgb". @@ -166,6 +168,7 @@ DEFINE_ALPHA_MASKBLIT(IntArgbPre, IntRgb, 4ByteArgb) DEFINE_ALPHA_MASKBLIT(IntRgb, IntRgb, 4ByteArgb) +ATTRIBUTE_NO_UBSAN DEFINE_SOLID_DRAWGLYPHLISTAA(IntRgb, 3ByteRgb) DEFINE_SOLID_DRAWGLYPHLISTLCD(IntRgb, 3ByteRgb) diff --git a/src/java.desktop/share/native/libfontmanager/HBShaper_Panama.c b/src/java.desktop/share/native/libfontmanager/HBShaper_Panama.c index 94289db7046c5..de067736c8c3b 100644 --- a/src/java.desktop/share/native/libfontmanager/HBShaper_Panama.c +++ b/src/java.desktop/share/native/libfontmanager/HBShaper_Panama.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,7 +63,7 @@ static float euclidianDistance(float a, float b) #define TYPO_LIGA 0x00000002 #define TYPO_RTL 0x80000000 -JDKEXPORT int jdk_hb_shape( +JDKEXPORT void jdk_hb_shape( float ptSize, float *matrix, void* pFace, @@ -92,13 +92,11 @@ JDKEXPORT int jdk_hb_shape( int featureCount = 0; char* kern = (flags & TYPO_KERN) ? "kern" : "-kern"; char* liga = (flags & TYPO_LIGA) ? "liga" : "-liga"; - int ret; unsigned int buflen; float devScale = 1.0f; if (getenv("HB_NODEVTX") != NULL) { float xPtSize = euclidianDistance(matrix[0], matrix[1]); - float yPtSize = euclidianDistance(matrix[2], matrix[3]); devScale = xPtSize / ptSize; } @@ -132,7 +130,7 @@ JDKEXPORT int jdk_hb_shape( glyphInfo = hb_buffer_get_glyph_infos(buffer, 0); glyphPos = hb_buffer_get_glyph_positions(buffer, &buflen); - ret = (*store_layout_results_fn) + (*store_layout_results_fn) (slot, baseIndex, offset, startX, startY, devScale, charCount, glyphCount, glyphInfo, glyphPos); @@ -141,5 +139,5 @@ JDKEXPORT int jdk_hb_shape( if (features != NULL) { free(features); } - return ret; + return; } diff --git a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c index f9ebacad66be8..37c6dba2a7836 100644 --- a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c +++ b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c @@ -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 @@ -513,8 +513,6 @@ Java_sun_font_FreetypeFontScaler_createScalerContextNative( double dmat[4], ptsz; FTScalerContext *context = (FTScalerContext*) calloc(1, sizeof(FTScalerContext)); - FTScalerInfo *scalerInfo = - (FTScalerInfo*) jlong_to_ptr(pScaler); if (context == NULL) { free(context); @@ -1652,7 +1650,6 @@ Java_sun_font_FreetypeFontScaler_getGlyphPointNative( jlong pScaler, jint glyphCode, jint pointNumber) { FT_Outline* outline; - jobject point = NULL; jfloat x=0, y=0; FTScalerContext *context = (FTScalerContext*) jlong_to_ptr(pScalerContext); diff --git a/src/java.desktop/share/native/libfontmanager/hb-jdk-p.h b/src/java.desktop/share/native/libfontmanager/hb-jdk-p.h index 58d39816b7591..c022e964e770f 100644 --- a/src/java.desktop/share/native/libfontmanager/hb-jdk-p.h +++ b/src/java.desktop/share/native/libfontmanager/hb-jdk-p.h @@ -56,13 +56,13 @@ hb_font_t* jdk_font_create_hbp( hb_font_funcs_t* font_funcs); -typedef int (*store_layoutdata_func_t) +typedef void (*store_layoutdata_func_t) (int slot, int baseIndex, int offset, float startX, float startY, float devScale, int charCount, int glyphCount, hb_glyph_info_t *glyphInfo, hb_glyph_position_t *glyphPos); -JDKEXPORT int jdk_hb_shape( +JDKEXPORT void jdk_hb_shape( float ptSize, float *matrix, diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java index 069e3b7559bea..1c0f8e27ffb74 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java @@ -771,6 +771,7 @@ protected Point getNewLocation(XConfigureEvent xe, int leftInset, int topInset) // TODO this should be the default for every case. switch (runningWM) { case XWM.CDE_WM: + case XWM.KDE2_WM: case XWM.MOTIF_WM: case XWM.METACITY_WM: case XWM.MUTTER_WM: diff --git a/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java b/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java index 10d30a2bc7dbc..c6b9d4ef7ad3c 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java +++ b/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java @@ -180,8 +180,8 @@ public synchronized SurfaceType getSurfaceType() { } @Override - public Object getProxyKey() { - return device.getProxyKeyFor(getSurfaceType()); + public SurfaceManager.ProxyCache getSurfaceDataProxyCache() { + return device.getProxyCacheFor(getSurfaceType()); } /** diff --git a/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java b/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java index 573d842e5f298..03f06408765c9 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java +++ b/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java @@ -36,10 +36,13 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Objects; +import sun.awt.image.SurfaceManager; import sun.awt.util.ThreadGroupUtils; import sun.java2d.SunGraphicsEnvironment; import sun.java2d.loops.SurfaceType; @@ -62,7 +65,7 @@ public final class X11GraphicsDevice extends GraphicsDevice * therefore methods, which is using this id should be ready to it. */ private volatile int screen; - HashMap x11ProxyKeyMap = new HashMap<>(); + Map x11ProxyCacheMap = Collections.synchronizedMap(new HashMap<>()); private static AWTPermission fullScreenExclusivePermission; private static Boolean xrandrExtSupported; @@ -86,15 +89,8 @@ public int getScreen() { return screen; } - public Object getProxyKeyFor(SurfaceType st) { - synchronized (x11ProxyKeyMap) { - Object o = x11ProxyKeyMap.get(st); - if (o == null) { - o = new Object(); - x11ProxyKeyMap.put(st, o); - } - return o; - } + public SurfaceManager.ProxyCache getProxyCacheFor(SurfaceType st) { + return x11ProxyCacheMap.computeIfAbsent(st, unused -> new SurfaceManager.ProxyCache()); } /** diff --git a/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java b/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java index 588dfbf882aef..ce7a8de5a8e54 100644 --- a/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java +++ b/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java @@ -72,6 +72,7 @@ public final class GLXGraphicsConfig private long pConfigInfo; private ContextCapabilities oglCaps; private final OGLContext context; + private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); private static native long getGLXConfigInfo(int screennum, int visualnum); private static native int getOGLCapabilities(long configInfo); @@ -89,8 +90,8 @@ private GLXGraphicsConfig(X11GraphicsDevice device, int visualnum, } @Override - public Object getProxyKey() { - return this; + public SurfaceManager.ProxyCache getSurfaceDataProxyCache() { + return surfaceDataProxyCache; } @Override diff --git a/src/java.desktop/unix/classes/sun/java2d/x11/X11SurfaceData.java b/src/java.desktop/unix/classes/sun/java2d/x11/X11SurfaceData.java index 2e70796d5bb99..0210dd929cbde 100644 --- a/src/java.desktop/unix/classes/sun/java2d/x11/X11SurfaceData.java +++ b/src/java.desktop/unix/classes/sun/java2d/x11/X11SurfaceData.java @@ -433,7 +433,7 @@ protected X11SurfaceData(X11ComponentPeer peer, this.depth = cm.getPixelSize(); initOps(peer, graphicsConfig, depth); if (isAccelerationEnabled()) { - setBlitProxyKey(gc.getProxyKey()); + setBlitProxyCache(gc.getSurfaceDataProxyCache()); } } diff --git a/src/java.desktop/unix/classes/sun/java2d/xr/XRGraphicsConfig.java b/src/java.desktop/unix/classes/sun/java2d/xr/XRGraphicsConfig.java index 7483128bec647..82ceeeb53506f 100644 --- a/src/java.desktop/unix/classes/sun/java2d/xr/XRGraphicsConfig.java +++ b/src/java.desktop/unix/classes/sun/java2d/xr/XRGraphicsConfig.java @@ -34,6 +34,8 @@ public class XRGraphicsConfig extends X11GraphicsConfig implements SurfaceManager.ProxiedGraphicsConfig { + private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); + private XRGraphicsConfig(X11GraphicsDevice device, int visualnum, int depth, int colormap, boolean doubleBuffer) { super(device, visualnum, depth, colormap, doubleBuffer); @@ -53,7 +55,8 @@ public static XRGraphicsConfig getConfig(X11GraphicsDevice device, doubleBuffer); } - public Object getProxyKey() { - return this; + @Override + public SurfaceManager.ProxyCache getSurfaceDataProxyCache() { + return surfaceDataProxyCache; } } diff --git a/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java b/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java index 077cc4e34d2a2..66adccea41e3d 100644 --- a/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java +++ b/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java @@ -291,8 +291,7 @@ protected XRSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc, this.solidloops = graphicsConfig.getSolidLoops(sType); this.depth = depth; initOps(peer, graphicsConfig, depth); - - setBlitProxyKey(gc.getProxyKey()); + setBlitProxyCache(gc.getSurfaceDataProxyCache()); } protected XRSurfaceData(XRBackend renderQueue) { diff --git a/src/java.desktop/unix/native/libfontmanager/X11FontScaler.c b/src/java.desktop/unix/native/libfontmanager/X11FontScaler.c index e705321e00698..6e836fa111c34 100644 --- a/src/java.desktop/unix/native/libfontmanager/X11FontScaler.c +++ b/src/java.desktop/unix/native/libfontmanager/X11FontScaler.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, 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 @@ -267,7 +267,6 @@ Java_sun_font_NativeFont_getGlyphAdvance xcs = AWTFontPerChar(xFont, glyphCode - context->minGlyph); advance = AWTCharAdvance(xcs); } else { - int direction, ascent, descent; AWTChar2b xChar; xChar.byte1 = (unsigned char) (glyphCode >> 8); diff --git a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java index d1e41c2c92498..f627978282d25 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java @@ -113,8 +113,8 @@ public int getVisual() { } @Override - public Object getProxyKey() { - return device; + public SurfaceManager.ProxyCache getSurfaceDataProxyCache() { + return device.surfaceDataProxyCache; } /** diff --git a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java index 5fc34c05e4d5a..13de92384e447 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java @@ -41,6 +41,7 @@ import java.awt.peer.WindowPeer; import java.util.ArrayList; +import sun.awt.image.SurfaceManager; import sun.awt.windows.WWindowPeer; import sun.java2d.SunGraphicsEnvironment; import sun.java2d.opengl.WGLGraphicsConfig; @@ -90,6 +91,8 @@ public class Win32GraphicsDevice extends GraphicsDevice implements private float scaleX; private float scaleY; + final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); + static { // 4455041 - Even when ddraw is disabled, ddraw.dll is loaded when diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java index b39b7e85b9813..df4d196c39226 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java @@ -256,7 +256,7 @@ protected D3DSurfaceData(WComponentPeer peer, D3DGraphicsConfig gc, } else { initSurface(); } - setBlitProxyKey(gc.getProxyKey()); + setBlitProxyCache(gc.getSurfaceDataProxyCache()); } @Override diff --git a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java index 485f3e27f51f2..b06db9ee01b0b 100644 --- a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java +++ b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java @@ -73,6 +73,7 @@ public final class WGLGraphicsConfig private ContextCapabilities oglCaps; private final OGLContext context; private Object disposerReferent = new Object(); + private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); public static native int getDefaultPixFmt(int screennum); private static native boolean initWGL(); @@ -99,8 +100,8 @@ protected WGLGraphicsConfig(Win32GraphicsDevice device, int visualnum, } @Override - public Object getProxyKey() { - return this; + public SurfaceManager.ProxyCache getSurfaceDataProxyCache() { + return surfaceDataProxyCache; } @Override diff --git a/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java b/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java index 629690fe1369b..68ac0fd3ac048 100644 --- a/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java +++ b/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java @@ -273,7 +273,7 @@ private GDIWindowSurfaceData(WComponentPeer peer, SurfaceType sType) { scaleX = gd.getDefaultScaleX(); scaleY = gd.getDefaultScaleY(); initOps(peer, depth, rMask, gMask, bMask, gd.getScreen()); - setBlitProxyKey(graphicsConfig.getProxyKey()); + setBlitProxyCache(graphicsConfig.getSurfaceDataProxyCache()); } @Override diff --git a/src/java.management/share/classes/javax/management/AttributeList.java b/src/java.management/share/classes/javax/management/AttributeList.java index 74c9b860f91b5..932c4974244f3 100644 --- a/src/java.management/share/classes/javax/management/AttributeList.java +++ b/src/java.management/share/classes/javax/management/AttributeList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -182,9 +182,9 @@ public void add(Attribute object) { * size())} a RuntimeOperationsException should be raised, wrapping the * java.lang.IndexOutOfBoundsException thrown. * - * @param object The Attribute object to be inserted. * @param index The position in the list where the new {@code Attribute} * object is to be inserted. + * @param object The Attribute object to be inserted. */ public void add(int index, Attribute object) { try { @@ -202,8 +202,8 @@ public void add(int index, Attribute object) { * out of range {@literal (index < 0 || index > size())} a RuntimeOperationsException * should be raised, wrapping the java.lang.IndexOutOfBoundsException thrown. * - * @param object The value to which the attribute element should be set. * @param index The position specified. + * @param object The value to which the attribute element should be set. */ public void set(int index, Attribute object) { try { @@ -238,9 +238,9 @@ public boolean addAll(AttributeList list) { * RuntimeOperationsException should be raised, wrapping the * java.lang.IndexOutOfBoundsException thrown. * - * @param list Elements to be inserted into the list. * @param index Position at which to insert the first element from the * AttributeList specified. + * @param list Elements to be inserted into the list. * * @return true if this list changed as a result of the call. * diff --git a/src/java.management/share/classes/javax/management/DefaultLoaderRepository.java b/src/java.management/share/classes/javax/management/DefaultLoaderRepository.java index 461ab1ec3c42d..6e84628702774 100644 --- a/src/java.management/share/classes/javax/management/DefaultLoaderRepository.java +++ b/src/java.management/share/classes/javax/management/DefaultLoaderRepository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, 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 @@ -80,8 +80,8 @@ public static Class loadClass(String className) * is not found the method will throw a ClassNotFoundException * exception. * - * @param className The name of the class to be loaded. * @param loader The class loader to be excluded. + * @param className The name of the class to be loaded. * * @return the loaded class. * diff --git a/src/java.management/share/classes/javax/management/MBeanConstructorInfo.java b/src/java.management/share/classes/javax/management/MBeanConstructorInfo.java index f327920d7d9c4..5803b306bab6f 100644 --- a/src/java.management/share/classes/javax/management/MBeanConstructorInfo.java +++ b/src/java.management/share/classes/javax/management/MBeanConstructorInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -75,10 +75,10 @@ public MBeanConstructorInfo(String description, Constructor constructor) { * Constructs an {@code MBeanConstructorInfo} object. * * @param name The name of the constructor. + * @param description A human readable description of the constructor. * @param signature {@code MBeanParameterInfo} objects * describing the parameters(arguments) of the constructor. This * may be null with the same effect as a zero-length array. - * @param description A human readable description of the constructor. */ public MBeanConstructorInfo(String name, String description, @@ -90,10 +90,10 @@ public MBeanConstructorInfo(String name, * Constructs an {@code MBeanConstructorInfo} object. * * @param name The name of the constructor. + * @param description A human readable description of the constructor. * @param signature {@code MBeanParameterInfo} objects * describing the parameters(arguments) of the constructor. This * may be null with the same effect as a zero-length array. - * @param description A human readable description of the constructor. * @param descriptor The descriptor for the constructor. This may be null * which is equivalent to an empty descriptor. * diff --git a/src/java.management/share/classes/javax/management/MBeanOperationInfo.java b/src/java.management/share/classes/javax/management/MBeanOperationInfo.java index 5069737edefc0..a0c6b76a79d55 100644 --- a/src/java.management/share/classes/javax/management/MBeanOperationInfo.java +++ b/src/java.management/share/classes/javax/management/MBeanOperationInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, 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 @@ -97,9 +97,9 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable { * fields contributed by any annotations on the {@code Method} * object that contain the {@link DescriptorKey} meta-annotation. * + * @param description A human readable description of the operation. * @param method The {@code java.lang.reflect.Method} object * describing the MBean operation. - * @param description A human readable description of the operation. */ public MBeanOperationInfo(String description, Method method) { this(method.getName(), diff --git a/src/java.management/share/classes/javax/management/MBeanServer.java b/src/java.management/share/classes/javax/management/MBeanServer.java index 8bf68ef35bf24..488c961551560 100644 --- a/src/java.management/share/classes/javax/management/MBeanServer.java +++ b/src/java.management/share/classes/javax/management/MBeanServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, 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 @@ -622,11 +622,11 @@ public Object instantiate(String className, Object params[], * newly created object is not registered in the MBean server.

            * * @param className The class name of the object to be instantiated. + * @param loaderName The object name of the class loader to be used. * @param params An array containing the parameters of the * constructor to be invoked. * @param signature An array containing the signature of the * constructor to be invoked. - * @param loaderName The object name of the class loader to be used. * * @return The newly instantiated object. * @@ -711,10 +711,10 @@ default public ObjectInputStream deserialize(String className, byte[] data) * * @param className The name of the class whose class loader should be * used for the de-serialization. - * @param data The byte array to be de-sererialized. * @param loaderName The name of the class loader to be used for * loading the specified class. If null, the MBean Server's class * loader will be used. + * @param data The byte array to be de-sererialized. * * @implSpec This method throws {@link UnsupportedOperationException} by default. * diff --git a/src/java.management/share/classes/javax/management/MBeanServerConnection.java b/src/java.management/share/classes/javax/management/MBeanServerConnection.java index 87764b81c9144..22b68f1912350 100644 --- a/src/java.management/share/classes/javax/management/MBeanServerConnection.java +++ b/src/java.management/share/classes/javax/management/MBeanServerConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -278,11 +278,11 @@ public ObjectInstance createMBean(String className, ObjectName name, * * @param className The class name of the MBean to be instantiated. * @param name The object name of the MBean. May be null. + * @param loaderName The object name of the class loader to be used. * @param params An array containing the parameters of the * constructor to be invoked. * @param signature An array containing the signature of the * constructor to be invoked. - * @param loaderName The object name of the class loader to be used. * * @return An ObjectInstance, containing the * ObjectName and the Java class name of the newly diff --git a/src/java.management/share/classes/javax/management/loading/ClassLoaderRepository.java b/src/java.management/share/classes/javax/management/loading/ClassLoaderRepository.java index 3512f51238cd8..ecd46e8a66dc4 100644 --- a/src/java.management/share/classes/javax/management/loading/ClassLoaderRepository.java +++ b/src/java.management/share/classes/javax/management/loading/ClassLoaderRepository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, 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 @@ -100,10 +100,10 @@ public Class loadClass(String className) * the same time. The {@link #loadClassBefore} method is * recommended to avoid the risk of deadlock.

            * - * @param className The name of the class to be loaded. * @param exclude The class loader to be excluded. May be null, * in which case this method is equivalent to {@link #loadClass * loadClass(className)}. + * @param className The name of the class to be loaded. * * @return the loaded class. * @@ -133,10 +133,10 @@ public Class loadClassWithout(ClassLoader exclude, * search as soon as stop is reached, a potential * deadlock with concurrent class loading is avoided.

            * - * @param className The name of the class to be loaded. * @param stop The class loader at which to stop. May be null, in * which case this method is equivalent to {@link #loadClass(String) * loadClass(className)}. + * @param className The name of the class to be loaded. * * @return the loaded class. * diff --git a/src/java.management/share/classes/javax/management/loading/DefaultLoaderRepository.java b/src/java.management/share/classes/javax/management/loading/DefaultLoaderRepository.java index 014ed0fccf6e8..6277c6d13174a 100644 --- a/src/java.management/share/classes/javax/management/loading/DefaultLoaderRepository.java +++ b/src/java.management/share/classes/javax/management/loading/DefaultLoaderRepository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,8 +88,8 @@ public static Class loadClass(String className) * is not found the method will throw a ClassNotFoundException * exception. * - * @param className The name of the class to be loaded. * @param loader The class loader to be excluded. + * @param className The name of the class to be loaded. * * @return the loaded class. * diff --git a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java index 1d22b41b1e8ee..4120bc2cd2d1d 100644 --- a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java +++ b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java @@ -136,9 +136,9 @@ public class ModelMBeanOperationInfo extends MBeanOperationInfo * on the {@code Method} object that contain the {@link * DescriptorKey} meta-annotation. * + * @param description A human readable description of the operation. * @param operationMethod The java.lang.reflect.Method object * describing the MBean operation. - * @param description A human readable description of the operation. */ public ModelMBeanOperationInfo(String description, @@ -160,10 +160,10 @@ public ModelMBeanOperationInfo(String description, * contributed by any annotations on the {@code Method} object * that contain the {@link DescriptorKey} meta-annotation. * - * @param operationMethod The java.lang.reflect.Method object - * describing the MBean operation. * @param description A human readable description of the * operation. + * @param operationMethod The java.lang.reflect.Method object + * describing the MBean operation. * @param descriptor An instance of Descriptor containing the * appropriate metadata for this instance of the * ModelMBeanOperationInfo. If it is null a default diff --git a/src/java.naming/share/classes/javax/naming/CompositeName.java b/src/java.naming/share/classes/javax/naming/CompositeName.java index d731c20facc67..021a2f5904483 100644 --- a/src/java.naming/share/classes/javax/naming/CompositeName.java +++ b/src/java.naming/share/classes/javax/naming/CompositeName.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 @@ -485,9 +485,9 @@ public Name addAll(Name suffix) * new component are shifted up (away from index 0) * to accommodate the new components. * - * @param n The non-null components to add. * @param posn The index in this name at which to add the new * components. Must be in the range [0,size()]. + * @param n The non-null components to add. * @return The updated CompositeName, not a new one. Cannot be null. * @throws InvalidNameException If n is not a composite name. * @throws ArrayIndexOutOfBoundsException @@ -525,9 +525,9 @@ public Name add(String comp) throws InvalidNameException { * component are shifted up by one (away from index 0) to accommodate * the new component. * - * @param comp The non-null component to add. * @param posn The index at which to add the new component. * Must be in the range [0,size()]. + * @param comp The non-null component to add. * @return The updated CompositeName, not a new one. Cannot be null. * @throws ArrayIndexOutOfBoundsException * If posn is outside the specified range. diff --git a/src/java.naming/share/classes/javax/naming/CompoundName.java b/src/java.naming/share/classes/javax/naming/CompoundName.java index ec570acbb3472..e66d9d1b4346d 100644 --- a/src/java.naming/share/classes/javax/naming/CompoundName.java +++ b/src/java.naming/share/classes/javax/naming/CompoundName.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 @@ -472,9 +472,9 @@ public Name addAll(Name suffix) throws InvalidNameException { * Implementation note: Currently the syntax properties of suffix * is not used or checked. They might be in the future. * - * @param n The non-null components to add. * @param posn The index in this name at which to add the new * components. Must be in the range [0,size()]. + * @param n The non-null components to add. * @return The updated CompoundName, not a new one. Cannot be null. * @throws ArrayIndexOutOfBoundsException * If posn is outside the specified range. @@ -512,9 +512,9 @@ public Name add(String comp) throws InvalidNameException{ * component are shifted up by one (away from index 0) * to accommodate the new component. * - * @param comp The non-null component to add. * @param posn The index at which to add the new component. * Must be in the range [0,size()]. + * @param comp The non-null component to add. * @throws ArrayIndexOutOfBoundsException * If posn is outside the specified range. * @return The updated CompoundName, not a new one. Cannot be null. diff --git a/src/java.naming/share/classes/javax/naming/Name.java b/src/java.naming/share/classes/javax/naming/Name.java index 163b950717644..24865fb64e460 100644 --- a/src/java.naming/share/classes/javax/naming/Name.java +++ b/src/java.naming/share/classes/javax/naming/Name.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, 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 @@ -215,11 +215,11 @@ public interface Name * component are shifted up (away from 0) to accommodate the new * components. * - * @param n - * the components to add * @param posn * the index in this name at which to add the new * components. Must be in the range [0,size()]. + * @param n + * the components to add * @return the updated name (not a new one) * * @throws ArrayIndexOutOfBoundsException @@ -248,11 +248,11 @@ public interface Name * are shifted up by one (away from index 0) to accommodate the new * component. * - * @param comp - * the component to add * @param posn * the index at which to add the new component. * Must be in the range [0,size()]. + * @param comp + * the component to add * @return the updated name (not a new one) * * @throws ArrayIndexOutOfBoundsException diff --git a/src/java.naming/share/classes/javax/naming/Reference.java b/src/java.naming/share/classes/javax/naming/Reference.java index 789ddb9519549..3d096f4b84fa6 100644 --- a/src/java.naming/share/classes/javax/naming/Reference.java +++ b/src/java.naming/share/classes/javax/naming/Reference.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 @@ -164,10 +164,10 @@ public Reference(String className, String factory, String factoryLocation) { * * @param className The non-null class name of the object to * which this reference refers. + * @param addr The non-null address of the object. * @param factory The possibly null class name of the object's factory. * @param factoryLocation The possibly null location from which * to load the factory (e.g. URL) - * @param addr The non-null address of the object. * @see javax.naming.spi.ObjectFactory * @see javax.naming.spi.NamingManager#getObjectInstance */ diff --git a/src/java.naming/share/classes/javax/naming/directory/SearchControls.java b/src/java.naming/share/classes/javax/naming/directory/SearchControls.java index 6d7cc4bb6cd53..8d1f04e06ff15 100644 --- a/src/java.naming/share/classes/javax/naming/directory/SearchControls.java +++ b/src/java.naming/share/classes/javax/naming/directory/SearchControls.java @@ -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 @@ -163,16 +163,16 @@ public SearchControls() { * Constructs a search constraints using arguments. * @param scope The search scope. One of: * OBJECT_SCOPE, ONELEVEL_SCOPE, SUBTREE_SCOPE. - * @param timelim The number of milliseconds to wait before returning. - * If 0, wait indefinitely. - * @param deref If true, dereference links during search. * @param countlim The maximum number of entries to return. If 0, return * all entries that satisfy filter. - * @param retobj If true, return the object bound to the name of the - * entry; if false, do not return object. + * @param timelim The number of milliseconds to wait before returning. + * If 0, wait indefinitely. * @param attrs The identifiers of the attributes to return along with * the entry. If null, return all attributes. If empty * return no attributes. + * @param retobj If true, return the object bound to the name of the + * entry; if false, do not return object. + * @param deref If true, dereference links during search. */ public SearchControls(int scope, long countlim, diff --git a/src/java.naming/share/classes/javax/naming/ldap/LdapName.java b/src/java.naming/share/classes/javax/naming/ldap/LdapName.java index 773f3b534b45d..bca85cbc11c32 100644 --- a/src/java.naming/share/classes/javax/naming/ldap/LdapName.java +++ b/src/java.naming/share/classes/javax/naming/ldap/LdapName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, 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 @@ -436,9 +436,9 @@ public Name addAll(List suffixRdns) { * index (if any) of the first new component are shifted up * (away from index 0) to accommodate the new components. * - * @param suffix The non-null components to add. * @param posn The index at which to add the new component. * Must be in the range [0,size()]. + * @param suffix The non-null components to add. * * @return The updated name (not a new instance). * @@ -471,9 +471,9 @@ public Name addAll(int posn, Name suffix) * index (if any) of the first new RDN are shifted up (away from index 0) to * accommodate the new RDNs. * - * @param suffixRdns The non-null suffix {@code Rdn}s to add. * @param posn The index at which to add the suffix RDNs. * Must be in the range [0,size()]. + * @param suffixRdns The non-null suffix {@code Rdn}s to add. * * @return The updated name (not a new instance). * @throws IndexOutOfBoundsException @@ -524,9 +524,9 @@ public Name add(Rdn comp) { * component are shifted up by one (away from index 0) to accommodate * the new component. * - * @param comp The non-null component to add. * @param posn The index at which to add the new component. * Must be in the range [0,size()]. + * @param comp The non-null component to add. * @return The updated LdapName, not a new instance. * Cannot be null. * @exception IndexOutOfBoundsException @@ -548,9 +548,9 @@ public Name add(int posn, String comp) throws InvalidNameException { * RDN are shifted up by one (away from index 0) to accommodate * the new RDN. * - * @param comp The non-null RDN to add. * @param posn The index at which to add the new RDN. * Must be in the range [0,size()]. + * @param comp The non-null RDN to add. * @return The updated LdapName, not a new instance. * Cannot be null. * @exception IndexOutOfBoundsException diff --git a/src/java.naming/share/classes/javax/naming/ldap/LdapReferralException.java b/src/java.naming/share/classes/javax/naming/ldap/LdapReferralException.java index 95a1ca7df0e2c..70009333f1089 100644 --- a/src/java.naming/share/classes/javax/naming/ldap/LdapReferralException.java +++ b/src/java.naming/share/classes/javax/naming/ldap/LdapReferralException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, 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 @@ -143,11 +143,11 @@ protected LdapReferralException() { * Service provider implementors should read the "Service Provider" section * in the {@code LdapContext} class description for implementation details. * - * @param reqCtls The possibly null request controls to use for the new context. - * If null or the empty array means use no request controls. * @param env The possibly null environment properties to use when * for the new context. If null, the context is initialized with no environment * properties. + * @param reqCtls The possibly null request controls to use for the new context. + * If null or the empty array means use no request controls. * @return The non-null context at which to continue the method. * @throws NamingException If a naming exception was encountered. * Call either {@code retryReferral()} or {@code skipReferral()} diff --git a/src/java.net.http/share/classes/java/net/http/HttpClient.java b/src/java.net.http/share/classes/java/net/http/HttpClient.java index 82090bb969836..fbe8010e80626 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpClient.java +++ b/src/java.net.http/share/classes/java/net/http/HttpClient.java @@ -410,6 +410,14 @@ public interface Builder { /** * Sets an authenticator to use for HTTP authentication. * + * @implNote + * In the JDK built-in implementation of the {@code HttpClient}, + * if a {@link HttpRequest} has an {@code Authorization} or {@code + * Proxy-Authorization} header set then its value is used and + * the {@link Authenticator} is not invoked for the corresponding + * authentication. In this case, any authentication errors are returned + * to the user and requests are not automatically retried. + * * @param authenticator the Authenticator * @return this builder */ diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java b/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java index 81acd83c423a7..278e2bf23b146 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java @@ -244,6 +244,14 @@ public HttpRequestImpl response(Response r) throws IOException { HttpHeaders hdrs = r.headers(); HttpRequestImpl req = r.request(); + if (req.getUserSetAuthFlag(SERVER) && status == UNAUTHORIZED) { + // return the response. We don't handle it. + return null; + } else if (req.getUserSetAuthFlag(PROXY) && status == PROXY_UNAUTHORIZED) { + // same + return null; + } + if (status != PROXY_UNAUTHORIZED) { if (exchange.proxyauth != null && !exchange.proxyauth.fromcache) { AuthInfo au = exchange.proxyauth; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java index eb30dc85e9c8e..1ff1e5f47330f 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java @@ -41,6 +41,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.net.http.HttpClient; import java.net.http.HttpHeaders; @@ -69,6 +70,8 @@ */ final class Exchange { + static final int MAX_NON_FINAL_RESPONSES = + Utils.getIntegerNetProperty("jdk.httpclient.maxNonFinalResponses", 8); final Logger debug = Utils.getDebugLogger(this::dbgString, Utils.DEBUG); final HttpRequestImpl request; @@ -93,6 +96,8 @@ final class Exchange { // exchange so that it can be aborted/timed out mid setup. final ConnectionAborter connectionAborter = new ConnectionAborter(); + final AtomicInteger nonFinalResponses = new AtomicInteger(); + Exchange(HttpRequestImpl request, MultiExchange multi) { this.request = request; this.upgrading = false; @@ -359,7 +364,7 @@ CompletableFuture checkCancelled(CompletableFuture cf, HttpConnection public void h2Upgrade() { upgrading = true; - request.setH2Upgrade(client.client2()); + request.setH2Upgrade(this); } synchronized IOException getCancelCause() { @@ -482,9 +487,9 @@ private CompletableFuture expectContinue(ExchangeImpl ex) { Log.logResponse(r1::toString); int rcode = r1.statusCode(); if (rcode == 100) { + nonFinalResponses.incrementAndGet(); Log.logTrace("Received 100-Continue: sending body"); - if (debug.on()) - debug.log("Received 100-Continue for %s", r1); + if (debug.on()) debug.log("Received 100-Continue for %s", r1); CompletableFuture cf = exchImpl.sendBodyAsync() .thenCompose(exIm -> exIm.getResponseAsync(parentExecutor)); @@ -492,9 +497,9 @@ private CompletableFuture expectContinue(ExchangeImpl ex) { cf = wrapForLog(cf); return cf; } else { - Log.logTrace("Expectation failed: Received {0}", rcode); - if (debug.on()) - debug.log("Expect-Continue failed (%d) for: %s", rcode, r1); + Log.logTrace("Expectation failed: Received {0}", + rcode); + if (debug.on()) debug.log("Expect-Continue failed (%d) for: %s", rcode, r1); if (upgrading && rcode == 101) { IOException failed = new IOException( "Unable to handle 101 while waiting for 100"); @@ -559,12 +564,20 @@ private CompletableFuture ignore1xxResponse(final Response rsp) { + rsp.statusCode()); } assert exchImpl != null : "Illegal state - current exchange isn't set"; - // ignore this Response and wait again for the subsequent response headers - final CompletableFuture cf = exchImpl.getResponseAsync(parentExecutor); - // we recompose the CF again into the ignore1xxResponse check/function because - // the 1xx response is allowed to be sent multiple times for a request, before - // a final response arrives - return cf.thenCompose(this::ignore1xxResponse); + int count = nonFinalResponses.incrementAndGet(); + if (MAX_NON_FINAL_RESPONSES > 0 && (count < 0 || count > MAX_NON_FINAL_RESPONSES)) { + return MinimalFuture.failedFuture( + new ProtocolException(String.format( + "Too many interim responses received: %s > %s", + count, MAX_NON_FINAL_RESPONSES))); + } else { + // ignore this Response and wait again for the subsequent response headers + final CompletableFuture cf = exchImpl.getResponseAsync(parentExecutor); + // we recompose the CF again into the ignore1xxResponse check/function because + // the 1xx response is allowed to be sent multiple times for a request, before + // a final response arrives + return cf.thenCompose(this::ignore1xxResponse); + } } else { // return the already completed future return MinimalFuture.completedFuture(rsp); @@ -829,6 +842,14 @@ HttpClient.Version version() { return multi.version(); } + boolean pushEnabled() { + return pushGroup != null; + } + + String h2cSettingsStrings() { + return client.client2().getSettingsString(pushEnabled()); + } + String dbgString() { return dbgTag; } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java index 669c173e3f825..8c796193015d3 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java @@ -25,6 +25,7 @@ package jdk.internal.net.http; +import java.io.IOException; import java.net.ProtocolException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; @@ -53,6 +54,12 @@ class Http1HeaderParser { private int responseCode; private HttpHeaders headers; private Map> privateMap = new HashMap<>(); + private long size; + + private static final int K = 1024; + private static final int MAX_HTTP_HEADER_SIZE = Utils.getIntegerNetProperty( + "jdk.http.maxHeaderSize", + Integer.MIN_VALUE, Integer.MAX_VALUE, 384 * K, true); enum State { INITIAL, STATUS_LINE, @@ -164,11 +171,16 @@ private char get(ByteBuffer input) { return (char)(input.get() & 0xFF); } - private void readResumeStatusLine(ByteBuffer input) { + private void readResumeStatusLine(ByteBuffer input) throws ProtocolException { + final long max = MAX_HTTP_HEADER_SIZE - size - 32 - sb.length(); + int count = 0; char c = 0; while (input.hasRemaining() && (c = get(input)) != CR) { if (c == LF) break; sb.append(c); + if (++count > max) { + checkMaxHeaderSize(sb.length()); + } } if (c == CR) { state = State.STATUS_LINE_FOUND_CR; @@ -185,6 +197,7 @@ private void readStatusLineFeed(ByteBuffer input) throws ProtocolException { } statusLine = sb.toString(); + size = size + 32 + statusLine.length(); sb = new StringBuilder(); if (!statusLine.startsWith("HTTP/1.")) { throw protocolException("Invalid status line: \"%s\"", statusLine); @@ -205,7 +218,23 @@ private void readStatusLineFeed(ByteBuffer input) throws ProtocolException { state = State.STATUS_LINE_END; } - private void maybeStartHeaders(ByteBuffer input) { + private void checkMaxHeaderSize(int sz) throws ProtocolException { + long s = size + sz + 32; + if (MAX_HTTP_HEADER_SIZE > 0 && s > MAX_HTTP_HEADER_SIZE) { + throw new ProtocolException(String.format("Header size too big: %s > %s", + s, MAX_HTTP_HEADER_SIZE)); + } + } + static private long newSize(long size, int name, int value) throws ProtocolException { + long newSize = size + name + value + 32; + if (MAX_HTTP_HEADER_SIZE > 0 && newSize > MAX_HTTP_HEADER_SIZE) { + throw new ProtocolException(String.format("Header size too big: %s > %s", + newSize, MAX_HTTP_HEADER_SIZE)); + } + return newSize; + } + + private void maybeStartHeaders(ByteBuffer input) throws ProtocolException { assert state == State.STATUS_LINE_END; assert sb.length() == 0; char c = get(input); @@ -215,6 +244,7 @@ private void maybeStartHeaders(ByteBuffer input) { state = State.STATUS_LINE_END_LF; } else { sb.append(c); + checkMaxHeaderSize(sb.length()); state = State.HEADER; } } @@ -232,9 +262,11 @@ private void maybeEndHeaders(ByteBuffer input) throws ProtocolException { } } - private void readResumeHeader(ByteBuffer input) { + private void readResumeHeader(ByteBuffer input) throws ProtocolException { assert state == State.HEADER; assert input.hasRemaining(); + final long max = MAX_HTTP_HEADER_SIZE - size - 32 - sb.length(); + int count = 0; while (input.hasRemaining()) { char c = get(input); if (c == CR) { @@ -248,6 +280,9 @@ private void readResumeHeader(ByteBuffer input) { if (c == HT) c = SP; sb.append(c); + if (++count > max) { + checkMaxHeaderSize(sb.length()); + } } } @@ -268,12 +303,12 @@ private void addHeaderFromString(String headerString) throws ProtocolException { if (!Utils.isValidValue(value)) { throw protocolException("Invalid header value \"%s: %s\"", name, value); } - + size = newSize(size, name.length(), value.length()); privateMap.computeIfAbsent(name.toLowerCase(Locale.US), k -> new ArrayList<>()).add(value); } - private void resumeOrLF(ByteBuffer input) { + private void resumeOrLF(ByteBuffer input) throws ProtocolException { assert state == State.HEADER_FOUND_CR || state == State.HEADER_FOUND_LF; char c = state == State.HEADER_FOUND_LF ? LF : get(input); if (c == LF) { @@ -283,10 +318,12 @@ private void resumeOrLF(ByteBuffer input) { state = State.HEADER_FOUND_CR_LF; } else if (c == SP || c == HT) { sb.append(SP); // parity with MessageHeaders + checkMaxHeaderSize(sb.length()); state = State.HEADER; } else { sb = new StringBuilder(); sb.append(c); + checkMaxHeaderSize(1); state = State.HEADER; } } @@ -312,6 +349,7 @@ private void resumeOrSecondCR(ByteBuffer input) throws ProtocolException { } else if (c == SP || c == HT) { assert sb.length() != 0; sb.append(SP); // continuation line + checkMaxHeaderSize(sb.length()); state = State.HEADER; } else { if (sb.length() > 0) { @@ -322,6 +360,7 @@ private void resumeOrSecondCR(ByteBuffer input) throws ProtocolException { addHeaderFromString(headerString); } sb.append(c); + checkMaxHeaderSize(sb.length()); state = State.HEADER; } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.java index 689690d89312d..1cfc658c8da61 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.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 @@ -45,6 +45,8 @@ import jdk.internal.net.http.common.Utils; import static java.lang.String.format; +import static java.net.Authenticator.RequestorType.PROXY; +import static java.net.Authenticator.RequestorType.SERVER; import static java.nio.charset.StandardCharsets.US_ASCII; /** @@ -91,7 +93,6 @@ private void logHeaders(String completeHeaders) { } } - public void collectHeaders0(StringBuilder sb) { BiPredicate filter = connection.headerFilter(request); @@ -104,7 +105,9 @@ public void collectHeaders0(StringBuilder sb) { // Filter overridable headers from userHeaders userHeaders = HttpHeaders.of(userHeaders.map(), - connection.contextRestricted(request, client)); + connection.contextRestricted(request)); + + Utils.setUserAuthFlags(request, userHeaders); final HttpHeaders uh = userHeaders; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java index 50338f94c1de5..92a48d901fff3 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,16 +36,18 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.locks.ReentrantLock; -import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.MinimalFuture; import jdk.internal.net.http.common.Utils; import jdk.internal.net.http.frame.SettingsFrame; + +import static jdk.internal.net.http.frame.SettingsFrame.INITIAL_CONNECTION_WINDOW_SIZE; import static jdk.internal.net.http.frame.SettingsFrame.INITIAL_WINDOW_SIZE; import static jdk.internal.net.http.frame.SettingsFrame.ENABLE_PUSH; import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE; import static jdk.internal.net.http.frame.SettingsFrame.MAX_CONCURRENT_STREAMS; import static jdk.internal.net.http.frame.SettingsFrame.MAX_FRAME_SIZE; +import static jdk.internal.net.http.frame.SettingsFrame.MAX_HEADER_LIST_SIZE; /** * Http2 specific aspects of HttpClientImpl @@ -98,16 +100,20 @@ class Http2ClientImpl { CompletableFuture getConnectionFor(HttpRequestImpl req, Exchange exchange) { String key = Http2Connection.keyFor(req); + boolean pushEnabled = exchange.pushEnabled(); connectionPoolLock.lock(); try { Http2Connection connection = connections.get(key); if (connection != null) { try { - if (!connection.tryReserveForPoolCheckout() || !connection.reserveStream(true)) { + if (!connection.tryReserveForPoolCheckout() + || !connection.reserveStream(true, pushEnabled)) { if (debug.on()) debug.log("removing connection from pool since it couldn't be" + - " reserved for use: %s", connection); + " reserved for use%s: %s", + pushEnabled ? " with server push enabled" : "", + connection); removeFromPool(connection); } else { // fast path if connection already exists @@ -137,7 +143,7 @@ CompletableFuture getConnectionFor(HttpRequestImpl req, try { if (conn != null) { try { - conn.reserveStream(true); + conn.reserveStream(true, exchange.pushEnabled()); } catch (IOException e) { throw new UncheckedIOException(e); // shouldn't happen } @@ -183,10 +189,21 @@ boolean offerConnection(Http2Connection c) { } Http2Connection c1 = connections.putIfAbsent(key, c); if (c1 != null) { - c.setFinalStream(); - if (debug.on()) - debug.log("existing entry in connection pool for %s", key); - return false; + if (c.serverPushEnabled() && !c1.serverPushEnabled()) { + c1.setFinalStream(); + connections.remove(key, c1); + connections.put(key, c); + if (debug.on()) { + debug.log("Replacing %s with %s in connection pool", c1, c); + } + if (c1.shouldClose()) c1.close(); + return true; + } else { + c.setFinalStream(); + if (debug.on()) + debug.log("existing entry in connection pool for %s", key); + return false; + } } if (debug.on()) debug.log("put in the connection pool: %s", c); @@ -250,8 +267,8 @@ HttpClientImpl client() { } /** Returns the client settings as a base64 (url) encoded string */ - String getSettingsString() { - SettingsFrame sf = getClientSettings(); + String getSettingsString(boolean defaultServerPush) { + SettingsFrame sf = getClientSettings(defaultServerPush); byte[] settings = sf.toByteArray(); // without the header Base64.Encoder encoder = Base64.getUrlEncoder() .withoutPadding(); @@ -261,14 +278,7 @@ String getSettingsString() { private static final int K = 1024; private static int getParameter(String property, int min, int max, int defaultValue) { - int value = Utils.getIntegerNetProperty(property, defaultValue); - // use default value if misconfigured - if (value < min || value > max) { - Log.logError("Property value for {0}={1} not in [{2}..{3}]: " + - "using default={4}", property, value, min, max, defaultValue); - value = defaultValue; - } - return value; + return Utils.getIntegerNetProperty(property, min, max, defaultValue, true); } // used for the connection window, to have a connection window size @@ -283,12 +293,27 @@ int getConnectionWindowSize(SettingsFrame clientSettings) { // and the connection window size. int defaultValue = Math.max(streamWindow, K*K*32); + // The min value is the max between the streamWindow and + // the initial connection window size + int minValue = Math.max(INITIAL_CONNECTION_WINDOW_SIZE, streamWindow); + return getParameter( "jdk.httpclient.connectionWindowSize", - streamWindow, Integer.MAX_VALUE, defaultValue); + minValue, Integer.MAX_VALUE, defaultValue); + } + + /** + * This method is used to test whether pushes are globally + * disabled on all connections. + * @return true if pushes are globally disabled on all connections + */ + boolean serverPushDisabled() { + return getParameter( + "jdk.httpclient.enablepush", + 0, 1, 1) == 0; } - SettingsFrame getClientSettings() { + SettingsFrame getClientSettings(boolean defaultServerPush) { SettingsFrame frame = new SettingsFrame(); // default defined for HTTP/2 is 4 K, we use 16 K. frame.setParameter(HEADER_TABLE_SIZE, getParameter( @@ -297,14 +322,15 @@ SettingsFrame getClientSettings() { // O: does not accept push streams. 1: accepts push streams. frame.setParameter(ENABLE_PUSH, getParameter( "jdk.httpclient.enablepush", - 0, 1, 1)); + 0, 1, defaultServerPush ? 1 : 0)); // HTTP/2 recommends to set the number of concurrent streams - // no lower than 100. We use 100. 0 means no stream would be - // accepted. That would render the client to be non functional, - // so we won't let 0 be configured for our Http2ClientImpl. + // no lower than 100. We use 100, unless push promises are + // disabled. + int initialServerStreams = frame.getParameter(ENABLE_PUSH) == 0 + ? 0 : 100; frame.setParameter(MAX_CONCURRENT_STREAMS, getParameter( "jdk.httpclient.maxstreams", - 1, Integer.MAX_VALUE, 100)); + 0, Integer.MAX_VALUE, initialServerStreams)); // Maximum size is 2^31-1. Don't allow window size to be less // than the minimum frame size as this is likely to be a // configuration error. HTTP/2 specify a default of 64 * K -1, @@ -317,6 +343,14 @@ SettingsFrame getClientSettings() { frame.setParameter(MAX_FRAME_SIZE, getParameter( "jdk.httpclient.maxframesize", 16 * K, 16 * K * K -1, 16 * K)); + // Maximum field section size we're prepared to accept + // This is the uncompressed name + value size + 32 per field line + int maxHeaderSize = getParameter( + "jdk.http.maxHeaderSize", + Integer.MIN_VALUE, Integer.MAX_VALUE, 384 * K); + // If the property is <= 0 the value is unlimited + if (maxHeaderSize <= 0) maxHeaderSize = -1; + frame.setParameter(MAX_HEADER_LIST_SIZE, maxHeaderSize); return frame; } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java index 9457ff6998832..2e6b42049840e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java @@ -31,6 +31,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.net.InetSocketAddress; +import java.net.ProtocolException; import java.net.http.HttpClient; import java.net.http.HttpHeaders; import java.nio.ByteBuffer; @@ -49,6 +50,7 @@ import java.util.concurrent.Flow; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; @@ -88,10 +90,13 @@ import jdk.internal.net.http.hpack.Encoder; import static java.nio.charset.StandardCharsets.UTF_8; import static jdk.internal.net.http.frame.SettingsFrame.DEFAULT_INITIAL_WINDOW_SIZE; +import static jdk.internal.net.http.frame.SettingsFrame.ENABLE_PUSH; import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE; +import static jdk.internal.net.http.frame.SettingsFrame.INITIAL_CONNECTION_WINDOW_SIZE; import static jdk.internal.net.http.frame.SettingsFrame.INITIAL_WINDOW_SIZE; import static jdk.internal.net.http.frame.SettingsFrame.MAX_CONCURRENT_STREAMS; import static jdk.internal.net.http.frame.SettingsFrame.MAX_FRAME_SIZE; +import static jdk.internal.net.http.frame.SettingsFrame.MAX_HEADER_LIST_SIZE; /** * An Http2Connection. Encapsulates the socket(channel) and any SSLEngine used @@ -327,6 +332,45 @@ void markPrefaceSent() { } } + private final class PushPromiseDecoder extends HeaderDecoder implements DecodingCallback { + + final int parentStreamId; + final int pushPromiseStreamId; + final Stream parent; + final AtomicReference errorRef = new AtomicReference<>(); + + PushPromiseDecoder(int parentStreamId, int pushPromiseStreamId, Stream parent) { + this.parentStreamId = parentStreamId; + this.pushPromiseStreamId = pushPromiseStreamId; + this.parent = parent; + } + + @Override + protected void addHeader(String name, String value) { + if (errorRef.get() == null) { + super.addHeader(name, value); + } + } + + @Override + public void onMaxHeaderListSizeReached(long size, int maxHeaderListSize) throws ProtocolException { + try { + DecodingCallback.super.onMaxHeaderListSizeReached(size, maxHeaderListSize); + } catch (ProtocolException pe) { + if (parent != null) { + if (errorRef.compareAndSet(null, pe)) { + // cancel the parent stream + resetStream(pushPromiseStreamId, ResetFrame.REFUSED_STREAM); + parent.onProtocolError(pe); + } + } else { + // interrupt decoding and closes the connection + throw pe; + } + } + } + } + private static final int HALF_CLOSED_LOCAL = 1; private static final int HALF_CLOSED_REMOTE = 2; @@ -355,7 +399,7 @@ void markPrefaceSent() { private final Decoder hpackIn; final SettingsFrame clientSettings; private volatile SettingsFrame serverSettings; - private record PushContinuationState(HeaderDecoder pushContDecoder, PushPromiseFrame pushContFrame) {} + private record PushContinuationState(PushPromiseDecoder pushContDecoder, PushPromiseFrame pushContFrame) {} private volatile PushContinuationState pushContinuationState; private final String key; // for HttpClientImpl.connections map private final FramesDecoder framesDecoder; @@ -370,12 +414,24 @@ private record PushContinuationState(HeaderDecoder pushContDecoder, PushPromiseF private final FramesController framesController = new FramesController(); private final Http2TubeSubscriber subscriber; final ConnectionWindowUpdateSender windowUpdater; - private volatile Throwable cause; + private final AtomicReference cause = new AtomicReference<>(); private volatile Supplier initial; private volatile Stream initialStream; + private ValidatingHeadersConsumer orphanedConsumer; + private final AtomicInteger orphanedHeaders = new AtomicInteger(); + static final int DEFAULT_FRAME_SIZE = 16 * 1024; + static final int MAX_LITERAL_WITH_INDEXING = + Utils.getIntegerNetProperty("jdk.httpclient.maxLiteralWithIndexing",512); + // The maximum number of HEADER frames, CONTINUATION frames, or PUSH_PROMISE frames + // referring to an already closed or non-existent stream that a client will accept to + // process. Receiving frames referring to non-existent or closed streams doesn't necessarily + // constitute an HTTP/2 protocol error, but receiving too many may indicate a problem + // with the connection. If this limit is reached, a {@link java.net.ProtocolException + // ProtocolException} will be raised and the connection will be closed. + static final int MAX_ORPHANED_HEADERS = 1024; // TODO: need list of control frames from other threads // that need to be sent @@ -383,19 +439,21 @@ private record PushContinuationState(HeaderDecoder pushContDecoder, PushPromiseF private Http2Connection(HttpConnection connection, Http2ClientImpl client2, int nextstreamid, - String key) { + String key, + boolean defaultServerPush) { this.connection = connection; this.client2 = client2; this.subscriber = new Http2TubeSubscriber(client2.client()); this.nextstreamid = nextstreamid; this.key = key; - this.clientSettings = this.client2.getClientSettings(); + this.clientSettings = this.client2.getClientSettings(defaultServerPush); this.framesDecoder = new FramesDecoder(this::processFrame, clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE)); // serverSettings will be updated by server this.serverSettings = SettingsFrame.defaultRFCSettings(); this.hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE)); - this.hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE)); + this.hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE), + clientSettings.getParameter(MAX_HEADER_LIST_SIZE), MAX_LITERAL_WITH_INDEXING); if (debugHpack.on()) { debugHpack.log("For the record:" + super.toString()); debugHpack.log("Decoder created: %s", hpackIn); @@ -414,14 +472,16 @@ private Http2Connection(HttpConnection connection, private Http2Connection(HttpConnection connection, Http2ClientImpl client2, Exchange exchange, - Supplier initial) + Supplier initial, + boolean defaultServerPush) throws IOException, InterruptedException { this(connection, client2, 3, // stream 1 is registered during the upgrade - keyFor(connection)); - reserveStream(true); + keyFor(connection), + defaultServerPush); + reserveStream(true, clientSettings.getFlag(ENABLE_PUSH)); Log.logTrace("Connection send window size {0} ", windowController.connectionWindowSize()); Stream initialStream = createStream(exchange); @@ -454,7 +514,8 @@ static CompletableFuture createAsync(HttpConnection connection, Exchange exchange, Supplier initial) { - return MinimalFuture.supply(() -> new Http2Connection(connection, client2, exchange, initial)); + return MinimalFuture.supply(() -> new Http2Connection(connection, client2, exchange, initial, + exchange.pushEnabled())); } // Requires TLS handshake. So, is really async @@ -478,7 +539,8 @@ static CompletableFuture createAsync(HttpRequestImpl request, .thenCompose(notused-> { CompletableFuture cf = new MinimalFuture<>(); try { - Http2Connection hc = new Http2Connection(request, h2client, connection); + Http2Connection hc = new Http2Connection(request, h2client, + connection, exchange.pushEnabled()); cf.complete(hc); } catch (IOException e) { cf.completeExceptionally(e); @@ -493,13 +555,15 @@ static CompletableFuture createAsync(HttpRequestImpl request, */ private Http2Connection(HttpRequestImpl request, Http2ClientImpl h2client, - HttpConnection connection) + HttpConnection connection, + boolean defaultServerPush) throws IOException { this(connection, h2client, 1, - keyFor(request)); + keyFor(request), + defaultServerPush); Log.logTrace("Connection send window size {0} ", windowController.connectionWindowSize()); @@ -522,24 +586,30 @@ final HttpClientImpl client() { // if false returned then a new Http2Connection is required // if true, the stream may be assigned to this connection // for server push, if false returned, then the stream should be cancelled - boolean reserveStream(boolean clientInitiated) throws IOException { + boolean reserveStream(boolean clientInitiated, boolean pushEnabled) throws IOException { stateLock.lock(); try { - return reserveStream0(clientInitiated); + return reserveStream0(clientInitiated, pushEnabled); } finally { stateLock.unlock(); } } - private boolean reserveStream0(boolean clientInitiated) throws IOException { + private boolean reserveStream0(boolean clientInitiated, boolean pushEnabled) throws IOException { if (finalStream()) { return false; } - if (clientInitiated && (lastReservedClientStreamid + 2) >= MAX_CLIENT_STREAM_ID) { + // If requesting to reserve a stream for an exchange for which push is enabled, + // we will reserve the stream in this connection only if this connection is also + // push enabled, unless pushes are globally disabled. + boolean pushCompatible = !clientInitiated || !pushEnabled + || this.serverPushEnabled() + || client2.serverPushDisabled(); + if (clientInitiated && (lastReservedClientStreamid >= MAX_CLIENT_STREAM_ID -2 || !pushCompatible)) { setFinalStream(); client2.removeFromPool(this); return false; - } else if (!clientInitiated && (lastReservedServerStreamid + 2) >= MAX_SERVER_STREAM_ID) { + } else if (!clientInitiated && (lastReservedServerStreamid >= MAX_SERVER_STREAM_ID - 2)) { setFinalStream(); client2.removeFromPool(this); return false; @@ -564,6 +634,15 @@ private boolean reserveStream0(boolean clientInitiated) throws IOException { return true; } + boolean shouldClose() { + stateLock.lock(); + try { + return finalStream() && streams.isEmpty(); + } finally { + stateLock.unlock(); + } + } + /** * Throws an IOException if h2 was not negotiated */ @@ -691,6 +770,10 @@ String key() { return this.key; } + public boolean serverPushEnabled() { + return clientSettings.getParameter(SettingsFrame.ENABLE_PUSH) == 1; + } + boolean offerConnection() { return client2.offerConnection(this); } @@ -795,7 +878,7 @@ final void asyncReceive(ByteBuffer buffer) { } Throwable getRecordedCause() { - return cause; + return cause.get(); } void shutdown(Throwable t) { @@ -804,11 +887,11 @@ void shutdown(Throwable t) { stateLock.lock(); try { if (!markShutdownRequested()) return; - Throwable initialCause = this.cause; - if (initialCause == null && t != null) this.cause = t; + cause.compareAndSet(null, t); } finally { stateLock.unlock(); } + if (Log.errors()) { if (t!= null && (!(t instanceof EOFException) || isActive())) { Log.logError(t); @@ -819,6 +902,7 @@ void shutdown(Throwable t) { } } client2.removeFromPool(this); + subscriber.stop(cause.get()); for (Stream s : streams.values()) { try { s.connectionClosing(t); @@ -872,17 +956,39 @@ void processFrame(Http2Frame frame) throws IOException { return; } + if (frame instanceof PushPromiseFrame && !serverPushEnabled()) { + String protocolError = "received a PUSH_PROMISE when SETTINGS_ENABLE_PUSH is 0"; + protocolError(ResetFrame.PROTOCOL_ERROR, protocolError); + return; + } + Stream stream = getStream(streamid); + var nextstreamid = this.nextstreamid; + if (stream == null && (streamid & 0x01) == 0x01 && streamid >= nextstreamid) { + String protocolError = String.format( + "received a frame for a non existing streamid(%s) >= nextstreamid(%s)", + streamid, nextstreamid); + protocolError(ResetFrame.PROTOCOL_ERROR, protocolError); + return; + } if (stream == null && pushContinuationState == null) { // Should never receive a frame with unknown stream id - if (frame instanceof HeaderFrame) { + if (frame instanceof HeaderFrame hf) { + String protocolError = checkMaxOrphanedHeadersExceeded(hf); + if (protocolError != null) { + protocolError(ResetFrame.PROTOCOL_ERROR, protocolError); + return; + } // always decode the headers as they may affect // connection-level HPACK decoding state - DecodingCallback decoder = new ValidatingHeadersConsumer()::onDecoded; + if (orphanedConsumer == null || frame.getClass() != ContinuationFrame.class) { + orphanedConsumer = new ValidatingHeadersConsumer(); + } + DecodingCallback decoder = orphanedConsumer::onDecoded; try { - decodeHeaders((HeaderFrame) frame, decoder); - } catch (UncheckedIOException e) { + decodeHeaders(hf, decoder); + } catch (IOException | UncheckedIOException e) { protocolError(ResetFrame.PROTOCOL_ERROR, e.getMessage()); return; } @@ -910,29 +1016,41 @@ void processFrame(Http2Frame frame) throws IOException { // While push frame is not null, the only acceptable frame on this // stream is a Continuation frame - if (pushContinuationState != null) { + PushContinuationState pcs = pushContinuationState; + if (pcs != null) { if (frame instanceof ContinuationFrame cf) { + if (stream == null) { + String protocolError = checkMaxOrphanedHeadersExceeded(cf); + if (protocolError != null) { + protocolError(ResetFrame.PROTOCOL_ERROR, protocolError); + return; + } + } try { - if (streamid == pushContinuationState.pushContFrame.streamid()) - handlePushContinuation(stream, cf); - else - protocolError(ErrorFrame.PROTOCOL_ERROR, "Received a Continuation Frame with an " + - "unexpected stream id"); - } catch (UncheckedIOException e) { + if (streamid == pcs.pushContFrame.streamid()) + handlePushContinuation(pcs, stream, cf); + else { + String protocolError = "Received a CONTINUATION with " + + "unexpected stream id: " + streamid + " != " + + pcs.pushContFrame.streamid(); + protocolError(ErrorFrame.PROTOCOL_ERROR, protocolError); + } + } catch (IOException | UncheckedIOException e) { debug.log("Error handling Push Promise with Continuation: " + e.getMessage(), e); protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage()); return; } } else { pushContinuationState = null; - protocolError(ErrorFrame.PROTOCOL_ERROR, "Expected a Continuation frame but received " + frame); + String protocolError = "Expected a CONTINUATION frame but received " + frame; + protocolError(ErrorFrame.PROTOCOL_ERROR, protocolError); return; } } else { if (frame instanceof PushPromiseFrame pp) { try { handlePushPromise(stream, pp); - } catch (UncheckedIOException e) { + } catch (IOException | UncheckedIOException e) { protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage()); return; } @@ -940,7 +1058,7 @@ void processFrame(Http2Frame frame) throws IOException { // decode headers try { decodeHeaders(hf, stream.rspHeadersConsumer()); - } catch (UncheckedIOException e) { + } catch (IOException | UncheckedIOException e) { debug.log("Error decoding headers: " + e.getMessage(), e); protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage()); return; @@ -953,6 +1071,44 @@ void processFrame(Http2Frame frame) throws IOException { } } + private String checkMaxOrphanedHeadersExceeded(HeaderFrame hf) { + if (MAX_ORPHANED_HEADERS > 0 ) { + int orphaned = orphanedHeaders.incrementAndGet(); + if (orphaned < 0 || orphaned > MAX_ORPHANED_HEADERS) { + return "Too many orphaned header frames received on connection"; + } + } + return null; + } + + // This method is called when a DataFrame that was added + // to a Stream::inputQ is later dropped from the queue + // without being consumed. + // + // Before adding a frame to the queue, the Stream calls + // connection.windowUpdater.canBufferUnprocessedBytes(), which + // increases the count of unprocessed bytes in the connection. + // After consuming the frame, it calls connection.windowUpdater::processed, + // which decrements the count of unprocessed bytes, and possibly + // sends a window update to the peer. + // + // This method is called when connection.windowUpdater::processed + // will not be called, which can happen when consuming the frame + // fails, or when an empty DataFrame terminates the stream, + // or when the stream is cancelled while data is still + // sitting in its inputQ. In the later case, it is called for + // each frame that is dropped from the queue. + final void releaseUnconsumed(DataFrame df) { + windowUpdater.released(df.payloadLength()); + dropDataFrame(df); + } + + // This method can be called directly when a DataFrame is dropped + // before/without having been added to any Stream::inputQ. + // In that case, the number of unprocessed bytes hasn't been incremented + // by the stream, and does not need to be decremented. + // Otherwise, if the frame is dropped after having been added to the + // inputQ, releaseUnconsumed above should be called. final void dropDataFrame(DataFrame df) { if (isMarked(closedState, SHUTDOWN_REQUESTED)) return; if (debug.on()) { @@ -977,38 +1133,65 @@ final void ensureWindowUpdated(DataFrame df) { private void handlePushPromise(Stream parent, PushPromiseFrame pp) throws IOException { + int promisedStreamid = pp.getPromisedStream(); + if ((promisedStreamid & 0x01) != 0x00) { + throw new ProtocolException("Received PUSH_PROMISE for stream " + promisedStreamid); + } + int streamId = pp.streamid(); + if ((streamId & 0x01) != 0x01) { + throw new ProtocolException("Received PUSH_PROMISE on stream " + streamId); + } // always decode the headers as they may affect connection-level HPACK // decoding state assert pushContinuationState == null; - HeaderDecoder decoder = new HeaderDecoder(); - decodeHeaders(pp, decoder::onDecoded); - int promisedStreamid = pp.getPromisedStream(); + PushPromiseDecoder decoder = new PushPromiseDecoder(streamId, promisedStreamid, parent); + decodeHeaders(pp, decoder); if (pp.endHeaders()) { - completePushPromise(promisedStreamid, parent, decoder.headers()); + if (decoder.errorRef.get() == null) { + completePushPromise(promisedStreamid, parent, decoder.headers()); + } } else { pushContinuationState = new PushContinuationState(decoder, pp); } } - private void handlePushContinuation(Stream parent, ContinuationFrame cf) + private void handlePushContinuation(PushContinuationState pcs, Stream parent, ContinuationFrame cf) throws IOException { - var pcs = pushContinuationState; - decodeHeaders(cf, pcs.pushContDecoder::onDecoded); + assert pcs.pushContFrame.streamid() == cf.streamid() : String.format( + "Received CONTINUATION on a different stream %s != %s", + cf.streamid(), pcs.pushContFrame.streamid()); + decodeHeaders(cf, pcs.pushContDecoder); // if all continuations are sent, set pushWithContinuation to null if (cf.endHeaders()) { - completePushPromise(pcs.pushContFrame.getPromisedStream(), parent, - pcs.pushContDecoder.headers()); + if (pcs.pushContDecoder.errorRef.get() == null) { + completePushPromise(pcs.pushContFrame.getPromisedStream(), parent, + pcs.pushContDecoder.headers()); + } pushContinuationState = null; } } private void completePushPromise(int promisedStreamid, Stream parent, HttpHeaders headers) throws IOException { + if (parent == null) { + resetStream(promisedStreamid, ResetFrame.REFUSED_STREAM); + return; + } HttpRequestImpl parentReq = parent.request; + if (promisedStreamid < nextPushStream) { + // From RFC 9113 section 5.1.1: + // The identifier of a newly established stream MUST be numerically + // greater than all streams that the initiating endpoint has + // opened or reserved. + protocolError(ResetFrame.PROTOCOL_ERROR, String.format( + "Unexpected stream identifier: %s < %s", promisedStreamid, nextPushStream)); + return; + } if (promisedStreamid != nextPushStream) { + // we don't support skipping stream ids; resetStream(promisedStreamid, ResetFrame.PROTOCOL_ERROR); return; - } else if (!reserveStream(false)) { + } else if (!reserveStream(false, true)) { resetStream(promisedStreamid, ResetFrame.REFUSED_STREAM); return; } else { @@ -1177,11 +1360,17 @@ private void protocolError(int errorCode) private void protocolError(int errorCode, String msg) throws IOException { + String protocolError = "protocol error" + (msg == null?"":(": " + msg)); + ProtocolException protocolException = + new ProtocolException(protocolError); if (markHalfClosedLocal()) { + framesDecoder.close(protocolError); + subscriber.stop(protocolException); + if (debug.on()) debug.log("Sending GOAWAY due to " + protocolException); GoAwayFrame frame = new GoAwayFrame(0, errorCode); sendFrame(frame); } - shutdown(new IOException("protocol error" + (msg == null?"":(": " + msg)))); + shutdown(protocolException); } private void handleSettings(SettingsFrame frame) @@ -1305,11 +1494,12 @@ private void sendConnectionPreface() throws IOException { // Note that the default initial window size, not to be confused // with the initial window size, is defined by RFC 7540 as // 64K -1. - final int len = windowUpdater.initialWindowSize - DEFAULT_INITIAL_WINDOW_SIZE; - if (len != 0) { + final int len = windowUpdater.initialWindowSize - INITIAL_CONNECTION_WINDOW_SIZE; + assert len >= 0; + if (len > 0) { if (Log.channel()) { Log.logChannel("Sending initial connection window update frame: {0} ({1} - {2})", - len, windowUpdater.initialWindowSize, DEFAULT_INITIAL_WINDOW_SIZE); + len, windowUpdater.initialWindowSize, INITIAL_CONNECTION_WINDOW_SIZE); } windowUpdater.sendWindowUpdate(len); } @@ -1356,7 +1546,7 @@ final Stream createStream(Exchange exchange) { Stream.PushedStream createPushStream(Stream parent, Exchange pushEx) { PushGroup pg = parent.exchange.getPushGroup(); - return new Stream.PushedStream<>(pg, this, pushEx); + return new Stream.PushedStream<>(parent, pg, this, pushEx); } /** @@ -1466,16 +1656,18 @@ private ByteBuffer getHeaderBuffer(int size) { private List encodeHeadersImpl(int bufferSize, HttpHeaders... headers) { ByteBuffer buffer = getHeaderBuffer(bufferSize); List buffers = new ArrayList<>(); - for(HttpHeaders header : headers) { + for (HttpHeaders header : headers) { for (Map.Entry> e : header.map().entrySet()) { String lKey = e.getKey().toLowerCase(Locale.US); List values = e.getValue(); for (String value : values) { hpackOut.header(lKey, value); while (!hpackOut.encode(buffer)) { - buffer.flip(); - buffers.add(buffer); - buffer = getHeaderBuffer(bufferSize); + if (!buffer.hasRemaining()) { + buffer.flip(); + buffers.add(buffer); + buffer = getHeaderBuffer(bufferSize); + } } } } @@ -1514,7 +1706,7 @@ private Stream registerNewStream(OutgoingHeaders> oh) { Throwable cause = null; synchronized (this) { if (isMarked(closedState, SHUTDOWN_REQUESTED)) { - cause = this.cause; + cause = this.cause.get(); if (cause == null) { cause = new IOException("Connection closed"); } @@ -1553,6 +1745,8 @@ void sendFrame(Http2Frame frame) { Stream stream = registerNewStream(oh); // provide protection from inserting unordered frames between Headers and Continuation if (stream != null) { + // we are creating a new stream: reset orphaned header count + orphanedHeaders.set(0); publisher.enqueue(encodeHeaders(oh, stream)); } } else { @@ -1621,7 +1815,7 @@ final class Http2TubeSubscriber implements TubeSubscriber { private volatile Flow.Subscription subscription; private volatile boolean completed; private volatile boolean dropped; - private volatile Throwable error; + private final AtomicReference errorRef = new AtomicReference<>(); private final ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); private final SequentialScheduler scheduler = @@ -1642,10 +1836,9 @@ final void processQueue() { asyncReceive(buffer); } } catch (Throwable t) { - Throwable x = error; - if (x == null) error = t; + errorRef.compareAndSet(null, t); } finally { - Throwable x = error; + Throwable x = errorRef.get(); if (x != null) { if (debug.on()) debug.log("Stopping scheduler", x); scheduler.stop(); @@ -1680,6 +1873,7 @@ public void onSubscribe(Flow.Subscription subscription) { @Override public void onNext(List item) { + if (completed) return; if (debug.on()) debug.log(() -> "onNext: got " + Utils.remaining(item) + " bytes in " + item.size() + " buffers"); queue.addAll(item); @@ -1688,19 +1882,21 @@ public void onNext(List item) { @Override public void onError(Throwable throwable) { + if (completed) return; if (debug.on()) debug.log(() -> "onError: " + throwable); - error = throwable; + errorRef.compareAndSet(null, throwable); completed = true; runOrSchedule(); } @Override public void onComplete() { + if (completed) return; String msg = isActive() ? "EOF reached while reading" : "Idle connection closed by HTTP/2 peer"; if (debug.on()) debug.log(msg); - error = new EOFException(msg); + errorRef.compareAndSet(null, new EOFException(msg)); completed = true; runOrSchedule(); } @@ -1712,6 +1908,18 @@ public void dropSubscription() { // then we might not need the 'dropped' boolean? dropped = true; } + + void stop(Throwable error) { + if (errorRef.compareAndSet(null, error)) { + completed = true; + scheduler.stop(); + queue.clear(); + if (subscription != null) { + subscription.cancel(); + } + queue.clear(); + } + } } boolean isActive() { @@ -1746,6 +1954,19 @@ public ConnectionWindowUpdateSender(Http2Connection connection, int getStreamId() { return 0; } + + @Override + protected boolean windowSizeExceeded(long received) { + if (connection.isOpen()) { + try { + connection.protocolError(ErrorFrame.FLOW_CONTROL_ERROR, + "connection window exceeded"); + } catch (IOException io) { + connection.shutdown(io); + } + } + return true; + } } /** diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index 3fe8efdd7af43..e1f4ec16dcd46 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -964,7 +964,9 @@ private void debugCompleted(String tag, long startNanos, HttpRequest req) { // SSLException throw new SSLException(msg, throwable); } else if (throwable instanceof ProtocolException) { - throw new ProtocolException(msg); + ProtocolException pe = new ProtocolException(msg); + pe.initCause(throwable); + throw pe; } else if (throwable instanceof IOException) { throw new IOException(msg, throwable); } else { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java index 8fbf27ddc4670..d9dd533c0f03c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java @@ -356,13 +356,13 @@ BiPredicate headerFilter(HttpRequestImpl request) { } } - BiPredicate contextRestricted(HttpRequestImpl request, HttpClient client) { + BiPredicate contextRestricted(HttpRequestImpl request) { if (!isTunnel() && request.isConnect()) { // establishing a proxy tunnel assert request.proxy() == null; - return Utils.PROXY_TUNNEL_RESTRICTED(client); + return Utils.PROXY_TUNNEL_RESTRICTED(); } else { - return Utils.CONTEXT_RESTRICTED(client); + return Utils.ACCEPT_ALL; } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java index 68a27041d6b25..839b6a6185d75 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package jdk.internal.net.http; import java.io.IOException; +import java.net.Authenticator; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.ProxySelector; @@ -47,6 +48,8 @@ import jdk.internal.net.http.common.Utils; import jdk.internal.net.http.websocket.WebSocketRequest; +import static java.net.Authenticator.RequestorType.PROXY; +import static java.net.Authenticator.RequestorType.SERVER; import static jdk.internal.net.http.common.Utils.ALLOWED_HEADERS; import static jdk.internal.net.http.common.Utils.ProxyHeaders; @@ -66,6 +69,8 @@ public class HttpRequestImpl extends HttpRequest implements WebSocketRequest { private volatile AccessControlContext acc; private final Duration timeout; // may be null private final Optional version; + private volatile boolean userSetAuthorization; + private volatile boolean userSetProxyAuthorization; private static String userAgent() { PrivilegedAction pa = () -> System.getProperty("java.version"); @@ -287,10 +292,10 @@ public HttpHeaders headers() { InetSocketAddress authority() { return authority; } - void setH2Upgrade(Http2ClientImpl h2client) { + void setH2Upgrade(Exchange exchange) { systemHeadersBuilder.setHeader("Connection", "Upgrade, HTTP2-Settings"); systemHeadersBuilder.setHeader("Upgrade", Alpns.H2C); - systemHeadersBuilder.setHeader("HTTP2-Settings", h2client.getSettingsString()); + systemHeadersBuilder.setHeader("HTTP2-Settings", exchange.h2cSettingsStrings()); } @Override @@ -333,6 +338,30 @@ boolean isWebSocket() { return isWebSocket; } + /** + * These flags are set if the user set an Authorization or Proxy-Authorization header + * overriding headers produced by an Authenticator that was also set + * + * The values are checked in the AuthenticationFilter which tells the library + * to return whatever response received to the user instead of causing request + * to be resent, in case of error. + */ + public void setUserSetAuthFlag(Authenticator.RequestorType type, boolean value) { + if (type == SERVER) { + userSetAuthorization = value; + } else { + userSetProxyAuthorization = value; + } + } + + public boolean getUserSetAuthFlag(Authenticator.RequestorType type) { + if (type == SERVER) { + return userSetAuthorization; + } else { + return userSetProxyAuthorization; + } + } + @Override public Optional bodyPublisher() { return requestPublisher == null ? Optional.empty() diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java b/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java index 66d89ae1fc5f9..22e03238d2140 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.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 @@ -37,6 +37,7 @@ import java.security.AccessControlContext; import java.security.AccessController; import java.util.List; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; @@ -137,16 +138,21 @@ public void applyPushPromise( if (!initiatingURI.getHost().equalsIgnoreCase(pushRequestURI.getHost())) return; + String initiatingScheme = initiatingURI.getScheme(); + String pushRequestScheme = pushRequestURI.getScheme(); + + if (!initiatingScheme.equalsIgnoreCase(pushRequestScheme)) return; + int initiatingPort = initiatingURI.getPort(); if (initiatingPort == -1 ) { - if ("https".equalsIgnoreCase(initiatingURI.getScheme())) + if ("https".equalsIgnoreCase(initiatingScheme)) initiatingPort = 443; else initiatingPort = 80; } int pushPort = pushRequestURI.getPort(); if (pushPort == -1 ) { - if ("https".equalsIgnoreCase(pushRequestURI.getScheme())) + if ("https".equalsIgnoreCase(pushRequestScheme)) pushPort = 443; else pushPort = 80; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 4563362292329..bbb63718dc693 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -30,6 +30,7 @@ import java.io.UncheckedIOException; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; +import java.net.ProtocolException; import java.net.URI; import java.net.http.HttpResponse.BodyHandler; import java.net.http.HttpResponse.ResponseInfo; @@ -43,6 +44,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Flow; import java.util.concurrent.Flow.Subscription; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -52,10 +54,13 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodySubscriber; + import jdk.internal.net.http.common.*; import jdk.internal.net.http.frame.*; import jdk.internal.net.http.hpack.DecodingCallback; +import static jdk.internal.net.http.Exchange.MAX_NON_FINAL_RESPONSES; + /** * Http/2 Stream handling. * @@ -140,6 +145,9 @@ class Stream extends ExchangeImpl { private volatile boolean closed; private volatile boolean endStreamSent; private volatile boolean finalResponseCodeReceived; + private volatile boolean trailerReceived; + private AtomicInteger nonFinalResponseCount = new AtomicInteger(); + // Indicates the first reason that was invoked when sending a ResetFrame // to the server. A streamState of 0 indicates that no reset was sent. // (see markStream(int code) @@ -152,14 +160,13 @@ class Stream extends ExchangeImpl { // send lock: prevent sending DataFrames after reset occurred. private final Lock sendLock = new ReentrantLock(); private final Lock stateLock = new ReentrantLock(); - /** * A reference to this Stream's connection Send Window controller. The * stream MUST acquire the appropriate amount of Send Window before * sending any data. Will be null for PushStreams, as they cannot send data. */ private final WindowController windowController; - private final WindowUpdateSender windowUpdater; + private final WindowUpdateSender streamWindowUpdater; // Only accessed in all method calls from incoming(), no need for volatile private boolean endStreamSeen; @@ -209,7 +216,8 @@ private void schedule() { int size = Utils.remaining(dsts, Integer.MAX_VALUE); if (size == 0 && finished) { inputQ.remove(); - connection.ensureWindowUpdated(df); // must update connection window + // consumed will not be called + connection.releaseUnconsumed(df); // must update connection window Log.logTrace("responseSubscriber.onComplete"); if (debug.on()) debug.log("incoming: onComplete"); connection.decrementStreamsCount(streamid); @@ -224,7 +232,11 @@ private void schedule() { try { subscriber.onNext(dsts); } catch (Throwable t) { - connection.dropDataFrame(df); // must update connection window + // Data frames that have been added to the inputQ + // must be released using releaseUnconsumed() to + // account for the amount of unprocessed bytes + // tracked by the connection.windowUpdater. + connection.releaseUnconsumed(df); throw t; } if (consumed(df)) { @@ -275,8 +287,12 @@ private void schedule() { private void drainInputQueue() { Http2Frame frame; while ((frame = inputQ.poll()) != null) { - if (frame instanceof DataFrame) { - connection.dropDataFrame((DataFrame)frame); + if (frame instanceof DataFrame df) { + // Data frames that have been added to the inputQ + // must be released using releaseUnconsumed() to + // account for the amount of unprocessed bytes + // tracked by the connection.windowUpdater. + connection.releaseUnconsumed(df); } } } @@ -302,12 +318,13 @@ private boolean consumed(DataFrame df) { boolean endStream = df.getFlag(DataFrame.END_STREAM); if (len == 0) return endStream; - connection.windowUpdater.update(len); - + connection.windowUpdater.processed(len); if (!endStream) { + streamWindowUpdater.processed(len); + } else { // Don't send window update on a stream which is // closed or half closed. - windowUpdater.update(len); + streamWindowUpdater.released(len); } // true: end of stream; false: more data coming @@ -377,8 +394,21 @@ public String toString() { } private void receiveDataFrame(DataFrame df) { - inputQ.add(df); - sched.runOrSchedule(); + try { + int len = df.payloadLength(); + if (len > 0) { + // we return from here if the connection is being closed. + if (!connection.windowUpdater.canBufferUnprocessedBytes(len)) return; + // we return from here if the stream is being closed. + if (closed || !streamWindowUpdater.canBufferUnprocessedBytes(len)) { + connection.releaseUnconsumed(df); + return; + } + } + inputQ.add(df); + } finally { + sched.runOrSchedule(); + } } /** Handles a RESET frame. RESET is always handled inline in the queue. */ @@ -462,7 +492,7 @@ CompletableFuture> sendBodyAsync() { this.responseHeadersBuilder = new HttpHeadersBuilder(); this.rspHeadersConsumer = new HeadersConsumer(); this.requestPseudoHeaders = createPseudoHeaders(request); - this.windowUpdater = new StreamWindowUpdateSender(connection); + this.streamWindowUpdater = new StreamWindowUpdateSender(connection); } private boolean checkRequestCancelled() { @@ -498,6 +528,8 @@ void incoming(Http2Frame frame) throws IOException { if (debug.on()) { debug.log("request cancelled or stream closed: dropping data frame"); } + // Data frames that have not been added to the inputQ + // can be released using dropDataFrame connection.dropDataFrame(df); } else { receiveDataFrame(df); @@ -520,16 +552,38 @@ void otherFrame(Http2Frame frame) throws IOException { // The Hpack decoder decodes into one of these consumers of name,value pairs DecodingCallback rspHeadersConsumer() { - return rspHeadersConsumer::onDecoded; + return rspHeadersConsumer; + } + + String checkInterimResponseCountExceeded() { + // this is also checked by Exchange - but tracking it here too provides + // a more informative message. + int count = nonFinalResponseCount.incrementAndGet(); + if (MAX_NON_FINAL_RESPONSES > 0 && (count < 0 || count > MAX_NON_FINAL_RESPONSES)) { + return String.format( + "Stream %s PROTOCOL_ERROR: too many interim responses received: %s > %s", + streamid, count, MAX_NON_FINAL_RESPONSES); + } + return null; } protected void handleResponse(HeaderFrame hf) throws IOException { HttpHeaders responseHeaders = responseHeadersBuilder.build(); if (!finalResponseCodeReceived) { - responseCode = (int) responseHeaders - .firstValueAsLong(":status") - .orElseThrow(() -> new IOException("no statuscode in response")); + try { + responseCode = (int) responseHeaders + .firstValueAsLong(":status") + .orElseThrow(() -> new ProtocolException(String.format( + "Stream %s PROTOCOL_ERROR: no status code in response", + streamid))); + } catch (ProtocolException cause) { + cancelImpl(cause, ResetFrame.PROTOCOL_ERROR); + rspHeadersConsumer.reset(); + return; + } + + String protocolErrorMsg = null; // If informational code, response is partially complete if (responseCode < 100 || responseCode > 199) { this.finalResponseCodeReceived = true; @@ -537,23 +591,31 @@ protected void handleResponse(HeaderFrame hf) throws IOException { // see RFC 9113 section 8.1: // A HEADERS frame with the END_STREAM flag set that carries an // informational status code is malformed - String msg = ("Stream %s PROTOCOL_ERROR: " + - "HEADERS frame with status %s has END_STREAM flag set") - .formatted(streamid, responseCode); + protocolErrorMsg = String.format( + "Stream %s PROTOCOL_ERROR: " + + "HEADERS frame with status %s has END_STREAM flag set", + streamid, responseCode); + } else { + protocolErrorMsg = checkInterimResponseCountExceeded(); + } + + if (protocolErrorMsg != null) { if (debug.on()) { - debug.log(msg); + debug.log(protocolErrorMsg); } - cancelImpl(new IOException(msg), ResetFrame.PROTOCOL_ERROR); + cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR); + rspHeadersConsumer.reset(); + return; } response = new Response( request, exchange, responseHeaders, connection(), responseCode, HttpClient.Version.HTTP_2); - /* TODO: review if needs to be removed - the value is not used, but in case `content-length` doesn't parse as - long, there will be NumberFormatException. If left as is, make sure - code up the stack handles NFE correctly. */ + /* TODO: review if needs to be removed + the value is not used, but in case `content-length` doesn't parse as + long, there will be NumberFormatException. If left as is, make sure + code up the stack handles NFE correctly. */ responseHeaders.firstValueAsLong("content-length"); if (Log.headers()) { @@ -572,6 +634,15 @@ request, exchange, responseHeaders, connection(), Log.dumpHeaders(sb, " ", responseHeaders); Log.logHeaders(sb.toString()); } + if (trailerReceived) { + String protocolErrorMsg = String.format( + "Stream %s PROTOCOL_ERROR: trailers already received", streamid); + if (debug.on()) { + debug.log(protocolErrorMsg); + } + cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR); + } + trailerReceived = true; rspHeadersConsumer.reset(); } @@ -778,7 +849,8 @@ private OutgoingHeaders> headerFrame(long contentLength) { HttpHeaders sysh = filterHeaders(h.build()); HttpHeaders userh = filterHeaders(request.getUserHeaders()); // Filter context restricted from userHeaders - userh = HttpHeaders.of(userh.map(), Utils.CONTEXT_RESTRICTED(client())); + userh = HttpHeaders.of(userh.map(), Utils.ACCEPT_ALL); + Utils.setUserAuthFlags(request, userh); // Don't override Cookie values that have been set by the CookieHandler. final HttpHeaders uh = userh; @@ -1182,7 +1254,7 @@ private DataFrame getEmptyEndStreamDataFrame() { /** * A List of responses relating to this stream. Normally there is only - * one response, but intermediate responses like 100 are allowed + * one response, but interim responses like 100 are allowed * and must be passed up to higher level before continuing. Deals with races * such as if responses are returned before the CFs get created by * getResponseAsync() @@ -1379,12 +1451,18 @@ void cancel(IOException cause) { @Override void onProtocolError(final IOException cause) { + onProtocolError(cause, ResetFrame.PROTOCOL_ERROR); + } + + void onProtocolError(final IOException cause, int code) { if (debug.on()) { - debug.log("cancelling exchange on stream %d due to protocol error: %s", streamid, cause.getMessage()); + debug.log("cancelling exchange on stream %d due to protocol error [%s]: %s", + streamid, ErrorFrame.stringForCode(code), + cause.getMessage()); } Log.logError("cancelling exchange on stream {0} due to protocol error: {1}\n", streamid, cause); // send a RESET frame and close the stream - cancelImpl(cause, ResetFrame.PROTOCOL_ERROR); + cancelImpl(cause, code); } void connectionClosing(Throwable cause) { @@ -1401,7 +1479,7 @@ void cancelImpl(Throwable e) { cancelImpl(e, ResetFrame.CANCEL); } - private void cancelImpl(final Throwable e, final int resetFrameErrCode) { + void cancelImpl(final Throwable e, final int resetFrameErrCode) { errorRef.compareAndSet(null, e); if (debug.on()) { if (streamid == 0) debug.log("cancelling stream: %s", (Object)e); @@ -1511,6 +1589,7 @@ void close() { } static class PushedStream extends Stream { + final Stream parent; final PushGroup pushGroup; // push streams need the response CF allocated up front as it is // given directly to user via the multi handler callback function. @@ -1520,16 +1599,17 @@ static class PushedStream extends Stream { volatile HttpResponse.BodyHandler pushHandler; private volatile boolean finalPushResponseCodeReceived; - PushedStream(PushGroup pushGroup, + PushedStream(Stream parent, + PushGroup pushGroup, Http2Connection connection, Exchange pushReq) { // ## no request body possible, null window controller super(connection, pushReq, null); + this.parent = parent; this.pushGroup = pushGroup; this.pushReq = pushReq.request(); this.pushCF = new MinimalFuture<>(); this.responseCF = new MinimalFuture<>(); - } CompletableFuture> responseCF() { @@ -1617,7 +1697,16 @@ protected void handleResponse(HeaderFrame hf) { .orElse(-1); if (responseCode == -1) { - completeResponseExceptionally(new IOException("No status code")); + cancelImpl(new ProtocolException("No status code"), ResetFrame.PROTOCOL_ERROR); + rspHeadersConsumer.reset(); + return; + } else if (responseCode >= 100 && responseCode < 200) { + String protocolErrorMsg = checkInterimResponseCountExceeded(); + if (protocolErrorMsg != null) { + cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR); + rspHeadersConsumer.reset(); + return; + } } this.finalPushResponseCodeReceived = true; @@ -1677,6 +1766,13 @@ String dbgString() { return dbgString = dbg; } } + + @Override + protected boolean windowSizeExceeded(long received) { + onProtocolError(new ProtocolException("stream %s flow control window exceeded" + .formatted(streamid)), ResetFrame.FLOW_CONTROL_ERROR); + return true; + } } /** @@ -1727,7 +1823,9 @@ void closeAsUnprocessed() { } } - private class HeadersConsumer extends ValidatingHeadersConsumer { + private class HeadersConsumer extends ValidatingHeadersConsumer implements DecodingCallback { + + boolean maxHeaderListSizeReached; @Override public void reset() { @@ -1740,6 +1838,9 @@ public void reset() { public void onDecoded(CharSequence name, CharSequence value) throws UncheckedIOException { + if (maxHeaderListSizeReached) { + return; + } try { String n = name.toString(); String v = value.toString(); @@ -1762,6 +1863,23 @@ public void onDecoded(CharSequence name, CharSequence value) protected String formatMessage(String message, String header) { return "malformed response: " + super.formatMessage(message, header); } + + @Override + public void onMaxHeaderListSizeReached(long size, int maxHeaderListSize) throws ProtocolException { + if (maxHeaderListSizeReached) return; + try { + DecodingCallback.super.onMaxHeaderListSizeReached(size, maxHeaderListSize); + } catch (ProtocolException cause) { + maxHeaderListSizeReached = true; + // If this is a push stream: cancel the parent. + if (Stream.this instanceof Stream.PushedStream ps) { + ps.parent.onProtocolError(cause); + } + // cancel the stream, continue processing + onProtocolError(cause); + reset(); + } + } } final class Http2StreamResponseSubscriber extends HttpBodySubscriberWrapper { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/WindowUpdateSender.java b/src/java.net.http/share/classes/jdk/internal/net/http/WindowUpdateSender.java index 0bccc24e498f6..0affadddf1518 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/WindowUpdateSender.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/WindowUpdateSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,16 +31,31 @@ import jdk.internal.net.http.frame.WindowUpdateFrame; import jdk.internal.net.http.common.Utils; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; +/** + * A class that tracks the amount of flow controlled + * data received on an HTTP/2 connection + */ abstract class WindowUpdateSender { final Logger debug = Utils.getDebugLogger(this::dbgString, Utils.DEBUG); + // The threshold at which window updates are sent in bytes final int limit; + // The flow control window in bytes + final int windowSize; final Http2Connection connection; - final AtomicInteger received = new AtomicInteger(); + // The amount of flow controlled data received and processed, in bytes, + // since the start of the window. + // The window is exhausted when received + unprocessed >= windowSize + final AtomicLong received = new AtomicLong(); + // The amount of flow controlled data received and unprocessed, in bytes, + // since the start of the window. + // The window is exhausted when received + unprocessed >= windowSize + final AtomicLong unprocessed = new AtomicLong(); final ReentrantLock sendLock = new ReentrantLock(); WindowUpdateSender(Http2Connection connection) { @@ -53,6 +68,7 @@ abstract class WindowUpdateSender { WindowUpdateSender(Http2Connection connection, int maxFrameSize, int initWindowSize) { this.connection = connection; + this.windowSize = initWindowSize; int v0 = Math.max(0, initWindowSize - maxFrameSize); int v1 = (initWindowSize + (maxFrameSize - 1)) / maxFrameSize; v1 = v1 * maxFrameSize / 2; @@ -66,16 +82,119 @@ abstract class WindowUpdateSender { maxFrameSize, initWindowSize, limit); } + // O for the connection window, > 0 for a stream window abstract int getStreamId(); + + /** + * {@return {@code true} if buffering the given amount of + * flow controlled data would not exceed the flow control + * window} + *

            + * This method is called before buffering and processing + * a DataFrame. The count of unprocessed bytes is incremented + * by the given amount, and checked against the number of + * available bytes in the flow control window. + *

            + * This method returns {@code true} if the bytes can be buffered + * without exceeding the flow control window, {@code false} + * if the flow control window is exceeded and corrective + * action (close/reset) has been taken. + *

            + * When this method returns true, either {@link #processed(int)} + * or {@link #released(int)} must eventually be called to release + * the bytes from the flow control window. + * + * @implSpec + * an HTTP/2 endpoint may disable its own flow control + * (see + * RFC 9113, section 5.2.1), in which case this + * method may return true even if the flow control window would + * be exceeded: that is, the flow control window is exceeded but + * the endpoint decided to take no corrective action. + * + * @param len a number of unprocessed bytes, which + * the caller wants to buffer. + */ + boolean canBufferUnprocessedBytes(int len) { + return !checkWindowSizeExceeded(unprocessed.addAndGet(len)); + } + + // adds the provided amount to the amount of already + // received and processed bytes and checks whether the + // flow control window is exceeded. If so, take + // corrective actions and return true. + private boolean checkWindowSizeExceeded(long len) { + // because windowSize is bound by Integer.MAX_VALUE + // we will never reach the point where received.get() + len + // could overflow + long rcv = received.get() + len; + return rcv > windowSize && windowSizeExceeded(rcv); + } + + /** + * Called after unprocessed buffered bytes have been + * processed, to release part of the flow control window + * + * @apiNote this method is called only when releasing bytes + * that where buffered after calling + * {@link #canBufferUnprocessedBytes(int)}. + * + * @param delta the amount of processed bytes to release + */ + void processed(int delta) { + long rest = unprocessed.addAndGet(-delta); + assert rest >= 0; + update(delta); + } + + /** + * Called when it is desired to release unprocessed bytes + * without processing them, or without triggering the + * sending of a window update. This method can be called + * instead of calling {@link #processed(int)}. + * When this method is called instead of calling {@link #processed(int)}, + * it should generally be followed by a call to {@link #update(int)}, + * unless the stream or connection is being closed. + * + * @apiNote this method should only be called to release bytes that + * have been buffered after calling {@link + * #canBufferUnprocessedBytes(int)}. + * + * @param delta the amount of bytes to release from the window + * + * @return the amount of remaining unprocessed bytes + */ + long released(int delta) { + long rest = unprocessed.addAndGet(-delta); + assert rest >= 0; + return rest; + } + + /** + * This method is called to update the flow control window, + * and possibly send a window update + * + * @apiNote this method can be called directly if a frame is + * dropped before calling {@link #canBufferUnprocessedBytes(int)}. + * Otherwise, either {@link #processed(int)} or {@link #released(int)} + * should be called, depending on whether sending a window update + * is desired or not. It is typically not desired to send an update + * if the stream or connection is being closed. + * + * @param delta the amount of bytes released from the window. + */ void update(int delta) { - int rcv = received.addAndGet(delta); + long rcv = received.addAndGet(delta); if (debug.on()) debug.log("update: %d, received: %d, limit: %d", delta, rcv, limit); + if (rcv > windowSize && windowSizeExceeded(rcv)) { + return; + } if (rcv > limit) { sendLock.lock(); try { - int tosend = received.get(); - if( tosend > limit) { + int tosend = (int)Math.min(received.get(), Integer.MAX_VALUE); + if (tosend > limit) { received.getAndAdd(-tosend); sendWindowUpdate(tosend); } @@ -87,6 +206,7 @@ void update(int delta) { void sendWindowUpdate(int delta) { if (debug.on()) debug.log("sending window update: %d", delta); + assert delta > 0 : "illegal window update delta: " + delta; connection.sendUnorderedFrame(new WindowUpdateFrame(getStreamId(), delta)); } @@ -104,4 +224,16 @@ String dbgString() { } } + /** + * Called when the flow control window size is exceeded + * This method may return false if flow control is disabled + * in this endpoint. + * + * @param received the amount of data received, which is greater + * than {@code windowSize} + * @return {@code true} if the error was reported to the peer + * and no further window update should be sent. + */ + protected abstract boolean windowSizeExceeded(long received); + } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java index 62d03844d2e82..d81f52e6630ef 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java @@ -39,7 +39,11 @@ public void onDecoded(CharSequence name, CharSequence value) { String n = name.toString(); String v = value.toString(); super.onDecoded(n, v); - headersBuilder.addHeader(n, v); + addHeader(n, v); + } + + protected void addHeader(String name, String value) { + headersBuilder.addHeader(name, value); } public HttpHeaders headers() { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java index b2eb570db0c1e..ef5af764e7609 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java @@ -82,6 +82,8 @@ import static java.lang.String.format; import static java.nio.charset.StandardCharsets.US_ASCII; import static java.util.stream.Collectors.joining; +import static java.net.Authenticator.RequestorType.PROXY; +import static java.net.Authenticator.RequestorType.SERVER; /** * Miscellaneous utilities @@ -210,24 +212,10 @@ private static Set getDisallowedHeaders() { return true; }; - // Headers that are not generally restricted, and can therefore be set by users, - // but can in some contexts be overridden by the implementation. - // Currently, only contains "Authorization" which will - // be overridden, when an Authenticator is set on the HttpClient. - // Needs to be BiPred to fit with general form of predicates - // used by caller. - - public static final BiPredicate CONTEXT_RESTRICTED(HttpClient client) { - return (k, v) -> client.authenticator().isEmpty() || - (!k.equalsIgnoreCase("Authorization") - && !k.equalsIgnoreCase("Proxy-Authorization")); - } - public record ProxyHeaders(HttpHeaders userHeaders, HttpHeaders systemHeaders) {} - private static final BiPredicate HOST_RESTRICTED = (k,v) -> !"host".equalsIgnoreCase(k); - public static final BiPredicate PROXY_TUNNEL_RESTRICTED(HttpClient client) { - return CONTEXT_RESTRICTED(client).and(HOST_RESTRICTED); + public static final BiPredicate PROXY_TUNNEL_RESTRICTED() { + return (k,v) -> !"host".equalsIgnoreCase(k); } private static final Predicate IS_HOST = "host"::equalsIgnoreCase; @@ -310,6 +298,19 @@ private static final boolean isAllowedForProxy(String name, public static final BiPredicate NO_PROXY_HEADERS_FILTER = (n,v) -> Utils.NO_PROXY_HEADER.test(n); + /** + * Check the user headers to see if the Authorization or ProxyAuthorization + * were set. We need to set special flags in the request if so. Otherwise + * we can't distinguish user set from Authenticator set headers + */ + public static void setUserAuthFlags(HttpRequestImpl request, HttpHeaders userHeaders) { + if (userHeaders.firstValue("Authorization").isPresent()) { + request.setUserSetAuthFlag(SERVER, true); + } + if (userHeaders.firstValue("Proxy-Authorization").isPresent()) { + request.setUserSetAuthFlag(PROXY, true); + } + } public static boolean proxyHasDisabledSchemes(boolean tunnel) { return tunnel ? ! PROXY_AUTH_TUNNEL_DISABLED_SCHEMES.isEmpty() @@ -616,6 +617,19 @@ public static int getIntegerProperty(String name, int defaultValue) { Integer.parseInt(System.getProperty(name, String.valueOf(defaultValue)))); } + public static int getIntegerNetProperty(String property, int min, int max, int defaultValue, boolean log) { + int value = Utils.getIntegerNetProperty(property, defaultValue); + // use default value if misconfigured + if (value < min || value > max) { + if (log && Log.errors()) { + Log.logError("Property value for {0}={1} not in [{2}..{3}]: " + + "using default={4}", property, value, min, max, defaultValue); + } + value = defaultValue; + } + return value; + } + public static SSLParameters copySSLParameters(SSLParameters p) { SSLParameters p1 = new SSLParameters(); p1.setAlgorithmConstraints(p.getAlgorithmConstraints()); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/frame/FramesDecoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/frame/FramesDecoder.java index 72c7750eb43c1..7ebfa09083022 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/frame/FramesDecoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/frame/FramesDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, 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 @@ -463,6 +463,16 @@ private Http2Frame parseSettingsFrame(int frameLength, int streamid, int flags) int val = getInt(); if (id > 0 && id <= SettingsFrame.MAX_PARAM) { // a known parameter. Ignore otherwise + if (id == SettingsFrame.INITIAL_WINDOW_SIZE && val < 0) { + return new MalformedFrame(ErrorFrame.FLOW_CONTROL_ERROR, + "SettingsFrame with INITIAL_WINDOW_SIZE > 2^31 -1: " + + (val & 0xffffffffL)); + } + if (id == SettingsFrame.MAX_FRAME_SIZE && (val < 16384 || val > 16777215)) { + return new MalformedFrame(ErrorFrame.PROTOCOL_ERROR, + "SettingsFrame with MAX_FRAME_SIZE out of range: " + + (val & 0xffffffffL)); + } sf.setParameter(id, val); // TODO parameters validation } } @@ -530,7 +540,12 @@ private Http2Frame parseWindowUpdateFrame(int frameLength, int streamid, int fla return new MalformedFrame(ErrorFrame.FRAME_SIZE_ERROR, "WindowUpdateFrame length is "+ frameLength+", expected 4"); } - return new WindowUpdateFrame(streamid, getInt() & 0x7fffffff); + int update = getInt(); + if (update < 0) { + return new MalformedFrame(ErrorFrame.FLOW_CONTROL_ERROR, + "WindowUpdateFrame with value > 2^31 -1 " + (update & 0xffffffffL)); + } + return new WindowUpdateFrame(streamid, update & 0x7fffffff); } private Http2Frame parseContinuationFrame(int frameLength, int streamid, int flags) { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/frame/SettingsFrame.java b/src/java.net.http/share/classes/jdk/internal/net/http/frame/SettingsFrame.java index 8a0119594176a..b3b8164598fcb 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/frame/SettingsFrame.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/frame/SettingsFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -166,6 +166,11 @@ public synchronized void update(SettingsFrame updated) { // The initial value is 2^14 (16,384) octets. public static final int DEFAULT_MAX_FRAME_SIZE = 16 * K; + // Initial connection window size. This cannot be updated using the + // SETTINGS frame. + public static final int INITIAL_CONNECTION_WINDOW_SIZE = DEFAULT_INITIAL_WINDOW_SIZE; + + public static SettingsFrame defaultRFCSettings() { SettingsFrame f = new SettingsFrame(); f.setParameter(ENABLE_PUSH, DEFAULT_ENABLE_PUSH); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java index 9d57a734ac304..881be12c67cee 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, 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 @@ -27,6 +27,7 @@ import jdk.internal.net.http.hpack.HPACK.Logger; import java.io.IOException; +import java.net.ProtocolException; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.atomic.AtomicLong; @@ -107,12 +108,16 @@ public final class Decoder { private final StringReader stringReader; private final StringBuilder name; private final StringBuilder value; + private final int maxHeaderListSize; + private final int maxIndexed; private int intValue; private boolean firstValueRead; private boolean firstValueIndex; private boolean nameHuffmanEncoded; private boolean valueHuffmanEncoded; private int capacity; + private long size; + private int indexed; /** * Constructs a {@code Decoder} with the specified initial capacity of the @@ -129,6 +134,31 @@ public final class Decoder { * if capacity is negative */ public Decoder(int capacity) { + this(capacity, 0, 0); + } + + /** + * Constructs a {@code Decoder} with the specified initial capacity of the + * header table, a max header list size, and a maximum number of literals + * with indexing per header section. + * + *

            The value of the capacity has to be agreed between decoder and encoder out-of-band, + * e.g. by a protocol that uses HPACK + * (see 4.2. Maximum Table Size). + * + * @param capacity + * a non-negative integer + * @param maxHeaderListSize + * a maximum value for the header list size. This is the uncompressed + * names size + uncompressed values size + 32 bytes per field line + * @param maxIndexed + * the maximum number of literal with indexing we're prepared to handle + * for a header field section + * + * @throws IllegalArgumentException + * if capacity is negative + */ + public Decoder(int capacity, int maxHeaderListSize, int maxIndexed) { id = DECODERS_IDS.incrementAndGet(); logger = HPACK.getLogger().subLogger("Decoder#" + id); if (logger.isLoggable(NORMAL)) { @@ -145,6 +175,8 @@ public Decoder(int capacity) { toString(), hashCode); }); } + this.maxHeaderListSize = maxHeaderListSize; + this.maxIndexed = maxIndexed; setMaxCapacity0(capacity); table = new SimpleHeaderTable(capacity, logger.subLogger("HeaderTable")); integerReader = new IntegerReader(); @@ -242,22 +274,25 @@ public void decode(ByteBuffer headerBlock, requireNonNull(consumer, "consumer"); if (logger.isLoggable(NORMAL)) { logger.log(NORMAL, () -> format("reading %s, end of header block? %s", - headerBlock, endOfHeaderBlock)); + headerBlock, endOfHeaderBlock)); } while (headerBlock.hasRemaining()) { proceed(headerBlock, consumer); } if (endOfHeaderBlock && state != State.READY) { logger.log(NORMAL, () -> format("unexpected end of %s representation", - state)); + state)); throw new IOException("Unexpected end of header block"); } + if (endOfHeaderBlock) { + size = indexed = 0; + } } private void proceed(ByteBuffer input, DecodingCallback action) throws IOException { switch (state) { - case READY -> resumeReady(input); + case READY -> resumeReady(input, action); case INDEXED -> resumeIndexed(input, action); case LITERAL -> resumeLiteral(input, action); case LITERAL_WITH_INDEXING -> resumeLiteralWithIndexing(input, action); @@ -268,7 +303,7 @@ private void proceed(ByteBuffer input, DecodingCallback action) } } - private void resumeReady(ByteBuffer input) { + private void resumeReady(ByteBuffer input, DecodingCallback action) throws IOException { int b = input.get(input.position()) & 0xff; // absolute read State s = states.get(b); if (logger.isLoggable(EXTRA)) { @@ -289,6 +324,9 @@ private void resumeReady(ByteBuffer input) { } break; case LITERAL_WITH_INDEXING: + if (maxIndexed > 0 && ++indexed > maxIndexed) { + action.onMaxLiteralWithIndexingReached(indexed, maxIndexed); + } state = State.LITERAL_WITH_INDEXING; firstValueIndex = (b & 0b0011_1111) != 0; if (firstValueIndex) { @@ -315,6 +353,12 @@ private void resumeReady(ByteBuffer input) { } } + private void checkMaxHeaderListSize(long sz, DecodingCallback consumer) throws ProtocolException { + if (maxHeaderListSize > 0 && sz > maxHeaderListSize) { + consumer.onMaxHeaderListSizeReached(sz, maxHeaderListSize); + } + } + // 0 1 2 3 4 5 6 7 // +---+---+---+---+---+---+---+---+ // | 1 | Index (7+) | @@ -332,6 +376,8 @@ private void resumeIndexed(ByteBuffer input, DecodingCallback action) } try { SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue); + size = size + 32 + f.name.length() + f.value.length(); + checkMaxHeaderListSize(size, action); action.onIndexed(intValue, f.name, f.value); } finally { state = State.READY; @@ -374,7 +420,7 @@ private SimpleHeaderTable.HeaderField getHeaderFieldAt(int index) // private void resumeLiteral(ByteBuffer input, DecodingCallback action) throws IOException { - if (!completeReading(input)) { + if (!completeReading(input, action)) { return; } try { @@ -385,6 +431,8 @@ private void resumeLiteral(ByteBuffer input, DecodingCallback action) intValue, value, valueHuffmanEncoded)); } SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue); + size = size + 32 + f.name.length() + value.length(); + checkMaxHeaderListSize(size, action); action.onLiteral(intValue, f.name, value, valueHuffmanEncoded); } else { if (logger.isLoggable(NORMAL)) { @@ -392,6 +440,8 @@ private void resumeLiteral(ByteBuffer input, DecodingCallback action) "literal without indexing ('%s', huffman=%b, '%s', huffman=%b)", name, nameHuffmanEncoded, value, valueHuffmanEncoded)); } + size = size + 32 + name.length() + value.length(); + checkMaxHeaderListSize(size, action); action.onLiteral(name, nameHuffmanEncoded, value, valueHuffmanEncoded); } } finally { @@ -425,7 +475,7 @@ private void resumeLiteral(ByteBuffer input, DecodingCallback action) private void resumeLiteralWithIndexing(ByteBuffer input, DecodingCallback action) throws IOException { - if (!completeReading(input)) { + if (!completeReading(input, action)) { return; } try { @@ -445,6 +495,8 @@ private void resumeLiteralWithIndexing(ByteBuffer input, } SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue); n = f.name; + size = size + 32 + n.length() + v.length(); + checkMaxHeaderListSize(size, action); action.onLiteralWithIndexing(intValue, n, v, valueHuffmanEncoded); } else { n = name.toString(); @@ -453,6 +505,8 @@ private void resumeLiteralWithIndexing(ByteBuffer input, "literal with incremental indexing ('%s', huffman=%b, '%s', huffman=%b)", n, nameHuffmanEncoded, value, valueHuffmanEncoded)); } + size = size + 32 + n.length() + v.length(); + checkMaxHeaderListSize(size, action); action.onLiteralWithIndexing(n, nameHuffmanEncoded, v, valueHuffmanEncoded); } table.put(n, v); @@ -486,7 +540,7 @@ private void resumeLiteralWithIndexing(ByteBuffer input, private void resumeLiteralNeverIndexed(ByteBuffer input, DecodingCallback action) throws IOException { - if (!completeReading(input)) { + if (!completeReading(input, action)) { return; } try { @@ -497,6 +551,8 @@ private void resumeLiteralNeverIndexed(ByteBuffer input, intValue, value, valueHuffmanEncoded)); } SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue); + size = size + 32 + f.name.length() + value.length(); + checkMaxHeaderListSize(size, action); action.onLiteralNeverIndexed(intValue, f.name, value, valueHuffmanEncoded); } else { if (logger.isLoggable(NORMAL)) { @@ -504,6 +560,8 @@ private void resumeLiteralNeverIndexed(ByteBuffer input, "literal never indexed ('%s', huffman=%b, '%s', huffman=%b)", name, nameHuffmanEncoded, value, valueHuffmanEncoded)); } + size = size + 32 + name.length() + value.length(); + checkMaxHeaderListSize(size, action); action.onLiteralNeverIndexed(name, nameHuffmanEncoded, value, valueHuffmanEncoded); } } finally { @@ -541,7 +599,7 @@ private void resumeSizeUpdate(ByteBuffer input, } } - private boolean completeReading(ByteBuffer input) throws IOException { + private boolean completeReading(ByteBuffer input, DecodingCallback action) throws IOException { if (!firstValueRead) { if (firstValueIndex) { if (!integerReader.read(input)) { @@ -551,6 +609,8 @@ private boolean completeReading(ByteBuffer input) throws IOException { integerReader.reset(); } else { if (!stringReader.read(input, name)) { + long sz = size + 32 + name.length(); + checkMaxHeaderListSize(sz, action); return false; } nameHuffmanEncoded = stringReader.isHuffmanEncoded(); @@ -560,6 +620,8 @@ private boolean completeReading(ByteBuffer input) throws IOException { return false; } else { if (!stringReader.read(input, value)) { + long sz = size + 32 + name.length() + value.length(); + checkMaxHeaderListSize(sz, action); return false; } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java index 5e9df860febeb..228f9bf02061e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java @@ -24,6 +24,7 @@ */ package jdk.internal.net.http.hpack; +import java.net.ProtocolException; import java.nio.ByteBuffer; /** @@ -292,4 +293,17 @@ default void onLiteralWithIndexing(CharSequence name, * new capacity of the header table */ default void onSizeUpdate(int capacity) { } + + default void onMaxHeaderListSizeReached(long size, int maxHeaderListSize) + throws ProtocolException { + throw new ProtocolException(String + .format("Size exceeds MAX_HEADERS_LIST_SIZE: %s > %s", + size, maxHeaderListSize)); + } + + default void onMaxLiteralWithIndexingReached(long indexed, int maxIndexed) + throws ProtocolException { + throw new ProtocolException(String.format("Too many literal with indexing: %s > %s", + indexed, maxIndexed)); + } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java index 4188937b1ad93..c603e917ca437 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, 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 @@ -258,9 +258,10 @@ public void header(CharSequence name, } } } + assert encoding : "encoding is false"; } - private boolean isHuffmanBetterFor(CharSequence value) { + protected final boolean isHuffmanBetterFor(CharSequence value) { // prefer Huffman encoding only if it is strictly smaller than Latin-1 return huffmanWriter.lengthOf(value) < value.length(); } @@ -340,6 +341,10 @@ protected int calculateCapacity(int maxCapacity) { return 0; } + protected final int tableIndexOf(CharSequence name, CharSequence value) { + return getHeaderTable().indexOf(name, value); + } + /** * Encodes the {@linkplain #header(CharSequence, CharSequence) set up} * header into the given buffer. @@ -380,6 +385,7 @@ public final boolean encode(ByteBuffer headerBlock) { writer.reset(); // FIXME: WHY? encoding = false; } + assert done || encoding : "done: " + done + ", encoding: " + encoding; return done; } @@ -542,4 +548,8 @@ protected final void checkEncoding() { // TODO: better name e.g. checkIfEncoding "Previous encoding operation hasn't finished yet"); } } + + protected final Logger logger() { + return logger; + } } diff --git a/src/java.net.http/share/classes/module-info.java b/src/java.net.http/share/classes/module-info.java index cf9d07bdf328f..c95d80657b881 100644 --- a/src/java.net.http/share/classes/module-info.java +++ b/src/java.net.http/share/classes/module-info.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 @@ -57,9 +57,11 @@ * means that the cache is unbounded. *

          5. *
          6. {@systemProperty jdk.httpclient.connectionWindowSize} (default: 2^26)
            - * The HTTP/2 client connection window size in bytes. The maximum size is 2^31-1. This value - * cannot be smaller than the stream window size, which can be configured through the - * {@code jdk.httpclient.windowsize} system property. + * The HTTP/2 client connection window size in bytes. Valid values are in the range + * [2^16-1, 2^31-1]. If an invalid value is provided, the default value is used. + * The implementation guarantees that the actual value will be no smaller than the stream + * window size, which can be configured through the {@code jdk.httpclient.windowsize} + * system property. *

          7. *
          8. {@systemProperty jdk.httpclient.disableRetryConnect} (default: false)
            * Whether automatic retry of connection failures is disabled. If false, then retries are @@ -115,6 +117,25 @@ * The HTTP/2 client maximum frame size in bytes. The server is not permitted to send a frame * larger than this. *

          9. + *
          10. {@systemProperty jdk.httpclient.maxLiteralWithIndexing} (default: 512)
            + * The maximum number of header field lines (header name and value pairs) that a + * client is willing to add to the HPack Decoder dynamic table during the decoding + * of an entire header field section. + * This is purely an implementation limit. + * If a peer sends a field section with encoding that + * exceeds this limit a {@link java.net.ProtocolException ProtocolException} will be raised. + * A value of zero or a negative value means no limit. + *

          11. + *
          12. {@systemProperty jdk.httpclient.maxNonFinalResponses} (default: 8)
            + * The maximum number of interim (non-final) responses that a client is prepared + * to accept on a request-response stream before the final response is received. + * Interim responses are responses with a status in the range [100, 199] inclusive. + * This is purely an implementation limit. + * If a peer sends a number of interim response that exceeds this limit before + * sending the final response, a {@link java.net.ProtocolException ProtocolException} + * will be raised. + * A value of zero or a negative value means no limit. + *

          13. *
          14. {@systemProperty jdk.httpclient.maxstreams} (default: 100)
            * The maximum number of HTTP/2 push streams that the client will permit servers to open * simultaneously. @@ -131,7 +152,8 @@ * or 16kB)
            The buffer size used by the web socket implementation for socket writes. *

          15. *
          16. {@systemProperty jdk.httpclient.windowsize} (default: 16777216 or 16 MB)
            - * The HTTP/2 client stream window size in bytes. + * The HTTP/2 client stream window size in bytes. Valid values are in the range [2^14, 2^31-1]. + * If an invalid value is provided, the default value is used. *

          17. *
          18. {@systemProperty jdk.httpclient.auth.retrylimit} (default: 3)
            * The number of attempts the Basic authentication filter will attempt to retry a failed @@ -155,6 +177,15 @@ * conf/net.properties)
            A comma separated list of HTTP authentication scheme names, that * are disallowed for use by the HTTP client implementation, for HTTP CONNECT tunneling. *

          19. + *
          20. {@systemProperty jdk.http.maxHeaderSize} (default: 393216 or 384kB) + *
            The maximum header field section size that the client is prepared to accept. + * This is computed as the sum of the size of the uncompressed header name, plus + * the size of the uncompressed header value, plus an overhead of 32 bytes for + * each field section line. If a peer sends a field section that exceeds this + * size a {@link java.net.ProtocolException ProtocolException} will be raised. + * This applies to all versions of the protocol. A value of zero or a negative + * value means no limit. + *

          21. * * @moduleGraph * @since 11 diff --git a/src/java.prefs/macosx/native/libprefs/MacOSXPreferencesFile.m b/src/java.prefs/macosx/native/libprefs/MacOSXPreferencesFile.m index eb2338ca94491..bc3d9aaf68242 100644 --- a/src/java.prefs/macosx/native/libprefs/MacOSXPreferencesFile.m +++ b/src/java.prefs/macosx/native/libprefs/MacOSXPreferencesFile.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, 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 @@ -83,7 +83,7 @@ static void throwOutOfMemoryError(JNIEnv *env, const char *msg) c = exceptionClass; } else { c = (*env)->FindClass(env, "java/lang/OutOfMemoryError"); - if ((*env)->ExceptionOccurred(env)) return; + if ((*env)->ExceptionCheck(env)) return; exceptionClass = (*env)->NewGlobalRef(env, c); } @@ -211,7 +211,7 @@ static jarray createJavaStringArray(JNIEnv *env, CFIndex count) c = stringClass; } else { c = (*env)->FindClass(env, "java/lang/String"); - if ((*env)->ExceptionOccurred(env)) return NULL; + if ((*env)->ExceptionCheck(env)) return NULL; stringClass = (*env)->NewGlobalRef(env, c); } @@ -892,7 +892,7 @@ static void createTreeForPath(CFStringRef path, CFStringRef name, result = NULL; } else { CFStringRef cfString = copyToCFString(env, value); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { // memory error in copyToCFString result = NULL; } else if (cfString == NULL) { @@ -940,10 +940,10 @@ static void BuildJavaArrayFn(const void *key, const void *value, void *context) CFStringRef cfString = NULL; JNIEnv *env = args->env; - if ((*env)->ExceptionOccurred(env)) return; // already failed + if ((*env)->ExceptionCheck(env)) return; // already failed cfString = copyToCFString(env, propkey); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { // memory error in copyToCFString } else if (!cfString) { // bogus value type in prefs file - no Java errors available @@ -960,9 +960,9 @@ static void BuildJavaArrayFn(const void *key, const void *value, void *context) } if (CFStringGetLength(cfString) <= 0) goto bad; // ignore empty javaString = toJavaString(env, cfString); - if ((*env)->ExceptionOccurred(env)) goto bad; + if ((*env)->ExceptionCheck(env)) goto bad; (*env)->SetObjectArrayElement(env, args->result,args->used,javaString); - if ((*env)->ExceptionOccurred(env)) goto bad; + if ((*env)->ExceptionCheck(env)) goto bad; args->used++; } @@ -1003,7 +1003,7 @@ static jarray getStringsForNode(JNIEnv *env, jobject klass, jobject jpath, args.used = 0; args.allowSlash = allowSlash; CFDictionaryApplyFunction(node, BuildJavaArrayFn, &args); - if (!(*env)->ExceptionOccurred(env)) { + if (!(*env)->ExceptionCheck(env)) { // array construction succeeded if (args.used < count) { // finished array is smaller than expected. diff --git a/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java b/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java index ed76ce57f9472..756eedade72a3 100644 --- a/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java +++ b/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -450,7 +450,7 @@ private void replayChanges() { changeLog.get(i).replay(); } - private static Timer syncTimer = new Timer(true); // Daemon Thread + private static final Timer syncTimer = new Timer(true); // Daemon Thread static { addShutdownHook(); @@ -540,7 +540,7 @@ public Void run() { } }); if (newNode) { - // These 2 things guarantee node will get wrtten at next flush/sync + // These 2 things guarantee node will get written at next flush/sync prefsCache = new TreeMap<>(); nodeCreate = new NodeCreate(); changeLog.add(nodeCreate); @@ -957,6 +957,8 @@ private boolean lockFile(boolean shared) throws SecurityException{ try { Thread.sleep(sleepTime); } catch(InterruptedException e) { + // Don't lose the interrupt. + Thread.currentThread().interrupt(); checkLockFile0ErrorCode(errorCode); return false; } @@ -1006,12 +1008,12 @@ private void checkLockFile0ErrorCode (int errorCode) * Initial time between lock attempts, in ms. The time is doubled * after each failing attempt (except the first). */ - private static int INIT_SLEEP_TIME = 50; + private static final int INIT_SLEEP_TIME = 50; /** * Maximum number of lock attempts. */ - private static int MAX_ATTEMPTS = 5; + private static final int MAX_ATTEMPTS = 5; /** * Release the appropriate file lock (user or system). diff --git a/src/java.scripting/share/classes/com/sun/tools/script/shell/Main.java b/src/java.scripting/share/classes/com/sun/tools/script/shell/Main.java index 55b0daa1a61e1..f1ac21bbfbbfb 100644 --- a/src/java.scripting/share/classes/com/sun/tools/script/shell/Main.java +++ b/src/java.scripting/share/classes/com/sun/tools/script/shell/Main.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 @@ -40,6 +40,10 @@ public class Main { * @param args command line argument array */ public static void main(String[] args) { + // print deprecation warning + getError().println(getMessage("deprecated.warning", + new Object[] { PROGRAM_NAME })); + // parse command line options String[] scriptArgs = processOptions(args); diff --git a/src/java.scripting/share/classes/com/sun/tools/script/shell/messages.properties b/src/java.scripting/share/classes/com/sun/tools/script/shell/messages.properties index 096842465b65e..a6c7762ed34f3 100644 --- a/src/java.scripting/share/classes/com/sun/tools/script/shell/messages.properties +++ b/src/java.scripting/share/classes/com/sun/tools/script/shell/messages.properties @@ -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 @@ -63,3 +63,6 @@ argument is script file and the rest of the arguments, if any, are passed\n\ as script arguments. If [arguments..] and -e or -f option is used, then all\n\ [arguments..] are passed as script arguments. If [arguments..], -e, -f are\n\ missing, then interactive mode is used. + +deprecated.warning=\ + Warning: {0} is deprecated and will be removed in a future release. \ No newline at end of file diff --git a/src/java.scripting/share/classes/javax/script/Invocable.java b/src/java.scripting/share/classes/javax/script/Invocable.java index 1fda248a521d4..87a9624fecd1d 100644 --- a/src/java.scripting/share/classes/javax/script/Invocable.java +++ b/src/java.scripting/share/classes/javax/script/Invocable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, 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 @@ -38,13 +38,13 @@ public interface Invocable { * Calls a method on a script object compiled during a previous script execution, * which is retained in the state of the ScriptEngine. * - * @param name The name of the procedure to be called. - * * @param thiz If the procedure is a member of a class * defined in the script and thiz is an instance of that class * returned by a previous execution or invocation, the named method is * called through that instance. * + * @param name The name of the procedure to be called. + * * @param args Arguments to pass to the procedure. The rules for converting * the arguments to scripting variables are implementation-specific. * diff --git a/src/java.scripting/share/classes/module-info.java b/src/java.scripting/share/classes/module-info.java index 4367a55a5a1e1..db7ac3db1b53a 100644 --- a/src/java.scripting/share/classes/module-info.java +++ b/src/java.scripting/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, 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 @@ -30,6 +30,8 @@ * command-line script shell, {@index jrunscript jrunscript tool}, * that supports executing JavaScript and other languages if its corresponding * script engine is installed. + *

            The {@code jrunscript} tool is deprecated and will be removed + * in a future release. * * @toolGuide jrunscript * diff --git a/src/java.scripting/share/man/jrunscript.1 b/src/java.scripting/share/man/jrunscript.1 index 59389c274d1ea..491c3cb3be329 100644 --- a/src/java.scripting/share/man/jrunscript.1 +++ b/src/java.scripting/share/man/jrunscript.1 @@ -1,4 +1,4 @@ -.\" 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 @@ -46,6 +46,7 @@ and batch modes \f[B]Note:\f[R] .PP This tool is \f[B]experimental\f[R] and unsupported. +It is deprecated and will be removed in a future release. .PP \f[V]jrunscript\f[R] [\f[I]options\f[R]] [\f[I]arguments\f[R]] .TP diff --git a/src/java.security.jgss/macosx/native/libosxkrb5/SCDynamicStoreConfig.m b/src/java.security.jgss/macosx/native/libosxkrb5/SCDynamicStoreConfig.m index 11645d152cdfa..43cab418e1700 100644 --- a/src/java.security.jgss/macosx/native/libosxkrb5/SCDynamicStoreConfig.m +++ b/src/java.security.jgss/macosx/native/libosxkrb5/SCDynamicStoreConfig.m @@ -51,7 +51,7 @@ void _SCDynamicStoreCallBack(SCDynamicStoreRef store, CFArrayRef changedKeys, vo jmethodID jm_Config_refresh = (*env)->GetStaticMethodID(env, jc_Config, "refresh", "()V"); CHECK_NULL(jm_Config_refresh); (*env)->CallStaticVoidMethod(env, jc_Config, jm_Config_refresh); - if ((*env)->ExceptionOccurred(env) != NULL) { + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); } if (createdFromAttach) { diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java index 5a6f74e130ca0..6140168ebbb9e 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.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 @@ -170,7 +170,7 @@ public String toString() { if (destroyed) { return "Destroyed EncryptionKey"; } - return "key " + key.toString(); + return "EncryptionKey: " + key.toString(); } /** diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java index c6f3f083a6630..c331833e9f05b 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.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 @@ -27,7 +27,6 @@ import javax.security.auth.Destroyable; import java.util.Arrays; -import java.util.Base64; import java.util.Objects; /** @@ -140,8 +139,7 @@ public String toString() { if (destroyed) { return "Destroyed KerberosCredMessage"; } else { - return "KRB_CRED from " + sender + " to " + recipient + ":\n" - + Base64.getUrlEncoder().encodeToString(message); + return "KRB_CRED from " + sender + " to " + recipient; } } diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java index 55c1be3c0d819..71aaddda9deff 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.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 @@ -273,9 +273,9 @@ public String toString() { if (destroyed) { return "Destroyed KerberosKey"; } - return "Kerberos Principal " + principal + - "Key Version " + versionNum + - "key " + key.toString(); + return "KerberosKey: principal " + principal + + ", version " + versionNum + + ", key " + key.toString(); } /** diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java index 46168cf83775c..b18f7d8eae1f1 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.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 @@ -30,7 +30,8 @@ import javax.crypto.SecretKey; import javax.security.auth.Destroyable; import javax.security.auth.DestroyFailedException; -import sun.security.util.HexDumpEncoder; + +import sun.security.jgss.krb5.Krb5Util; import sun.security.krb5.Asn1Exception; import sun.security.krb5.PrincipalName; import sun.security.krb5.EncryptionKey; @@ -225,15 +226,8 @@ private void readObject(ObjectInputStream ois) } public String toString() { - HexDumpEncoder hd = new HexDumpEncoder(); - return "EncryptionKey: keyType=" + keyType - + " keyBytes (hex dump)=" - + (keyBytes == null || keyBytes.length == 0 ? - " Empty Key" : - '\n' + hd.encodeBuffer(keyBytes) - + '\n'); - - + return "keyType=" + keyType + + ", " + Krb5Util.keyInfo(keyBytes); } public int hashCode() { diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java index fa596fc6a1e5c..92b694efb86ca 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java @@ -33,8 +33,10 @@ import sun.security.jgss.TokenTracker; import sun.security.krb5.*; import java.io.InputStream; -import java.io.OutputStream; +import java.io.InvalidObjectException; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.OutputStream; import java.security.*; import javax.security.auth.Subject; import javax.security.auth.kerberos.ServicePermission; @@ -899,15 +901,11 @@ public final int getWrapSizeLimit(int qop, boolean confReq, public final byte[] wrap(byte[] inBuf, int offset, int len, MessageProp msgProp) throws GSSException { - if (DEBUG != null) { - DEBUG.println("Krb5Context.wrap: data=[" - + getHexBytes(inBuf, offset, len) - + "]"); - } - if (state != STATE_DONE) - throw new GSSException(GSSException.NO_CONTEXT, -1, - "Wrap called in invalid state!"); + if (state != STATE_DONE) { + throw new GSSException(GSSException.NO_CONTEXT, -1, + "Wrap called in invalid state!"); + } byte[] encToken = null; try { @@ -1050,12 +1048,6 @@ public final byte[] unwrap(byte[] inBuf, int offset, int len, setSequencingAndReplayProps(token, msgProp); } - if (DEBUG != null) { - DEBUG.println("Krb5Context.unwrap: data=[" - + getHexBytes(data, 0, data.length) - + "]"); - } - return data; } @@ -1405,8 +1397,22 @@ public byte[] getEncoded() { @Override public String toString() { - return "Kerberos session key: etype: " + key.getEType() + "\n" + - new HexDumpEncoder().encodeBuffer(key.getBytes()); + return "Kerberos session key: etype=" + key.getEType() + + ", " + Krb5Util.keyInfo(key.getBytes()); + } + + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException + ("KerberosSessionKey not directly deserializable"); } } @@ -1477,5 +1483,4 @@ public void setAuthTime(String authTime) { public void setAuthzData(AuthorizationData authzData) { this.authzData = authzData; } - } diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java index 1b109cc881f15..4cc306282e687 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.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 @@ -33,7 +33,9 @@ import javax.security.auth.kerberos.KerberosPrincipal; import java.io.Serial; import java.net.InetAddress; +import java.io.InvalidObjectException; import java.io.IOException; +import java.io.ObjectInputStream; import java.util.Date; import java.security.AccessController; import java.security.PrivilegedExceptionAction; @@ -400,4 +402,17 @@ public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException { throw ge; } } + + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException("Krb5InitCredential not deserializable"); + } } diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java index 10dea6749e59e..e784b7b33cad6 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java @@ -187,4 +187,19 @@ public static EncryptionKey[] keysFromJavaxKeyTab( KeyTab ktab, PrincipalName cname) { return snapshotFromJavaxKeyTab(ktab).readServiceKeys(cname); } + + public static String keyInfo(byte[] data) { + if (data == null) { + return "null key"; + } else if (data.length == 0) { + return "empty key"; + } else { + for (byte b : data) { + if (b != 0) { + return data.length + "-byte key"; + } + } + return data.length + "-byte zero key"; + } + } } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java b/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java index f975ba15a673e..b5453fae916a0 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java @@ -31,6 +31,7 @@ package sun.security.krb5; +import sun.security.jgss.krb5.Krb5Util; import sun.security.util.*; import sun.security.krb5.internal.*; import sun.security.krb5.internal.crypto.*; @@ -498,12 +499,7 @@ public synchronized void writeKey(CCacheOutputStream cos) public String toString() { return "EncryptionKey: keyType=" + keyType - + " kvno=" + kvno - + " keyValue (hex dump)=" - + (keyValue == null || keyValue.length == 0 ? - " Empty Key" : '\n' - + Krb5.hexDumper.encodeBuffer(keyValue) - + '\n'); + + ", kvno=" + kvno + ", " + Krb5Util.keyInfo(keyValue); } /** diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java index b93ced00c65c1..db6192ce9ee2c 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java @@ -83,28 +83,36 @@ * * http://www.ietf.org/rfc/rfc4120.txt. */ -// The instance fields not statically typed as Serializable are ASN.1 -// encoded and written by the writeObject method. -@SuppressWarnings("serial") + public class KRBError implements java.io.Serializable { static final long serialVersionUID = 3643809337475284503L; - private int pvno; - private int msgType; - private KerberosTime cTime; //optional - private Integer cuSec; //optional - private KerberosTime sTime; - private Integer suSec; - private int errorCode; - private Realm crealm; //optional - private PrincipalName cname; //optional - private PrincipalName sname; - private String eText; //optional - private byte[] eData; //optional - private Checksum eCksum; //optional - - private PAData[] pa; // PA-DATA in eData + private transient int pvno; + private transient int msgType; + private transient KerberosTime cTime; //optional + private transient Integer cuSec; //optional + private transient KerberosTime sTime; + private transient Integer suSec; + private transient int errorCode; + private transient Realm crealm; //optional + private transient PrincipalName cname; //optional + private transient PrincipalName sname; + private transient String eText; //optional + private transient byte[] eData; //optional + private transient Checksum eCksum; //optional + + private transient PAData[] pa; // PA-DATA in eData + + + /** + * Restores the state of this object from the stream. + * + * @param is the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { try { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java index c3cac113c4029..0850abb53c83a 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java @@ -320,9 +320,6 @@ public static String getErrorMessage(int i) { public static final Debug DEBUG = Debug.of("krb5", GetPropertyAction .privilegedGetProperty("sun.security.krb5.debug")); - public static final sun.security.util.HexDumpEncoder hexDumper = - new sun.security.util.HexDumpEncoder(); - static { errMsgList = new Hashtable (); errMsgList.put(KDC_ERR_NONE, "No error"); diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java index 9d24de5c2e61c..6b9f5de0c3d8e 100644 --- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java +++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java @@ -195,10 +195,6 @@ private void acquire() System.out.print("Password for " + princName + ":"); System.out.flush(); psswd = Password.readPassword(System.in); - if (DEBUG != null) { - DEBUG.println(">>> Kinit console input " + - new String(psswd)); - } } builder = new KrbAsReqBuilder(principal, psswd); } else { diff --git a/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c b/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c index 221aaccbf2bab..fe71f334617e1 100644 --- a/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c +++ b/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c @@ -877,13 +877,13 @@ jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize) (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize, (jbyte *)encodedTicket); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { (*env)->DeleteLocalRef(env, ary); return (jobject) NULL; } ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, ary); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { (*env)->DeleteLocalRef(env, ary); return (jobject) NULL; } @@ -993,7 +993,7 @@ jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) { } (*env)->SetByteArrayRegion(env, ary, (jsize) 0, cryptoKey->Length, (jbyte *)cryptoKey->Value); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { (*env)->DeleteLocalRef(env, ary); } else { encryptionKey = (*env)->NewObject(env, encryptionKeyClass, @@ -1018,7 +1018,7 @@ jobject BuildTicketFlags(JNIEnv *env, PULONG flags) { } (*env)->SetByteArrayRegion(env, ary, (jsize) 0, sizeof(*flags), (jbyte *)&nlflags); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { (*env)->DeleteLocalRef(env, ary); } else { ticketFlags = (*env)->NewObject(env, ticketFlagsClass, diff --git a/src/java.smartcardio/unix/legal/pcsclite.md b/src/java.smartcardio/unix/legal/pcsclite.md index 99a9936a4771d..66cdf62ee159e 100644 --- a/src/java.smartcardio/unix/legal/pcsclite.md +++ b/src/java.smartcardio/unix/legal/pcsclite.md @@ -1,4 +1,4 @@ -## PC/SC Lite v1.9.9 +## PC/SC Lite v2.3.0 ### PC/SC Lite Notice ``` @@ -9,19 +9,19 @@ Only 3 header files are included in this distribution: winscard.h, wintypes.h, p Copyright for winscard.h: * Copyright (C) 1999-2003 * David Corcoran - * Copyright (C) 2002-2009 + * Copyright (C) 2002-2018 * Ludovic Rousseau Copyright for wintypes.h: * Copyright (C) 1999 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2018 * Ludovic Rousseau Copyright for pcsclite.h: * Copyright (C) 1999-2004 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Copyright (C) 2005 * Martin Paljak diff --git a/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/pcsclite.h b/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/pcsclite.h index e722b13a73062..f589868a7ba32 100644 --- a/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/pcsclite.h +++ b/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/pcsclite.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2004 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Copyright (C) 2005 * Martin Paljak @@ -192,7 +192,8 @@ extern const SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci; /** @ingroup ErrorCodes */ #define SCARD_E_INVALID_CHV ((LONG)0x8010002A) /**< The supplied PIN is incorrect. */ /** @ingroup ErrorCodes */ -#define SCARD_E_UNKNOWN_RES_MNG ((LONG)0x8010002B) /**< An unrecognized error code was returned from a layered component. */ +#define SCARD_E_UNKNOWN_RES_MSG ((LONG)0x8010002B) /**< An unrecognized error code was returned from a layered component. */ +#define SCARD_E_UNKNOWN_RES_MNG SCARD_E_UNKNOWN_RES_MSG /** @ingroup ErrorCodes */ #define SCARD_E_NO_SUCH_CERTIFICATE ((LONG)0x8010002C) /**< The requested certificate does not exist. */ /** @ingroup ErrorCodes */ @@ -279,7 +280,7 @@ extern const SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci; #define INFINITE 0xFFFFFFFF /**< Infinite timeout */ #endif -#define PCSCLITE_VERSION_NUMBER "1.9.9" /**< Current version */ +#define PCSCLITE_VERSION_NUMBER "2.3.0" /**< Current version */ /** Maximum readers context (a slot is count as a reader) */ #define PCSCLITE_MAX_READERS_CONTEXTS 16 diff --git a/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/winscard.h b/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/winscard.h index d2c5a5758b5c0..f9a4265de85ca 100644 --- a/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/winscard.h +++ b/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/winscard.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2003 * David Corcoran - * Copyright (C) 2002-2009 + * Copyright (C) 2002-2018 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/wintypes.h b/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/wintypes.h index 3770de20909e1..5e8973a099362 100644 --- a/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/wintypes.h +++ b/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/wintypes.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2018 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/java.sql.rowset/share/classes/javax/sql/rowset/CachedRowSet.java b/src/java.sql.rowset/share/classes/javax/sql/rowset/CachedRowSet.java index c10cefef29000..e9efa2c711803 100644 --- a/src/java.sql.rowset/share/classes/javax/sql/rowset/CachedRowSet.java +++ b/src/java.sql.rowset/share/classes/javax/sql/rowset/CachedRowSet.java @@ -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 @@ -1561,10 +1561,10 @@ public interface CachedRowSet extends RowSet, Joinable { * method is more a matter of convenience when compared to using the version * of execute that takes a ResultSet object. * - * @param startRow the position in the ResultSet from where to start - * populating the records in this CachedRowSet * @param rs the ResultSet object containing the data * to be read into this CachedRowSet object + * @param startRow the position in the ResultSet from where to start + * populating the records in this CachedRowSet * @throws SQLException if a null ResultSet object is supplied * or this CachedRowSet object cannot * retrieve the associated ResultSetMetaData object diff --git a/src/java.xml/share/classes/javax/xml/stream/XMLEventFactory.java b/src/java.xml/share/classes/javax/xml/stream/XMLEventFactory.java index 6ca9768915c31..d47f4d0e1229c 100644 --- a/src/java.xml/share/classes/javax/xml/stream/XMLEventFactory.java +++ b/src/java.xml/share/classes/javax/xml/stream/XMLEventFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2023, 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 @@ -258,9 +258,9 @@ public abstract StartElement createStartElement(QName name, * an empty NamespaceContext. Querying this event for its namespaces or * attributes will result in an empty iterator being returned. * + * @param prefix the prefix of the QName of the new StartElement * @param namespaceUri the uri of the QName of the new StartElement * @param localName the local name of the QName of the new StartElement - * @param prefix the prefix of the QName of the new StartElement * @return an instance of the requested StartElement */ public abstract StartElement createStartElement(String prefix, @@ -272,9 +272,9 @@ public abstract StartElement createStartElement(String prefix, * Attributes can be added to this StartElement by passing an iterator * that walks over a set of Attribute interfaces. * + * @param prefix the prefix of the QName of the new StartElement * @param namespaceUri the uri of the QName of the new StartElement * @param localName the local name of the QName of the new StartElement - * @param prefix the prefix of the QName of the new StartElement * @param attributes an unordered set of objects that implement * Attribute to add to the new StartElement * @param namespaces an unordered set of objects that implement @@ -293,9 +293,9 @@ public abstract StartElement createStartElement(String prefix, * Attributes can be added to this StartElement by passing an iterator * that walks over a set of Attribute interfaces. * + * @param prefix the prefix of the QName of the new StartElement * @param namespaceUri the uri of the QName of the new StartElement * @param localName the local name of the QName of the new StartElement - * @param prefix the prefix of the QName of the new StartElement * @param attributes an unordered set of objects that implement * Attribute to add to the new StartElement, may be null * @param namespaces an unordered set of objects that implement @@ -323,9 +323,9 @@ public abstract EndElement createEndElement(QName name, /** * Create a new EndElement + * @param prefix the prefix of the QName of the new StartElement * @param namespaceUri the uri of the QName of the new StartElement * @param localName the local name of the QName of the new StartElement - * @param prefix the prefix of the QName of the new StartElement * @return an instance of the requested EndElement */ public abstract EndElement createEndElement(String prefix, @@ -333,9 +333,9 @@ public abstract EndElement createEndElement(String prefix, String localName); /** * Create a new EndElement + * @param prefix the prefix of the QName of the new StartElement * @param namespaceUri the uri of the QName of the new StartElement * @param localName the local name of the QName of the new StartElement - * @param prefix the prefix of the QName of the new StartElement * @param namespaces an unordered set of objects that implement * Namespace that have gone out of scope, may be null * @return an instance of the requested EndElement diff --git a/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java b/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java index 47ef2e437c993..a6bac73e528ab 100644 --- a/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java +++ b/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2022, 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 @@ -77,8 +77,8 @@ public XMLStreamException(Throwable th) { /** * Construct an exception with the associated message and exception * - * @param th a nested exception * @param msg the message to report + * @param th a nested exception */ public XMLStreamException(String msg, Throwable th) { super(msg, th); @@ -88,9 +88,9 @@ public XMLStreamException(String msg, Throwable th) { /** * Construct an exception with the associated message, exception and location. * - * @param th a nested exception * @param msg the message to report * @param location the location of the error + * @param th a nested exception */ public XMLStreamException(String msg, Location location, Throwable th) { super("ParseError at [row,col]:["+location.getLineNumber()+","+ diff --git a/src/java.xml/share/classes/javax/xml/stream/XMLStreamWriter.java b/src/java.xml/share/classes/javax/xml/stream/XMLStreamWriter.java index 7cd383245a807..9f0f49776e550 100644 --- a/src/java.xml/share/classes/javax/xml/stream/XMLStreamWriter.java +++ b/src/java.xml/share/classes/javax/xml/stream/XMLStreamWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2022, 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 @@ -209,8 +209,8 @@ public void writeStartElement(String namespaceURI, String localName) /** * Writes a start tag to the output - * @param localName local name of the tag, may not be null * @param prefix the prefix of the tag, may not be null + * @param localName local name of the tag, may not be null * @param namespaceURI the uri to bind the prefix to, may not be null * @throws XMLStreamException if an error occurs */ diff --git a/src/java.xml/share/classes/javax/xml/transform/TransformerConfigurationException.java b/src/java.xml/share/classes/javax/xml/transform/TransformerConfigurationException.java index a90e29121a81a..9c0b9a4be5bda 100644 --- a/src/java.xml/share/classes/javax/xml/transform/TransformerConfigurationException.java +++ b/src/java.xml/share/classes/javax/xml/transform/TransformerConfigurationException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, 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 @@ -67,9 +67,9 @@ public TransformerConfigurationException(Throwable e) { * Create a new TransformerConfigurationException with the * given Exception base cause and detail message. * + * @param msg The detail message. * @param e The exception to be encapsulated in a * TransformerConfigurationException - * @param msg The detail message. */ public TransformerConfigurationException(String msg, Throwable e) { super(msg, e); diff --git a/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryConfigurationError.java b/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryConfigurationError.java index 47c4dda1ee664..b61060b74042b 100644 --- a/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryConfigurationError.java +++ b/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryConfigurationError.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 @@ -69,9 +69,9 @@ public SchemaFactoryConfigurationError(Throwable cause) { * Create a new SchemaFactoryConfigurationError with the * given Throwable base cause and detail message. * + * @param message The detail message. * @param cause The exception or error to be encapsulated in a * SchemaFactoryConfigurationError. - * @param message The detail message. */ public SchemaFactoryConfigurationError(String message, Throwable cause) { super(message, cause); diff --git a/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java b/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java index 93656cdf51381..10d23f335354e 100644 --- a/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java +++ b/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java @@ -42,6 +42,8 @@ import java.util.Properties; import java.util.stream.Collectors; +import java.nio.charset.StandardCharsets; + /* * The HotSpot implementation of com.sun.tools.attach.VirtualMachine. */ @@ -102,7 +104,7 @@ private void loadAgentLibrary(String agentLibrary, boolean isAbsolute, String op agentLibrary, isAbsolute ? "true" : "false", options); - String result = readErrorMessage(in); + String result = readMessage(in); if (result.isEmpty()) { throw new AgentLoadException("Target VM did not respond"); } else if (result.startsWith(msgPrefix)) { @@ -327,6 +329,45 @@ public InputStream executeCommand(String cmd, Object ... args) throws IOExceptio } } + // Attach API version support + protected static final int VERSION_1 = 1; + protected static final int VERSION_2 = 2; + + /* + * Detects Attach API version supported by target VM. + */ + protected int detectVersion() throws IOException { + try { + InputStream reply = execute("getversion"); + String message = readMessage(reply); + reply.close(); + try { + int supportedVersion = Integer.parseUnsignedInt(message); + // we expect only VERSION_2 + if (supportedVersion == VERSION_2) { + return VERSION_2; + } + } catch (NumberFormatException nfe) { + // bad reply - fallback to VERSION_1 + } + } catch (AttachOperationFailedException | AgentLoadException ex) { + // the command is not supported, the VM supports VERSION_1 only + } + return VERSION_1; + } + + /* + * For testing purposes Attach API v2 may be disabled. + */ + protected boolean isAPIv2Enabled() { + // if "jdk.attach.compat" property is set, only v1 is enabled. + try { + String value = System.getProperty("jdk.attach.compat"); + return !("true".equalsIgnoreCase(value)); + } catch (SecurityException se) { + } + return true; + } /* * Utility method to read an 'int' from the input stream. Ideally @@ -367,7 +408,7 @@ int readInt(InputStream in) throws IOException { /* * Utility method to read data into a String. */ - String readErrorMessage(InputStream in) throws IOException { + String readMessage(InputStream in) throws IOException { String s; StringBuilder message = new StringBuilder(); BufferedReader br = new BufferedReader(new InputStreamReader(in)); @@ -400,7 +441,7 @@ void processCompletionStatus(IOException ioe, String cmd, InputStream sis) throw } if (completionStatus != 0) { // read from the stream and use that as the error message - String message = readErrorMessage(sis); + String message = readMessage(sis); sis.close(); // In the event of a protocol mismatch then the target VM @@ -417,6 +458,51 @@ void processCompletionStatus(IOException ioe, String cmd, InputStream sis) throw } } + /* + * Helper writer interface to send commands to the target VM. + */ + public static interface AttachOutputStream { + abstract void write(byte[] buffer, int offset, int length) throws IOException; + } + + private int dataSize(Object obj) { + return (obj == null ? 0 : obj.toString().getBytes(StandardCharsets.UTF_8).length) + 1; + } + + /* + * Writes object (usually String or Integer) to the attach writer. + */ + private void writeString(AttachOutputStream writer, Object obj) throws IOException { + if (obj != null) { + String s = obj.toString(); + if (s.length() > 0) { + byte[] b = s.getBytes(StandardCharsets.UTF_8); + writer.write(b, 0, b.length); + } + } + byte b[] = new byte[1]; + b[0] = 0; + writer.write(b, 0, 1); + } + + protected void writeCommand(AttachOutputStream writer, int ver, String cmd, Object ... args) throws IOException { + writeString(writer, ver); + if (ver == VERSION_2) { + // for v2 write size of the data + int size = dataSize(cmd); + for (Object arg: args) { + size += dataSize(arg); + } + writeString(writer, size); + } + writeString(writer, cmd); + // v1 commands always write 3 arguments + int argNumber = ver == VERSION_1 ? 3 : args.length; + for (int i = 0; i < argNumber; i++) { + writeString(writer, i < args.length ? args[i] : null); + } + } + /* * InputStream for the socket connection to get target VM */ diff --git a/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java index 9c30f5618d66e..23c15ad06e187 100644 --- a/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java @@ -26,6 +26,7 @@ import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AttachNotSupportedException; +import com.sun.tools.attach.AttachOperationFailedException; import com.sun.tools.attach.spi.AttachProvider; import java.io.IOException; @@ -42,6 +43,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { private static byte[] stub; private volatile long hProcess; // handle to the process + private int ver = VERSION_1; // updated in ctor depending on detectVersion result VirtualMachineImpl(AttachProvider provider, String id) throws AttachNotSupportedException, IOException @@ -51,11 +53,15 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { int pid = Integer.parseInt(id); hProcess = openProcess(pid); - // The target VM might be a pre-6.0 VM so we enqueue a "null" command - // which minimally tests that the enqueue function exists in the target - // VM. try { - enqueue(hProcess, stub, null, null); + if (isAPIv2Enabled()) { + ver = detectVersion(); + } else { + // The target VM might be a pre-6.0 VM so we enqueue a "null" command + // which minimally tests that the enqueue function exists in the target + // VM. + enqueue(hProcess, stub, VERSION_1, null, null); + } } catch (IOException x) { throw new AttachNotSupportedException(x.getMessage()); } @@ -73,7 +79,6 @@ public void detach() throws IOException { InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException { - assert args.length <= 3; // includes null checkNulls(args); // create a pipe using a random name @@ -83,12 +88,12 @@ InputStream execute(String cmd, Object ... args) String pipename = pipeprefix + r; long hPipe; try { - hPipe = createPipe(pipename); + hPipe = createPipe(ver, pipename); } catch (IOException ce) { // Retry with another random pipe name. r = rnd.nextInt(); pipename = pipeprefix + r; - hPipe = createPipe(pipename); + hPipe = createPipe(ver, pipename); } // check if we are detached - in theory it's possible that detach is invoked @@ -99,18 +104,34 @@ InputStream execute(String cmd, Object ... args) } try { - // enqueue the command to the process - enqueue(hProcess, stub, cmd, pipename, args); + // enqueue the command to the process. + if (ver == VERSION_1) { + enqueue(hProcess, stub, ver, cmd, pipename, args); + } else { + // for v2 operations request contains only pipe name. + enqueue(hProcess, stub, ver, null, pipename); + } - // wait for command to complete - process will connect with the - // completion status + // wait for the target VM to connect to the pipe. connectPipe(hPipe); + IOException ioe = null; + + if (ver == VERSION_2) { + PipeOutputStream writer = new PipeOutputStream(hPipe); + + try { + writeCommand(writer, ver, cmd, args); + } catch (IOException x) { + ioe = x; + } + } + // create an input stream for the pipe SocketInputStreamImpl in = new SocketInputStreamImpl(hPipe); // Process the command completion status - processCompletionStatus(null, cmd, in); + processCompletionStatus(ioe, cmd, in); // return the input stream return in; @@ -121,6 +142,17 @@ InputStream execute(String cmd, Object ... args) } } + private static class PipeOutputStream implements AttachOutputStream { + private long hPipe; + public PipeOutputStream(long hPipe) { + this.hPipe = hPipe; + } + @Override + public void write(byte[] buffer, int offset, int length) throws IOException { + VirtualMachineImpl.writePipe(hPipe, buffer, offset, length); + } + } + // An InputStream based on a pipe to the target VM private static class SocketInputStreamImpl extends SocketInputStream { public SocketInputStreamImpl(long fd) { @@ -149,7 +181,7 @@ protected void close(long fd) throws IOException { static native void closeProcess(long hProcess) throws IOException; - static native long createPipe(String name) throws IOException; + static native long createPipe(int ver, String name) throws IOException; static native void closePipe(long hPipe) throws IOException; @@ -157,7 +189,9 @@ protected void close(long fd) throws IOException { static native int readPipe(long hPipe, byte buf[], int off, int buflen) throws IOException; - static native void enqueue(long hProcess, byte[] stub, + static native void writePipe(long hPipe, byte buf[], int off, int buflen) throws IOException; + + static native void enqueue(long hProcess, byte[] stub, int ver, String cmd, String pipename, Object ... args) throws IOException; static { diff --git a/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c b/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c index a8b17c22d83f2..7a436ef85c259 100644 --- a/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c +++ b/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c @@ -46,9 +46,11 @@ static IsWow64ProcessFunc _IsWow64Process; typedef BOOL (WINAPI *EnumProcessModulesFunc) (HANDLE, HMODULE *, DWORD, LPDWORD ); typedef DWORD (WINAPI *GetModuleFileNameExFunc) ( HANDLE, HMODULE, LPTSTR, DWORD ); -/* exported function in target VM */ +/* exported functions in target VM */ typedef jint (WINAPI* EnqueueOperationFunc) (const char* cmd, const char* arg1, const char* arg2, const char* arg3, const char* pipename); +typedef jint (WINAPI* EnqueueOperationFunc_v2) + (const char* pipename); /* OpenProcess with SE_DEBUG_NAME privilege */ static HANDLE @@ -70,11 +72,13 @@ static jboolean jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, size_t #define MAX_PIPE_NAME_LENGTH 256 typedef struct { + jint version; GetModuleHandleFunc _GetModuleHandle; GetProcAddressFunc _GetProcAddress; char jvmLib[MAX_LIBNAME_LENGTH]; /* "jvm.dll" */ char func1[MAX_FUNC_LENGTH]; char func2[MAX_FUNC_LENGTH]; + char func_v2[MAX_FUNC_LENGTH]; char cmd[MAX_CMD_LENGTH + 1]; /* "load", "dump", ... */ char arg[MAX_ARGS][MAX_ARG_LENGTH + 1]; /* arguments to command */ char pipename[MAX_PIPE_NAME_LENGTH + 1]; @@ -102,27 +106,36 @@ DEF_STATIC_JNI_OnLoad DWORD WINAPI jvm_attach_thread_func(DataBlock *pData) { HINSTANCE h; - EnqueueOperationFunc addr; h = pData->_GetModuleHandle(pData->jvmLib); if (h == NULL) { return ERR_OPEN_JVM_FAIL; } - addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func1)); - if (addr == NULL) { - addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func2)); - } - if (addr == NULL) { + if (pData->version == 1) { + EnqueueOperationFunc addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func1)); + if (addr == NULL) { + addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func2)); + } + if (addr == NULL) { + return ERR_GET_ENQUEUE_FUNC_FAIL; + } + /* "null" command - does nothing in the target VM */ + if (pData->cmd[0] == '\0') { + return 0; + } else { + return (*addr)(pData->cmd, pData->arg[0], pData->arg[1], pData->arg[2], pData->pipename); + } + } else if (pData->version == 2) { + EnqueueOperationFunc_v2 addr = (EnqueueOperationFunc_v2)(pData->_GetProcAddress(h, pData->func_v2)); + if (addr == NULL) { + return ERR_GET_ENQUEUE_FUNC_FAIL; + } + return (*addr)(pData->pipename); + } else { return ERR_GET_ENQUEUE_FUNC_FAIL; } - /* "null" command - does nothing in the target VM */ - if (pData->cmd[0] == '\0') { - return 0; - } else { - return (*addr)(pData->cmd, pData->arg[0], pData->arg[1], pData->arg[2], pData->pipename); - } } /* This function marks the end of jvm_attach_thread_func. */ @@ -261,7 +274,7 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_closeProcess * Signature: (Ljava/lang/String;)J */ JNIEXPORT jlong JNICALL Java_sun_tools_attach_VirtualMachineImpl_createPipe - (JNIEnv *env, jclass cls, jstring pipename) + (JNIEnv *env, jclass cls, jint ver, jstring pipename) { HANDLE hPipe; char name[MAX_PIPE_NAME_LENGTH]; @@ -289,7 +302,8 @@ JNIEXPORT jlong JNICALL Java_sun_tools_attach_VirtualMachineImpl_createPipe hPipe = CreateNamedPipe( name, // pipe name - PIPE_ACCESS_INBOUND, // read access + ver == 1 ? PIPE_ACCESS_INBOUND // read access + : PIPE_ACCESS_DUPLEX, // read-write access PIPE_TYPE_BYTE | // byte mode PIPE_READMODE_BYTE | PIPE_WAIT, // blocking mode @@ -377,14 +391,46 @@ JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_readPipe return (jint)nread; } +/* + * Class: sun_tools_attach_VirtualMachineImpl + * Method: writePipe + * Signature: (J[BII)V + */ +JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_writePipe + (JNIEnv *env, jclass cls, jlong hPipe, jbyteArray buffer, jint offset, jint length) +{ + jsize remaining = length; + do { + jbyte buf[128]; + jsize len = sizeof(buf); + DWORD written; + + if (len > remaining) { + len = remaining; + } + (*env)->GetByteArrayRegion(env, buffer, offset, len, buf); + + BOOL fSuccess = WriteFile((HANDLE)hPipe, buf, len, &written, NULL); + + if (!fSuccess) { + JNU_ThrowIOExceptionWithLastError(env, "WriteFile"); + return; + } + + offset += written; + remaining -= written; + + } while (remaining > 0); +} + /* * Class: sun_tools_attach_VirtualMachineImpl * Method: enqueue * Signature: (JZLjava/lang/String;[Ljava/lang/Object;)V */ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue - (JNIEnv *env, jclass cls, jlong handle, jbyteArray stub, jstring cmd, - jstring pipename, jobjectArray args) + (JNIEnv *env, jclass cls, jlong handle, jbyteArray stub, jint ver, + jstring cmd, jstring pipename, jobjectArray args) { DataBlock data; DataBlock* pData; @@ -399,12 +445,15 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue * Setup data to copy to target process */ memset(&data, 0, sizeof(data)); + data.version = ver; + data._GetModuleHandle = _GetModuleHandle; data._GetProcAddress = _GetProcAddress; strcpy(data.jvmLib, "jvm"); strcpy(data.func1, "JVM_EnqueueOperation"); strcpy(data.func2, "_JVM_EnqueueOperation@20"); + strcpy(data.func_v2, "JVM_EnqueueOperation_v2"); /* * Command and arguments @@ -432,7 +481,7 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue return; } } - if ((*env)->ExceptionOccurred(env)) return; + if ((*env)->ExceptionCheck(env)) return; } } for (i = argsLen; i < MAX_ARGS; i++) { @@ -463,7 +512,7 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue stubLen = (DWORD)(*env)->GetArrayLength(env, stub); stubCode = (*env)->GetByteArrayElements(env, stub, &isCopy); - if ((*env)->ExceptionOccurred(env)) return; + if ((*env)->ExceptionCheck(env)) return; pCode = (PDWORD) VirtualAllocEx( hProcess, 0, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if (pCode == NULL) { @@ -636,7 +685,7 @@ static jboolean jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, size_t cstr[0] = '\0'; } else { str = JNU_GetStringPlatformChars(env, jstr, &isCopy); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return result; } if (strlen(str) >= cstr_buf_size) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java index b37b571e79529..0c589c54edd94 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java @@ -262,6 +262,7 @@ public enum Feature { PRIMITIVE_PATTERNS(JDK23, Fragments.FeaturePrimitivePatterns, DiagKind.PLURAL), FLEXIBLE_CONSTRUCTORS(JDK22, Fragments.FeatureFlexibleConstructors, DiagKind.NORMAL), MODULE_IMPORTS(JDK23, Fragments.FeatureModuleImports, DiagKind.PLURAL), + PRIVATE_MEMBERS_IN_PERMITS_CLAUSE(JDK19), ; enum DiagKind { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java index 4e62828c42658..cfe4ef662e5cb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java @@ -51,7 +51,6 @@ import com.sun.tools.javac.code.Type.JCPrimitiveType; import com.sun.tools.javac.code.Type.JCVoidType; import com.sun.tools.javac.code.Type.MethodType; -import com.sun.tools.javac.code.Type.UnknownType; import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.comp.Modules; import com.sun.tools.javac.jvm.Target; @@ -408,9 +407,6 @@ protected Symtab(Context context) throws CompletionFailure { names = Names.instance(context); - // Create the unknown type - unknownType = new UnknownType(); - messages = JavacMessages.instance(context); MissingInfoHandler missingInfoHandler = MissingInfoHandler.instance(context); @@ -420,6 +416,23 @@ protected Symtab(Context context) throws CompletionFailure { missingInfoHandler, target.runtimeUseNestAccess()); + noModule = new ModuleSymbol(names.empty, null) { + @Override public boolean isNoModule() { + return true; + } + }; + addRootPackageFor(noModule); + + Source source = Source.instance(context); + if (Feature.MODULES.allowedInSource(source)) { + java_base = enterModule(names.java_base); + //avoid completing java.base during the Symtab initialization + java_base.completer = Completer.NULL_COMPLETER; + java_base.visiblePackages = Collections.emptyMap(); + } else { + java_base = noModule; + } + // create the basic builtin symbols unnamedModule = new ModuleSymbol(names.empty, null) { { @@ -427,7 +440,6 @@ protected Symtab(Context context) throws CompletionFailure { exports = List.nil(); provides = List.nil(); uses = List.nil(); - ModuleSymbol java_base = enterModule(names.java_base); com.sun.tools.javac.code.Directive.RequiresDirective d = new com.sun.tools.javac.code.Directive.RequiresDirective(java_base, EnumSet.of(com.sun.tools.javac.code.Directive.RequiresFlag.MANDATED)); @@ -447,7 +459,6 @@ public String toString() { exports = List.nil(); provides = List.nil(); uses = List.nil(); - ModuleSymbol java_base = enterModule(names.java_base); com.sun.tools.javac.code.Directive.RequiresDirective d = new com.sun.tools.javac.code.Directive.RequiresDirective(java_base, EnumSet.of(com.sun.tools.javac.code.Directive.RequiresFlag.MANDATED)); @@ -456,13 +467,6 @@ public String toString() { }; addRootPackageFor(errModule); - noModule = new ModuleSymbol(names.empty, null) { - @Override public boolean isNoModule() { - return true; - } - }; - addRootPackageFor(noModule); - noSymbol = new TypeSymbol(NIL, 0, names.empty, Type.noType, rootPackage) { @Override @DefinedBy(Api.LANGUAGE_MODEL) public R accept(ElementVisitor v, P p) { @@ -475,8 +479,8 @@ public R accept(ElementVisitor v, P p) { errType = new ErrorType(errSymbol, Type.noType); unknownSymbol = new ClassSymbol(PUBLIC|STATIC|ACYCLIC, names.fromString(""), null, rootPackage); - unknownSymbol.members_field = new Scope.ErrorScope(unknownSymbol); - unknownSymbol.type = unknownType; + // Create the unknown type + unknownType = new ErrorType(unknownSymbol, Type.noType); // initialize builtin types initType(byteType, "byte", "Byte"); @@ -526,16 +530,6 @@ public R accept(ElementVisitor v, P p) { // Enter symbol for the errSymbol scope.enter(errSymbol); - Source source = Source.instance(context); - if (Feature.MODULES.allowedInSource(source)) { - java_base = enterModule(names.java_base); - //avoid completing java.base during the Symtab initialization - java_base.completer = Completer.NULL_COMPLETER; - java_base.visiblePackages = Collections.emptyMap(); - } else { - java_base = noModule; - } - // Get the initial completer for ModuleSymbols from Modules moduleCompleter = Modules.instance(context).getCompleter(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java index 151c39fae40f0..7bcef30a3f9af 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java @@ -500,7 +500,7 @@ protected void appendAnnotationsString(StringBuilder sb, if (prefix) { sb.append(" "); } - sb.append(getAnnotationMirrors()); + sb.append(getAnnotationMirrors().toString(" ")); sb.append(" "); } } @@ -2408,30 +2408,6 @@ public R accept(TypeVisitor v, P p) { } } - public static class UnknownType extends Type { - - public UnknownType() { - // Unknown is a synthesized internal type, so it cannot be - // annotated. - super(null, List.nil()); - } - - @Override - public TypeTag getTag() { - return UNKNOWN; - } - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public R accept(TypeVisitor v, P p) { - return v.visitUnknown(this, p); - } - - @Override - public boolean isPartial() { - return true; - } - } - /** * A visitor for types. A visitor is used to implement operations * (or relations) on types. Most common operations on types are diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java index 944494760719c..51d3deec88bcb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java @@ -121,10 +121,6 @@ public enum TypeTag { */ ERROR, - /** The tag of an unknown type - */ - UNKNOWN, - /** The tag of all instantiatable type variables. */ UNDETVAR, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index 8576d8cfb2f02..e35ecbdc95684 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -1216,7 +1216,7 @@ public Boolean visitArrayType(ArrayType t, Type s) { @Override public Boolean visitUndetVar(UndetVar t, Type s) { //todo: test against origin needed? or replace with substitution? - if (t == s || t.qtype == s || s.hasTag(ERROR) || s.hasTag(UNKNOWN)) { + if (t == s || t.qtype == s || s.hasTag(ERROR)) { return true; } else if (s.hasTag(BOT)) { //if 's' is 'null' there's no instantiated type U for which @@ -1466,7 +1466,7 @@ public Boolean visitUndetVar(UndetVar t, Type s) { return false; } - if (t == s || t.qtype == s || s.hasTag(ERROR) || s.hasTag(UNKNOWN)) { + if (t == s || t.qtype == s || s.hasTag(ERROR)) { return true; } @@ -2422,7 +2422,7 @@ private Type combineMetadata(final Type s, ARRAY, MODULE, TYPEVAR, WILDCARD, BOT: return s.dropMetadata(Annotations.class); case VOID, METHOD, PACKAGE, FORALL, DEFERRED, - NONE, ERROR, UNKNOWN, UNDETVAR, UNINITIALIZED_THIS, + NONE, ERROR, UNDETVAR, UNINITIALIZED_THIS, UNINITIALIZED_OBJECT: return s; default: @@ -3328,6 +3328,10 @@ public Type subst(Type t, List from, List to) { return t.map(new Subst(from, to)); } + /* this class won't substitute all types for example UndetVars are never substituted, this is + * by design as UndetVars are used locally during inference and shouldn't escape from inference routines, + * some specialized applications could need a tailored solution + */ private class Subst extends StructuralTypeMapping { List from; List to; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java index b8afce009a591..f121849457c77 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java @@ -92,6 +92,10 @@ public class AttrContext { */ boolean allowProtectedAccess = false; + /** Are we attributing a permits clause? + */ + boolean isPermitsClause = false; + /** Are arguments to current function applications boxed into an array for varargs? */ Resolve.MethodResolutionPhase pendingResolutionPhase = null; @@ -149,6 +153,7 @@ AttrContext dup(WriteableScope scope) { info.preferredTreeForDiagnostics = preferredTreeForDiagnostics; info.visitingServiceImplementation = visitingServiceImplementation; info.allowProtectedAccess = allowProtectedAccess; + info.isPermitsClause = isPermitsClause; return info; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java index f5df6adddf377..81e07277bfbdc 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java @@ -801,15 +801,15 @@ public abstract class IncorporationAction { /** * Helper function: perform subtyping through incorporation cache. */ - boolean isSubtype(Type s, Type t, Warner warn) { - return doIncorporationOp(IncorporationBinaryOpKind.IS_SUBTYPE, s, t, warn); + boolean isSubtype(Type s, Type t, Warner warn, InferenceContext ic) { + return doIncorporationOp(IncorporationBinaryOpKind.IS_SUBTYPE, s, t, warn, ic); } /** * Helper function: perform type-equivalence through incorporation cache. */ - boolean isSameType(Type s, Type t) { - return doIncorporationOp(IncorporationBinaryOpKind.IS_SAME_TYPE, s, t, null); + boolean isSameType(Type s, Type t, InferenceContext ic) { + return doIncorporationOp(IncorporationBinaryOpKind.IS_SAME_TYPE, s, t, null, ic); } @Override @@ -853,7 +853,7 @@ void apply(InferenceContext inferenceContext, Warner warn) { for (Type b : uv.getBounds(to)) { b = typeFunc.apply(inferenceContext, b); if (optFilter != null && optFilter.test(inferenceContext, b)) continue; - boolean success = checkBound(t, b, from, to, warn); + boolean success = checkBound(t, b, from, to, warn, inferenceContext); if (!success) { report(from, to); } @@ -873,13 +873,13 @@ EnumSet boundsToCheck() { /** * Is source type 's' compatible with target type 't' given source and target bound kinds? */ - boolean checkBound(Type s, Type t, InferenceBound ib_s, InferenceBound ib_t, Warner warn) { + boolean checkBound(Type s, Type t, InferenceBound ib_s, InferenceBound ib_t, Warner warn, InferenceContext ic) { if (ib_s.lessThan(ib_t)) { - return isSubtype(s, t, warn); + return isSubtype(s, t, warn, ic); } else if (ib_t.lessThan(ib_s)) { - return isSubtype(t, s, warn); + return isSubtype(t, s, warn, ic); } else { - return isSameType(s, t); + return isSameType(s, t, ic); } } @@ -1010,7 +1010,7 @@ void apply(InferenceContext inferenceContext, Warner warn) { if (!allParamsSuperBound1.head.hasTag(WILDCARD) && !allParamsSuperBound2.head.hasTag(WILDCARD)) { if (!isSameType(inferenceContext.asUndetVar(allParamsSuperBound1.head), - inferenceContext.asUndetVar(allParamsSuperBound2.head))) { + inferenceContext.asUndetVar(allParamsSuperBound2.head), inferenceContext)) { reportBoundError(uv, InferenceBound.UPPER); } } @@ -1194,11 +1194,11 @@ private Type asSuper(Type t, Type sup) { types.asSuper(t, sup.tsym); } - boolean doIncorporationOp(IncorporationBinaryOpKind opKind, Type op1, Type op2, Warner warn) { - IncorporationBinaryOp newOp = new IncorporationBinaryOp(opKind, op1, op2); + boolean doIncorporationOp(IncorporationBinaryOpKind opKind, Type op1, Type op2, Warner warn, InferenceContext ic) { + IncorporationBinaryOpKey newOp = new IncorporationBinaryOpKey(opKind, ic.asTypeVar(op1), ic.asTypeVar(op2), types); Boolean res = incorporationCache.get(newOp); if (res == null) { - incorporationCache.put(newOp, res = newOp.apply(warn)); + incorporationCache.put(newOp, res = opKind.apply(op1, op2, warn, types)); } return res; } @@ -1232,26 +1232,14 @@ boolean apply(Type op1, Type op2, Warner warn, Types types) { * are not executed unnecessarily (which would potentially lead to adding * same bounds over and over). */ - class IncorporationBinaryOp { - - IncorporationBinaryOpKind opKind; - Type op1; - Type op2; - - IncorporationBinaryOp(IncorporationBinaryOpKind opKind, Type op1, Type op2) { - this.opKind = opKind; - this.op1 = op1; - this.op2 = op2; - } - + record IncorporationBinaryOpKey(IncorporationBinaryOpKind opKind, Type op1, Type op2, Types types) { @Override public boolean equals(Object o) { - return (o instanceof IncorporationBinaryOp incorporationBinaryOp) - && opKind == incorporationBinaryOp.opKind - && types.isSameType(op1, incorporationBinaryOp.op1) - && types.isSameType(op2, incorporationBinaryOp.op2); + return (o instanceof IncorporationBinaryOpKey anotherKey) + && opKind == anotherKey.opKind + && types.isSameType(op1, anotherKey.op1) + && types.isSameType(op2, anotherKey.op2); } - @Override public int hashCode() { int result = opKind.hashCode(); @@ -1261,14 +1249,10 @@ public int hashCode() { result += types.hashCode(op2); return result; } - - boolean apply(Warner warn) { - return opKind.apply(op1, op2, warn, types); - } } /** an incorporation cache keeps track of all executed incorporation-related operations */ - Map incorporationCache = new LinkedHashMap<>(); + Map incorporationCache = new LinkedHashMap<>(); protected static class BoundFilter implements Predicate { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java index 2fec365aff521..35cd9a25ae43d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java @@ -214,6 +214,20 @@ final List asUndetVars(List ts) { return buf.toList(); } + /** + * Replace all undet vars in a given type with corresponding free variables + */ + public final Type asTypeVar(Type t) { + return asTypeVarFun.apply(t); + } + + Types.TypeMapping asTypeVarFun = new Type.StructuralTypeMapping<>() { + @Override + public Type visitUndetVar(UndetVar uv, Void aVoid) { + return uv.qtype; + } + }; + List instTypes() { ListBuffer buf = new ListBuffer<>(); for (Type t : undetvars) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 5bf1bc0ead149..b6d7e16690283 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -111,6 +111,7 @@ public class Resolve { private final boolean compactMethodDiags; private final boolean allowLocalVariableTypeInference; private final boolean allowYieldStatement; + private final boolean allowPrivateMembersInPermitsClause; final EnumSet verboseResolutionMode; final boolean dumpMethodReferenceSearchResults; final boolean dumpStacktraceOnError; @@ -147,6 +148,7 @@ protected Resolve(Context context) { Target target = Target.instance(context); allowLocalVariableTypeInference = Feature.LOCAL_VARIABLE_TYPE_INFERENCE.allowedInSource(source); allowYieldStatement = Feature.SWITCH_EXPRESSION.allowedInSource(source); + allowPrivateMembersInPermitsClause = Feature.PRIVATE_MEMBERS_IN_PERMITS_CLAUSE.allowedInSource(source); polymorphicSignatureScope = WriteableScope.create(syms.noSymbol); allowModules = Feature.MODULES.allowedInSource(source); allowRecords = Feature.RECORDS.allowedInSource(source); @@ -425,7 +427,9 @@ public boolean isAccessible(Env env, Type site, Symbol sym, boolean (env.enclClass.sym == sym.owner // fast special case || env.enclClass.sym.outermostClass() == - sym.owner.outermostClass()) + sym.owner.outermostClass() + || + privateMemberInPermitsClauseIfAllowed(env, sym)) && sym.isInheritedIn(site.tsym, types); case 0: @@ -458,6 +462,13 @@ public boolean isAccessible(Env env, Type site, Symbol sym, boolean return isAccessible(env, site, checkInner) && notOverriddenIn(site, sym); } } + + private boolean privateMemberInPermitsClauseIfAllowed(Env env, Symbol sym) { + return allowPrivateMembersInPermitsClause && + env.info.isPermitsClause && + ((JCClassDecl) env.tree).sym.outermostClass() == sym.owner.outermostClass(); + } + //where /* `sym' is accessible only if not overridden by * another symbol which is a member of `site' @@ -1853,6 +1864,10 @@ Symbol findMethod(Env env, bestSoFar, allowBoxing, useVarargs); + if (bestSoFar.kind == AMBIGUOUS) { + AmbiguityError a_err = (AmbiguityError)bestSoFar.baseSymbol(); + bestSoFar = a_err.mergeAbstracts(site); + } return bestSoFar; } // where @@ -2757,7 +2772,7 @@ Symbol resolveMethod(DiagnosticPosition pos, return lookupMethod(env, pos, env.enclClass.sym, resolveMethodCheck, new BasicLookupHelper(name, env.enclClass.sym.type, argtypes, typeargtypes) { @Override - Symbol doLookup(Env env, MethodResolutionPhase phase) { + Symbol lookup(Env env, MethodResolutionPhase phase) { return findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()); @@ -2789,7 +2804,7 @@ private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext, List typeargtypes) { return lookupMethod(env, pos, location, resolveContext, new BasicLookupHelper(name, site, argtypes, typeargtypes) { @Override - Symbol doLookup(Env env, MethodResolutionPhase phase) { + Symbol lookup(Env env, MethodResolutionPhase phase) { return findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()); @@ -2913,7 +2928,7 @@ private Symbol resolveConstructor(MethodResolutionContext resolveContext, List typeargtypes) { return lookupMethod(env, pos, site.tsym, resolveContext, new BasicLookupHelper(names.init, site, argtypes, typeargtypes) { @Override - Symbol doLookup(Env env, MethodResolutionPhase phase) { + Symbol lookup(Env env, MethodResolutionPhase phase) { return findConstructor(pos, env, site, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()); @@ -2972,7 +2987,7 @@ Symbol resolveDiamond(DiagnosticPosition pos, return lookupMethod(env, pos, site.tsym, resolveMethodCheck, new BasicLookupHelper(names.init, site, argtypes, typeargtypes) { @Override - Symbol doLookup(Env env, MethodResolutionPhase phase) { + Symbol lookup(Env env, MethodResolutionPhase phase) { return findDiamond(pos, env, site, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()); @@ -3503,18 +3518,6 @@ abstract class BasicLookupHelper extends LookupHelper { super(name, site, argtypes, typeargtypes, maxPhase); } - @Override - final Symbol lookup(Env env, MethodResolutionPhase phase) { - Symbol sym = doLookup(env, phase); - if (sym.kind == AMBIGUOUS) { - AmbiguityError a_err = (AmbiguityError)sym.baseSymbol(); - sym = a_err.mergeAbstracts(site); - } - return sym; - } - - abstract Symbol doLookup(Env env, MethodResolutionPhase phase); - @Override Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { if (sym.kind.isResolutionError()) { @@ -3561,10 +3564,6 @@ ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) { abstract JCMemberReference.ReferenceKind referenceKind(Symbol sym); Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { - if (sym.kind == AMBIGUOUS) { - AmbiguityError a_err = (AmbiguityError)sym.baseSymbol(); - sym = a_err.mergeAbstracts(site); - } //skip error reporting return sym; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java index 5be8d755d41e2..b518d7edb4b3a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java @@ -979,11 +979,17 @@ private void fillPermits(JCClassDecl tree, Env baseEnv) { if (sym.isPermittedExplicit) { ListBuffer permittedSubtypeSymbols = new ListBuffer<>(); List permittedTrees = tree.permitting; - for (JCExpression permitted : permittedTrees) { - Type pt = attr.attribBase(permitted, baseEnv, false, false, false); - permittedSubtypeSymbols.append(pt.tsym); + var isPermitsClause = baseEnv.info.isPermitsClause; + try { + baseEnv.info.isPermitsClause = true; + for (JCExpression permitted : permittedTrees) { + Type pt = attr.attribBase(permitted, baseEnv, false, false, false); + permittedSubtypeSymbols.append(pt.tsym); + } + sym.setPermittedSubclasses(permittedSubtypeSymbols.toList()); + } finally { + baseEnv.info.isPermitsClause = isPermitsClause; } - sym.setPermittedSubclasses(permittedSubtypeSymbols.toList()); } } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 6abf9f057b043..233629e10bb56 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2192,7 +2192,7 @@ public void visitCompoundAnnotationProxy(CompoundAnnotationProxy proxy) { Type resolvePossibleProxyType(Type t) { if (t instanceof ProxyType proxyType) { - Assert.check(requestingOwner.owner.kind == MDL); + Assert.check(requestingOwner.owner instanceof ModuleSymbol); ModuleSymbol prevCurrentModule = currentModule; currentModule = (ModuleSymbol) requestingOwner.owner; try { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java index 1bc5de7f73a80..71e39a6a4080f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java @@ -193,10 +193,14 @@ public NoType getNoType(TypeKind kind) { public ArrayType getArrayType(TypeMirror componentType) { switch (componentType.getKind()) { case VOID: + case NONE: + case NULL: case EXECUTABLE: case WILDCARD: // heh! case PACKAGE: case MODULE: + case UNION: + case INTERSECTION: throw new IllegalArgumentException(componentType.toString()); } return new Type.ArrayType((Type) componentType, syms.arrayClass); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/StringNameTable.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/StringNameTable.java index b8106a43b7c9d..81d67b241487a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/StringNameTable.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/StringNameTable.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 @@ -62,7 +62,15 @@ public StringNameTable(Names names, int initialCapacity, boolean intern) { @Override public Name fromString(String string) { - return this.nameMap.computeIfAbsent(string, s -> new NameImpl(this, intern ? s.intern() : s)); + Name name = nameMap.get(string); + if (name == null) { + if (intern) { + string = string.intern(); + } + name = new NameImpl(this, string); + nameMap.put(string, name); + } + return name; } @Override diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java index d528f1b848584..49718e254b3e1 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java @@ -240,6 +240,19 @@ protected Object writeReplace() throws ObjectStreamException { return new KeyRep(type, getAlgorithm(), format, getEncodedInternal()); } + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException("P11Key not directly deserializable"); + } + public String toString() { token.ensureValid(); String s1 = token.provider.getName() + " " + algorithm + " " + type diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java index 70effc141bc11..7ef8510ddee48 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.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 @@ -187,9 +187,23 @@ private void implNextBytes(byte[] bytes) { } } + /** + * Restores the state of this object from the stream. + * + * @param in the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (token == null) { + throw new InvalidObjectException("token is null"); + } + if (mixBuffer != null) { + mixBuffer = mixBuffer.clone(); + } // assign default values to non-null transient fields iBuffer = new byte[IBUFFER_SIZE]; ibuffered = 0; diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java index 44a2c4efb0694..e77edc98399eb 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -1947,6 +1947,19 @@ private Object writeReplace() throws ObjectStreamException { return new SunPKCS11Rep(this); } + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException("SunPKCS11 not directly deserializable"); + } + /** * Serialized representation of the SunPKCS11 provider. */ diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java index a25fa1c39e5b7..d6c291ebc570c 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java @@ -127,11 +127,6 @@ public String toString() { sb.append(pPassword.length); sb.append(Constants.NEWLINE); - sb.append(Constants.INDENT); - sb.append("pPassword: "); - sb.append(pPassword); - sb.append(Constants.NEWLINE); - sb.append(Constants.INDENT); sb.append("ulSaltLen: "); sb.append(pSalt.length); diff --git a/src/jdk.crypto.cryptoki/share/legal/pkcs11cryptotoken.md b/src/jdk.crypto.cryptoki/share/legal/pkcs11cryptotoken.md index 08d1e3c713d92..7877f54fe6e39 100644 --- a/src/jdk.crypto.cryptoki/share/legal/pkcs11cryptotoken.md +++ b/src/jdk.crypto.cryptoki/share/legal/pkcs11cryptotoken.md @@ -1,16 +1,16 @@ -## OASIS PKCS #11 Cryptographic Token Interface v3.0 +## OASIS PKCS #11 Cryptographic Token Interface v3.1 ### OASIS PKCS #11 Cryptographic Token Interface License

             
            -Copyright © OASIS Open 2020. All Rights Reserved.
            +Copyright © OASIS Open 2023. All Rights Reserved.
             
            -    All capitalized terms in the following text have the meanings
            +All capitalized terms in the following text have the meanings
             assigned to them in the OASIS Intellectual Property Rights Policy (the
             "OASIS IPR Policy"). The full Policy may be found at the OASIS website:
            -[http://www.oasis-open.org/policies-guidelines/ipr]
            +[https://www.oasis-open.org/policies-guidelines/ipr/].
             
            -    This document and translations of it may be copied and furnished to
            +This document and translations of it may be copied and furnished to
             others, and derivative works that comment on or otherwise explain it or
             assist in its implementation may be prepared, copied, published, and
             distributed, in whole or in part, without restriction of any kind,
            @@ -23,10 +23,10 @@ Committee (in which case the rules applicable to copyrights, as set
             forth in the OASIS IPR Policy, must be followed) or as required to
             translate it into languages other than English.
             
            -    The limited permissions granted above are perpetual and will not be
            +The limited permissions granted above are perpetual and will not be
             revoked by OASIS or its successors or assigns.
             
            -    This document and the information contained herein is provided on an
            +This document and the information contained herein is provided on an
             "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
             INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
             INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP RIGHTS OR ANY IMPLIED
            @@ -35,7 +35,11 @@ AND ITS MEMBERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
             CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THIS DOCUMENT OR ANY
             PART THEREOF.
             
            -    [OASIS requests that any OASIS Party or any other party that
            +As stated in the OASIS IPR Policy, the following three paragraphs in
            +brackets apply to OASIS Standards Final Deliverable documents (Committee
            +Specifications, OASIS Standards, or Approved Errata).
            +
            +[OASIS requests that any OASIS Party or any other party that
             believes it has patent claims that would necessarily be infringed by
             implementations of this OASIS Standards Final Deliverable, to notify
             OASIS TC Administrator and provide an indication of its willingness to
            @@ -43,7 +47,7 @@ grant patent licenses to such patent claims in a manner consistent with
             the IPR Mode of the OASIS Technical Committee that produced this
             deliverable.]
             
            -    [OASIS invites any party to contact the OASIS TC Administrator if it
            +[OASIS invites any party to contact the OASIS TC Administrator if it
             is aware of a claim of ownership of any patent claims that would
             necessarily be infringed by implementations of this OASIS Standards
             Final Deliverable by a patent holder that is not willing to provide a
            @@ -52,7 +56,7 @@ of the OASIS Technical Committee that produced this OASIS Standards
             Final Deliverable. OASIS may include such claims on its website, but
             disclaims any obligation to do so.]
             
            -    [OASIS takes no position regarding the validity or scope of any
            +[OASIS takes no position regarding the validity or scope of any
             intellectual property or other rights that might be claimed to pertain
             to the implementation or use of the technology described in this OASIS
             Standards Final Deliverable or the extent to which any license under
            diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11.h b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11.h
            index 5b050def5205f..5933da0e3b75c 100644
            --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11.h
            +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11.h
            @@ -1,8 +1,11 @@
            -/* Copyright (c) OASIS Open 2016-2019. All Rights Reserved.
            - * Distributed under the terms of the OASIS IPR Policy,
            - * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY
            - * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A
            - * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others.
            +/*
            + * PKCS #11 Specification Version 3.1
            + * OASIS Standard
            + * 23 July 2023
            + * Copyright (c) OASIS Open 2023. All Rights Reserved.
            + * Source: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/include/pkcs11-v3.1/
            + * Latest stage of narrative specification: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html
            + * TC IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php
              */
             
             #ifndef _PKCS11_H_
            @@ -47,7 +50,7 @@ extern "C" {
              *
              * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
              *
            - * If you're using windows, it might be defined by:
            + * If you're using Windows, it might be defined by:
              *
              * #define CK_PTR *
              *
            @@ -65,7 +68,7 @@ extern "C" {
              *   CK_VOID_PTR pReserved
              * );
              *
            - * If you're using Windows to declare a function in a Win32 cryptoki .dll,
            + * If you're using Windows to declare a function in a Win32 Cryptoki .dll,
              * it might be defined by:
              *
              * #define CK_DECLARE_FUNCTION(returnType, name) \
            @@ -241,4 +244,3 @@ struct CK_FUNCTION_LIST {
             
             #endif /* _PKCS11_H_ */
             
            -
            diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11f.h b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11f.h
            index 0553c1dc73ca2..80c43400d05f8 100644
            --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11f.h
            +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11f.h
            @@ -1,12 +1,11 @@
            -/* Copyright (c) OASIS Open 2016, 2019. All Rights Reserved./
            - * /Distributed under the terms of the OASIS IPR Policy,
            - * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY
            - * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A
            - * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others.
            - */
            -
            -/* Latest version of the specification:
            - * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
            +/*
            + * PKCS #11 Specification Version 3.1
            + * OASIS Standard
            + * 23 July 2023
            + * Copyright (c) OASIS Open 2023. All Rights Reserved.
            + * Source: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/include/pkcs11-v3.1/
            + * Latest stage of narrative specification: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html
            + * TC IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php
              */
             
             /* This header file contains pretty much everything about all the
            diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h
            index ab6ef326e8bd6..79d7cf7d7dae7 100644
            --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h
            +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h
            @@ -1,12 +1,11 @@
            -/* Copyright (c) OASIS Open 2016, 2019. All Rights Reserved./
            - * /Distributed under the terms of the OASIS IPR Policy,
            - * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY
            - * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A
            - * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others.
            - */
            -
            -/* Latest version of the specification:
            - * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
            +/*
            + * PKCS #11 Specification Version 3.1
            + * OASIS Standard
            + * 23 July 2023
            + * Copyright (c) OASIS Open 2023. All Rights Reserved.
            + * Source: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/include/pkcs11-v3.1/
            + * Latest stage of narrative specification: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html
            + * TC IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php
              */
             
             /* See top of pkcs11.h for information about the macros that
            @@ -18,7 +17,7 @@
             #define _PKCS11T_H_ 1
             
             #define CRYPTOKI_VERSION_MAJOR          3
            -#define CRYPTOKI_VERSION_MINOR          0
            +#define CRYPTOKI_VERSION_MINOR          1
             #define CRYPTOKI_VERSION_AMENDMENT      0
             
             #define CK_TRUE         1
            @@ -329,8 +328,11 @@ typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
             #define CKP_EXTENDED_PROVIDER         0x00000002UL
             #define CKP_AUTHENTICATION_TOKEN      0x00000003UL
             #define CKP_PUBLIC_CERTIFICATES_TOKEN 0x00000004UL
            +#define CKP_COMPLETE_PROVIDER         0x00000005UL
            +#define CKP_HKDF_TLS_TOKEN            0x00000006UL
             #define CKP_VENDOR_DEFINED            0x80000000UL
             
            +
             /* CK_HW_FEATURE_TYPE is a value that identifies the hardware feature type
              * of an object with CK_OBJECT_CLASS equal to CKO_HW_FEATURE.
              */
            @@ -409,9 +411,11 @@ typedef CK_ULONG          CK_KEY_TYPE;
             #define CKK_EC_EDWARDS          0x00000040UL
             #define CKK_EC_MONTGOMERY       0x00000041UL
             #define CKK_HKDF                0x00000042UL
            +
             #define CKK_SHA512_224_HMAC     0x00000043UL
             #define CKK_SHA512_256_HMAC     0x00000044UL
             #define CKK_SHA512_T_HMAC       0x00000045UL
            +#define CKK_HSS                 0x00000046UL
             
             #define CKK_VENDOR_DEFINED      0x80000000UL
             
            @@ -481,9 +485,9 @@ typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
             #define CKA_CERTIFICATE_CATEGORY        0x00000087UL
             #define CKA_JAVA_MIDP_SECURITY_DOMAIN   0x00000088UL
             #define CKA_URL                         0x00000089UL
            -#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY  0x0000008AUL
            -#define CKA_HASH_OF_ISSUER_PUBLIC_KEY   0x0000008BUL
            -#define CKA_NAME_HASH_ALGORITHM         0x0000008CUL
            +#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY  0x0000008aUL
            +#define CKA_HASH_OF_ISSUER_PUBLIC_KEY   0x0000008bUL
            +#define CKA_NAME_HASH_ALGORITHM         0x0000008cUL
             #define CKA_CHECK_VALUE                 0x00000090UL
             
             #define CKA_KEY_TYPE           0x00000100UL
            @@ -496,9 +500,9 @@ typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
             #define CKA_UNWRAP             0x00000107UL
             #define CKA_SIGN               0x00000108UL
             #define CKA_SIGN_RECOVER       0x00000109UL
            -#define CKA_VERIFY             0x0000010AUL
            -#define CKA_VERIFY_RECOVER     0x0000010BUL
            -#define CKA_DERIVE             0x0000010CUL
            +#define CKA_VERIFY             0x0000010aUL
            +#define CKA_VERIFY_RECOVER     0x0000010bUL
            +#define CKA_DERIVE             0x0000010cUL
             #define CKA_START_DATE         0x00000110UL
             #define CKA_END_DATE           0x00000111UL
             #define CKA_MODULUS            0x00000120UL
            @@ -555,12 +559,12 @@ typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
             #define CKA_OTP_TIME_REQUIREMENT      0x00000225UL
             #define CKA_OTP_COUNTER_REQUIREMENT   0x00000226UL
             #define CKA_OTP_PIN_REQUIREMENT       0x00000227UL
            -#define CKA_OTP_COUNTER               0x0000022EUL
            -#define CKA_OTP_TIME                  0x0000022FUL
            -#define CKA_OTP_USER_IDENTIFIER       0x0000022AUL
            -#define CKA_OTP_SERVICE_IDENTIFIER    0x0000022BUL
            -#define CKA_OTP_SERVICE_LOGO          0x0000022CUL
            -#define CKA_OTP_SERVICE_LOGO_TYPE     0x0000022DUL
            +#define CKA_OTP_COUNTER               0x0000022eUL
            +#define CKA_OTP_TIME                  0x0000022fUL
            +#define CKA_OTP_USER_IDENTIFIER       0x0000022aUL
            +#define CKA_OTP_SERVICE_IDENTIFIER    0x0000022bUL
            +#define CKA_OTP_SERVICE_LOGO          0x0000022cUL
            +#define CKA_OTP_SERVICE_LOGO_TYPE     0x0000022dUL
             
             #define CKA_GOSTR3410_PARAMS            0x00000250UL
             #define CKA_GOSTR3411_PARAMS            0x00000251UL
            @@ -586,6 +590,7 @@ typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
             #define CKA_SUPPORTED_CMS_ATTRIBUTES    0x00000503UL
             #define CKA_ALLOWED_MECHANISMS          (CKF_ARRAY_ATTRIBUTE|0x00000600UL)
             #define CKA_PROFILE_ID                  0x00000601UL
            +
             #define CKA_X2RATCHET_BAG               0x00000602UL
             #define CKA_X2RATCHET_BAGSIZE           0x00000603UL
             #define CKA_X2RATCHET_BOBS1STMSG        0x00000604UL
            @@ -603,6 +608,13 @@ typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
             #define CKA_X2RATCHET_NS                0x00000610UL
             #define CKA_X2RATCHET_PNS               0x00000611UL
             #define CKA_X2RATCHET_RK                0x00000612UL
            +/* HSS */
            +#define CKA_HSS_LEVELS                  0x00000617UL
            +#define CKA_HSS_LMS_TYPE                0x00000618UL
            +#define CKA_HSS_LMOTS_TYPE              0x00000619UL
            +#define CKA_HSS_LMS_TYPES               0x0000061aUL
            +#define CKA_HSS_LMOTS_TYPES             0x0000061bUL
            +#define CKA_HSS_KEYS_REMAINING          0x0000061cUL
             
             #define CKA_VENDOR_DEFINED              0x80000000UL
             
            @@ -644,11 +656,11 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
             #define CKM_RIPEMD160_RSA_PKCS         0x00000008UL
             #define CKM_RSA_PKCS_OAEP              0x00000009UL
             
            -#define CKM_RSA_X9_31_KEY_PAIR_GEN     0x0000000AUL
            -#define CKM_RSA_X9_31                  0x0000000BUL
            -#define CKM_SHA1_RSA_X9_31             0x0000000CUL
            -#define CKM_RSA_PKCS_PSS               0x0000000DUL
            -#define CKM_SHA1_RSA_PKCS_PSS          0x0000000EUL
            +#define CKM_RSA_X9_31_KEY_PAIR_GEN     0x0000000aUL
            +#define CKM_RSA_X9_31                  0x0000000bUL
            +#define CKM_SHA1_RSA_X9_31             0x0000000cUL
            +#define CKM_RSA_PKCS_PSS               0x0000000dUL
            +#define CKM_SHA1_RSA_PKCS_PSS          0x0000000eUL
             
             #define CKM_DSA_KEY_PAIR_GEN           0x00000010UL
             #define CKM_DSA                        0x00000011UL
            @@ -659,8 +671,8 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
             #define CKM_DSA_SHA512                 0x00000016UL
             #define CKM_DSA_SHA3_224               0x00000018UL
             #define CKM_DSA_SHA3_256               0x00000019UL
            -#define CKM_DSA_SHA3_384               0x0000001AUL
            -#define CKM_DSA_SHA3_512               0x0000001BUL
            +#define CKM_DSA_SHA3_384               0x0000001aUL
            +#define CKM_DSA_SHA3_512               0x0000001bUL
             
             #define CKM_DH_PKCS_KEY_PAIR_GEN       0x00000020UL
             #define CKM_DH_PKCS_DERIVE             0x00000021UL
            @@ -682,12 +694,12 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
             
             #define CKM_SHA512_224                 0x00000048UL
             #define CKM_SHA512_224_HMAC            0x00000049UL
            -#define CKM_SHA512_224_HMAC_GENERAL    0x0000004AUL
            -#define CKM_SHA512_224_KEY_DERIVATION  0x0000004BUL
            -#define CKM_SHA512_256                 0x0000004CUL
            -#define CKM_SHA512_256_HMAC            0x0000004DUL
            -#define CKM_SHA512_256_HMAC_GENERAL    0x0000004EUL
            -#define CKM_SHA512_256_KEY_DERIVATION  0x0000004FUL
            +#define CKM_SHA512_224_HMAC_GENERAL    0x0000004aUL
            +#define CKM_SHA512_224_KEY_DERIVATION  0x0000004bUL
            +#define CKM_SHA512_256                 0x0000004cUL
            +#define CKM_SHA512_256_HMAC            0x0000004dUL
            +#define CKM_SHA512_256_HMAC_GENERAL    0x0000004eUL
            +#define CKM_SHA512_256_KEY_DERIVATION  0x0000004fUL
             
             #define CKM_SHA512_T                   0x00000050UL
             #define CKM_SHA512_T_HMAC              0x00000051UL
            @@ -781,25 +793,25 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
             #define CKM_SECURID                    0x00000282UL
             #define CKM_HOTP_KEY_GEN               0x00000290UL
             #define CKM_HOTP                       0x00000291UL
            -#define CKM_ACTI                       0x000002A0UL
            -#define CKM_ACTI_KEY_GEN               0x000002A1UL
            -
            -#define CKM_SHA3_256                   0x000002B0UL
            -#define CKM_SHA3_256_HMAC              0x000002B1UL
            -#define CKM_SHA3_256_HMAC_GENERAL      0x000002B2UL
            -#define CKM_SHA3_256_KEY_GEN           0x000002B3UL
            -#define CKM_SHA3_224                   0x000002B5UL
            -#define CKM_SHA3_224_HMAC              0x000002B6UL
            -#define CKM_SHA3_224_HMAC_GENERAL      0x000002B7UL
            -#define CKM_SHA3_224_KEY_GEN           0x000002B8UL
            -#define CKM_SHA3_384                   0x000002C0UL
            -#define CKM_SHA3_384_HMAC              0x000002C1UL
            -#define CKM_SHA3_384_HMAC_GENERAL      0x000002C2UL
            -#define CKM_SHA3_384_KEY_GEN           0x000002C3UL
            -#define CKM_SHA3_512                   0x000002D0UL
            -#define CKM_SHA3_512_HMAC              0x000002D1UL
            -#define CKM_SHA3_512_HMAC_GENERAL      0x000002D2UL
            -#define CKM_SHA3_512_KEY_GEN           0x000002D3UL
            +#define CKM_ACTI                       0x000002a0UL
            +#define CKM_ACTI_KEY_GEN               0x000002a1UL
            +
            +#define CKM_SHA3_256                   0x000002b0UL
            +#define CKM_SHA3_256_HMAC              0x000002b1UL
            +#define CKM_SHA3_256_HMAC_GENERAL      0x000002b2UL
            +#define CKM_SHA3_256_KEY_GEN           0x000002b3UL
            +#define CKM_SHA3_224                   0x000002b5UL
            +#define CKM_SHA3_224_HMAC              0x000002b6UL
            +#define CKM_SHA3_224_HMAC_GENERAL      0x000002b7UL
            +#define CKM_SHA3_224_KEY_GEN           0x000002b8UL
            +#define CKM_SHA3_384                   0x000002c0UL
            +#define CKM_SHA3_384_HMAC              0x000002c1UL
            +#define CKM_SHA3_384_HMAC_GENERAL      0x000002c2UL
            +#define CKM_SHA3_384_KEY_GEN           0x000002c3UL
            +#define CKM_SHA3_512                   0x000002d0UL
            +#define CKM_SHA3_512_HMAC              0x000002d1UL
            +#define CKM_SHA3_512_HMAC_GENERAL      0x000002d2UL
            +#define CKM_SHA3_512_KEY_GEN           0x000002d3UL
             
             
             #define CKM_CAST_KEY_GEN               0x00000300UL
            @@ -870,9 +882,9 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
             #define CKM_SHA3_256_KEY_DERIVATION    0x00000397UL
             #define CKM_SHA3_224_KEY_DERIVATION    0x00000398UL
             #define CKM_SHA3_384_KEY_DERIVATION    0x00000399UL
            -#define CKM_SHA3_512_KEY_DERIVATION    0x0000039AUL
            -#define CKM_SHAKE_128_KEY_DERIVATION   0x0000039BUL
            -#define CKM_SHAKE_256_KEY_DERIVATION   0x0000039CUL
            +#define CKM_SHA3_512_KEY_DERIVATION    0x0000039aUL
            +#define CKM_SHAKE_128_KEY_DERIVATION   0x0000039bUL
            +#define CKM_SHAKE_256_KEY_DERIVATION   0x0000039cUL
             #define CKM_SHA3_256_KEY_DERIVE  CKM_SHA3_256_KEY_DERIVATION
             #define CKM_SHA3_224_KEY_DERIVE  CKM_SHA3_224_KEY_DERIVATION
             #define CKM_SHA3_384_KEY_DERIVE  CKM_SHA3_384_KEY_DERIVATION
            @@ -880,40 +892,42 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
             #define CKM_SHAKE_128_KEY_DERIVE CKM_SHAKE_128_KEY_DERIVATION
             #define CKM_SHAKE_256_KEY_DERIVE CKM_SHAKE_256_KEY_DERIVATION
             
            -#define CKM_PBE_MD2_DES_CBC            0x000003A0UL
            -#define CKM_PBE_MD5_DES_CBC            0x000003A1UL
            -#define CKM_PBE_MD5_CAST_CBC           0x000003A2UL
            -#define CKM_PBE_MD5_CAST3_CBC          0x000003A3UL
            -#define CKM_PBE_MD5_CAST5_CBC          0x000003A4UL /* Deprecated */
            -#define CKM_PBE_MD5_CAST128_CBC        0x000003A4UL
            -#define CKM_PBE_SHA1_CAST5_CBC         0x000003A5UL /* Deprecated */
            -#define CKM_PBE_SHA1_CAST128_CBC       0x000003A5UL
            -#define CKM_PBE_SHA1_RC4_128           0x000003A6UL
            -#define CKM_PBE_SHA1_RC4_40            0x000003A7UL
            -#define CKM_PBE_SHA1_DES3_EDE_CBC      0x000003A8UL
            -#define CKM_PBE_SHA1_DES2_EDE_CBC      0x000003A9UL
            -#define CKM_PBE_SHA1_RC2_128_CBC       0x000003AAUL
            -#define CKM_PBE_SHA1_RC2_40_CBC        0x000003ABUL
            -
            -#define CKM_PKCS5_PBKD2                0x000003B0UL
            -
            -#define CKM_PBA_SHA1_WITH_SHA1_HMAC    0x000003C0UL
            -
            -#define CKM_WTLS_PRE_MASTER_KEY_GEN         0x000003D0UL
            -#define CKM_WTLS_MASTER_KEY_DERIVE          0x000003D1UL
            -#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC   0x000003D2UL
            -#define CKM_WTLS_PRF                        0x000003D3UL
            -#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE  0x000003D4UL
            -#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE  0x000003D5UL
            -
            -#define CKM_TLS12_MAC                       0x000003D8UL
            -#define CKM_TLS12_KDF                       0x000003D9UL
            -#define CKM_TLS12_MASTER_KEY_DERIVE         0x000003E0UL
            -#define CKM_TLS12_KEY_AND_MAC_DERIVE        0x000003E1UL
            -#define CKM_TLS12_MASTER_KEY_DERIVE_DH      0x000003E2UL
            -#define CKM_TLS12_KEY_SAFE_DERIVE           0x000003E3UL
            -#define CKM_TLS_MAC                         0x000003E4UL
            -#define CKM_TLS_KDF                         0x000003E5UL
            +#define CKM_PBE_MD2_DES_CBC            0x000003a0UL
            +#define CKM_PBE_MD5_DES_CBC            0x000003a1UL
            +#define CKM_PBE_MD5_CAST_CBC           0x000003a2UL
            +#define CKM_PBE_MD5_CAST3_CBC          0x000003a3UL
            +#define CKM_PBE_MD5_CAST5_CBC          0x000003a4UL /* Deprecated */
            +#define CKM_PBE_MD5_CAST128_CBC        0x000003a4UL
            +#define CKM_PBE_SHA1_CAST5_CBC         0x000003a5UL /* Deprecated */
            +#define CKM_PBE_SHA1_CAST128_CBC       0x000003a5UL
            +#define CKM_PBE_SHA1_RC4_128           0x000003a6UL
            +#define CKM_PBE_SHA1_RC4_40            0x000003a7UL
            +#define CKM_PBE_SHA1_DES3_EDE_CBC      0x000003a8UL
            +#define CKM_PBE_SHA1_DES2_EDE_CBC      0x000003a9UL
            +#define CKM_PBE_SHA1_RC2_128_CBC       0x000003aaUL
            +#define CKM_PBE_SHA1_RC2_40_CBC        0x000003abUL
            +
            +#define CKM_PKCS5_PBKD2                0x000003b0UL
            +
            +#define CKM_PBA_SHA1_WITH_SHA1_HMAC    0x000003c0UL
            +
            +#define CKM_WTLS_PRE_MASTER_KEY_GEN         0x000003d0UL
            +#define CKM_WTLS_MASTER_KEY_DERIVE          0x000003d1UL
            +#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC   0x000003d2UL
            +#define CKM_WTLS_PRF                        0x000003d3UL
            +#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE  0x000003d4UL
            +#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE  0x000003d5UL
            +
            +#define CKM_TLS10_MAC_SERVER                0x000003d6UL
            +#define CKM_TLS10_MAC_CLIENT                0x000003d7UL
            +#define CKM_TLS12_MAC                       0x000003d8UL
            +#define CKM_TLS12_KDF                       0x000003d9UL
            +#define CKM_TLS12_MASTER_KEY_DERIVE         0x000003e0UL
            +#define CKM_TLS12_KEY_AND_MAC_DERIVE        0x000003e1UL
            +#define CKM_TLS12_MASTER_KEY_DERIVE_DH      0x000003e2UL
            +#define CKM_TLS12_KEY_SAFE_DERIVE           0x000003e3UL
            +#define CKM_TLS_MAC                         0x000003e4UL
            +#define CKM_TLS_KDF                         0x000003e5UL
             
             #define CKM_KEY_WRAP_LYNKS             0x00000400UL
             #define CKM_KEY_WRAP_SET_OAEP          0x00000401UL
            @@ -983,7 +997,7 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
             #define CKM_ECDSA_SHA256               0x00001044UL
             #define CKM_ECDSA_SHA384               0x00001045UL
             #define CKM_ECDSA_SHA512               0x00001046UL
            -#define CKM_EC_KEY_PAIR_GEN_W_EXTRA_BITS 0x0000140BUL
            +#define CKM_EC_KEY_PAIR_GEN_W_EXTRA_BITS 0x0000140bUL
             
             #define CKM_ECDH1_DERIVE               0x00001050UL
             #define CKM_ECDH1_COFACTOR_DERIVE      0x00001051UL
            @@ -1012,12 +1026,12 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
             #define CKM_AES_GCM                    0x00001087UL
             #define CKM_AES_CCM                    0x00001088UL
             #define CKM_AES_CTS                    0x00001089UL
            -#define CKM_AES_CMAC                   0x0000108AUL
            -#define CKM_AES_CMAC_GENERAL           0x0000108BUL
            +#define CKM_AES_CMAC                   0x0000108aUL
            +#define CKM_AES_CMAC_GENERAL           0x0000108bUL
             
            -#define CKM_AES_XCBC_MAC               0x0000108CUL
            -#define CKM_AES_XCBC_MAC_96            0x0000108DUL
            -#define CKM_AES_GMAC                   0x0000108EUL
            +#define CKM_AES_XCBC_MAC               0x0000108cUL
            +#define CKM_AES_XCBC_MAC_96            0x0000108dUL
            +#define CKM_AES_GMAC                   0x0000108eUL
             
             #define CKM_BLOWFISH_KEY_GEN           0x00001090UL
             #define CKM_BLOWFISH_CBC               0x00001091UL
            @@ -1066,6 +1080,7 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
             #define CKM_AES_KEY_WRAP               0x00002109UL     /* WAS: 0x00001090 */
             #define CKM_AES_KEY_WRAP_PAD           0x0000210AUL     /* WAS: 0x00001091 */
             #define CKM_AES_KEY_WRAP_KWP           0x0000210BUL
            +#define CKM_AES_KEY_WRAP_PKCS7         0x0000210CUL
             
             #define CKM_RSA_PKCS_TPM_1_1           0x00004001UL
             #define CKM_RSA_PKCS_OAEP_TPM_1_1      0x00004002UL
            @@ -1125,6 +1140,14 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
             #define CKM_SP800_108_FEEDBACK_KDF     0x000003adUL
             #define CKM_SP800_108_DOUBLE_PIPELINE_KDF 0x000003aeUL
             
            +#define CKM_IKE2_PRF_PLUS_DERIVE       0x0000402eUL
            +#define CKM_IKE_PRF_DERIVE             0x0000402fUL
            +#define CKM_IKE1_PRF_DERIVE            0x00004030UL
            +#define CKM_IKE1_EXTENDED_DERIVE       0x00004031UL
            +#define CKM_HSS_KEY_PAIR_GEN           0x00004032UL
            +#define CKM_HSS                        0x00004033UL
            +
            +
             #define CKM_VENDOR_DEFINED             0x80000000UL
             
             typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
            @@ -1320,6 +1343,7 @@ typedef CK_ULONG          CK_RV;
             #define CKR_FUNCTION_REJECTED                 0x00000200UL
             #define CKR_TOKEN_RESOURCE_EXCEEDED           0x00000201UL
             #define CKR_OPERATION_CANCEL_FAILED           0x00000202UL
            +#define CKR_KEY_EXHAUSTED                     0x00000203UL
             
             #define CKR_VENDOR_DEFINED                    0x80000000UL
             
            @@ -1436,6 +1460,7 @@ typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
             #define CKG_MGF1_SHA3_384     0x00000008UL
             #define CKG_MGF1_SHA3_512     0x00000009UL
             
            +
             /* CK_RSA_PKCS_OAEP_SOURCE_TYPE  is used to indicate the source
              * of the encoding parameter when formatting a message block
              * for the PKCS #1 OAEP encryption scheme.
            @@ -1701,8 +1726,7 @@ typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
                 CK_ULONG    length;
             } CK_DES_CBC_ENCRYPT_DATA_PARAMS;
             
            -typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
            -        CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
            +typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
             
             typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
                 CK_BYTE     iv[16];
            @@ -1710,8 +1734,7 @@ typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
                 CK_ULONG    length;
             } CK_AES_CBC_ENCRYPT_DATA_PARAMS;
             
            -typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
            -        CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
            +typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
             
             /* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
              * CKM_SKIPJACK_PRIVATE_WRAP mechanism
            @@ -2051,6 +2074,7 @@ typedef CK_ULONG CK_GENERATOR_FUNCTION;
             #define CKG_GENERATE         0x00000001UL
             #define CKG_GENERATE_COUNTER 0x00000002UL
             #define CKG_GENERATE_RANDOM  0x00000003UL
            +#define CKG_GENERATE_COUNTER_XOR 0x00000004UL
             
             typedef struct CK_GCM_MESSAGE_PARAMS {
                 CK_BYTE_PTR           pIv;
            @@ -2061,7 +2085,7 @@ typedef struct CK_GCM_MESSAGE_PARAMS {
                 CK_ULONG              ulTagBits;
             } CK_GCM_MESSAGE_PARAMS;
             
            -typedef CK_GCM_MESSAGE_PARAMS CK_GCM_MESSAGE_PARAMS_PTR;
            +typedef CK_GCM_MESSAGE_PARAMS CK_PTR CK_GCM_MESSAGE_PARAMS_PTR;
             
             typedef struct CK_CCM_PARAMS {
                 CK_ULONG    ulDataLen;
            @@ -2084,7 +2108,7 @@ typedef struct CK_CCM_MESSAGE_PARAMS {
                 CK_ULONG              ulMACLen;
             } CK_CCM_MESSAGE_PARAMS;
             
            -typedef CK_CCM_MESSAGE_PARAMS CK_CCM_MESSAGE_PARAMS_PTR;
            +typedef CK_CCM_MESSAGE_PARAMS CK_PTR CK_CCM_MESSAGE_PARAMS_PTR;
             
             /* Deprecated. Use CK_GCM_PARAMS */
             typedef struct CK_AES_GCM_PARAMS {
            @@ -2339,7 +2363,6 @@ typedef struct CK_SALSA20_PARAMS {
                 CK_BYTE_PTR pNonce;
                 CK_ULONG    ulNonceBits;
             } CK_SALSA20_PARAMS;
            -
             typedef CK_SALSA20_PARAMS CK_PTR CK_SALSA20_PARAMS_PTR;
             
             typedef struct CK_SALSA20_CHACHA20_POLY1305_PARAMS {
            @@ -2423,6 +2446,7 @@ typedef struct CK_XEDDSA_PARAMS {
             } CK_XEDDSA_PARAMS;
             typedef CK_XEDDSA_PARAMS CK_PTR CK_XEDDSA_PARAMS_PTR;
             
            +/* HKDF params */
             typedef struct CK_HKDF_PARAMS {
                 CK_BBOOL          bExtract;
                 CK_BBOOL          bExpand;
            @@ -2440,5 +2464,60 @@ typedef CK_HKDF_PARAMS CK_PTR CK_HKDF_PARAMS_PTR;
             #define CKF_HKDF_SALT_DATA   0x00000002UL
             #define CKF_HKDF_SALT_KEY    0x00000004UL
             
            +/* HSS */
            +typedef CK_ULONG                   CK_HSS_LEVELS;
            +typedef CK_ULONG                   CK_LMS_TYPE;
            +typedef CK_ULONG                   CK_LMOTS_TYPE;
            +
            +typedef struct specifiedParams {
            +    CK_HSS_LEVELS levels;
            +    CK_LMS_TYPE   lm_type[8];
            +    CK_LMOTS_TYPE lm_ots_type[8];
            +} specifiedParams;
            +
            +/* IKE Params */
            +typedef struct CK_IKE2_PRF_PLUS_DERIVE_PARAMS {
            +    CK_MECHANISM_TYPE prfMechanism;
            +    CK_BBOOL          bHasSeedKey;
            +    CK_OBJECT_HANDLE  hSeedKey;
            +    CK_BYTE_PTR       pSeedData;
            +    CK_ULONG          ulSeedDataLen;
            +} CK_IKE2_PRF_PLUS_DERIVE_PARAMS;
            +typedef CK_IKE2_PRF_PLUS_DERIVE_PARAMS CK_PTR CK_IKE2_PRF_PLUS_DERIVE_PARAMS_PTR;
            +
            +typedef struct CK_IKE_PRF_DERIVE_PARAMS {
            +    CK_MECHANISM_TYPE prfMechanism;
            +    CK_BBOOL          bDataAsKey;
            +    CK_BBOOL          bRekey;
            +    CK_BYTE_PTR       pNi;
            +    CK_ULONG          ulNiLen;
            +    CK_BYTE_PTR       pNr;
            +    CK_ULONG          ulNrLen;
            +    CK_OBJECT_HANDLE  hNewKey;
            +} CK_IKE_PRF_DERIVE_PARAMS;
            +typedef CK_IKE_PRF_DERIVE_PARAMS CK_PTR CK_IKE_PRF_DERIVE_PARAMS_PTR;
            +
            +typedef struct CK_IKE1_PRF_DERIVE_PARAMS {
            +    CK_MECHANISM_TYPE prfMechanism;
            +    CK_BBOOL          bHasPrevKey;
            +    CK_OBJECT_HANDLE  hKeygxy;
            +    CK_OBJECT_HANDLE  hPrevKey;
            +    CK_BYTE_PTR       pCKYi;
            +    CK_ULONG          ulCKYiLen;
            +    CK_BYTE_PTR       pCKYr;
            +    CK_ULONG          ulCKYrLen;
            +    CK_BYTE           keyNumber;
            +} CK_IKE1_PRF_DERIVE_PARAMS;
            +typedef CK_IKE1_PRF_DERIVE_PARAMS CK_PTR CK_IKE1_PRF_DERIVE_PARAMS_PTR;
            +
            +typedef struct CK_IKE1_EXTENDED_DERIVE_PARAMS {
            +    CK_MECHANISM_TYPE prfMechanism;
            +    CK_BBOOL          bHasKeygxy;
            +    CK_OBJECT_HANDLE  hKeygxy;
            +    CK_BYTE_PTR       pExtraData;
            +    CK_ULONG          ulExtraDataLen;
            +} CK_IKE1_EXTENDED_DERIVE_PARAMS;
            +typedef CK_IKE1_EXTENDED_DERIVE_PARAMS CK_PTR CK_IKE1_EXTENDED_DERIVE_PARAMS_PTR;
            +
             #endif /* _PKCS11T_H_ */
             
            diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java
            index 174e63bff26ca..ff59ddf8268d5 100644
            --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java
            +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java
            @@ -1,5 +1,5 @@
             /*
            - * Copyright (c) 2010, 2013, 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
            @@ -431,10 +431,10 @@ public MethodHandle compose(final MethodHandle fallback) {
                  * Composes the invocation, guard, switch points, and the exception into a
                  * composite method handle that knows how to fall back when the guard fails
                  * or the invocation is invalidated.
            -     * @param switchpointFallback the fallback method handle in case a switch
            -     * point is invalidated.
                  * @param guardFallback the fallback method handle in case guard returns
                  * false.
            +     * @param switchpointFallback the fallback method handle in case a switch
            +     * point is invalidated.
                  * @param catchFallback the fallback method in case the exception handler
                  * triggers.
                  * @return a composite method handle.
            diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp
            index 962b1ae51722b..0ad95d0eac7cf 100644
            --- a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp
            +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp
            @@ -420,7 +420,6 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo
               jboolean isCopy;
               jlongArray array;
               jlong *regs;
            -  int i;
             
               struct ps_prochandle* ph = get_proc_handle(env, this_obj);
               if (get_lwp_regs(ph, lwp_id, &gregs) != true) {
            diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c
            index d3b4d3d1af927..4cb791111bcf6 100644
            --- a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c
            +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c
            @@ -356,7 +356,6 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t
             
                 if (shdr->sh_type == sym_section) {
                   ELF_SYM  *syms;
            -      int rslt;
                   size_t size, n, j, htab_sz;
             
                   // FIXME: there could be multiple data buffers associated with the
            @@ -390,8 +389,9 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t
                     goto bad;
                   }
             
            -      rslt = hcreate_r(htab_sz, symtab->hash_table);
            -      // guarantee(rslt, "unexpected failure: hcreate_r");
            +      if (hcreate_r(htab_sz, symtab->hash_table) == 0) {
            +        goto bad;
            +      }
             
                   // shdr->sh_link points to the section that contains the actual strings
                   // for symbol names. the st_name field in ELF_SYM is just the
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
            index 870621421c85b..d8c4d1a781e8f 100644
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
            +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
            @@ -39,7 +39,6 @@
             import sun.jvm.hotspot.gc.shared.*;
             import sun.jvm.hotspot.gc.shenandoah.*;
             import sun.jvm.hotspot.gc.g1.*;
            -import sun.jvm.hotspot.gc.x.*;
             import sun.jvm.hotspot.gc.z.*;
             import sun.jvm.hotspot.interpreter.*;
             import sun.jvm.hotspot.oops.*;
            @@ -1124,10 +1123,6 @@ public void addAnnotation(Address addr, OopHandle handle) {
                                       ShenandoahHeap heap = (ShenandoahHeap) collHeap;
                                       anno = "ShenandoahHeap ";
                                       bad = false;
            -                        } else if (collHeap instanceof XCollectedHeap) {
            -                          XCollectedHeap heap = (XCollectedHeap) collHeap;
            -                          anno = "ZHeap ";
            -                          bad = false;
                                     } else if (collHeap instanceof ZCollectedHeap) {
                                       ZCollectedHeap heap = (ZCollectedHeap) collHeap;
                                       anno = "ZHeap ";
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XAddress.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XAddress.java
            deleted file mode 100644
            index fbd151108906e..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XAddress.java
            +++ /dev/null
            @@ -1,77 +0,0 @@
            -/*
            - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -
            -class XAddress {
            -    static long as_long(Address value) {
            -        if (value == null) {
            -            return 0;
            -        }
            -        return value.asLongValue();
            -    };
            -
            -    static boolean is_null(Address value) {
            -        return value == null;
            -    }
            -
            -    static boolean is_weak_bad(Address value) {
            -        return (as_long(value) & XGlobals.XAddressWeakBadMask()) != 0L;
            -    }
            -
            -    static boolean is_weak_good(Address value) {
            -        return !is_weak_bad(value) && !is_null(value);
            -    }
            -
            -    static boolean is_weak_good_or_null(Address value) {
            -        return !is_weak_bad(value);
            -    }
            -
            -    static long offset(Address address) {
            -        return as_long(address) & XGlobals.XAddressOffsetMask();
            -    }
            -
            -    static Address good(Address value) {
            -        return VM.getVM().getDebugger().newAddress(offset(value) | XGlobals.XAddressGoodMask());
            -    }
            -
            -    static Address good_or_null(Address value) {
            -        return is_null(value) ? value : good(value);
            -    }
            -
            -    private static boolean isPowerOf2(long value) {
            -        return (value != 0L) && ((value & (value - 1)) == 0L);
            -    }
            -
            -    static boolean isIn(Address addr) {
            -        long value = as_long(addr);
            -        if (!isPowerOf2(value & ~XGlobals.XAddressOffsetMask())) {
            -            return false;
            -        }
            -        return (value & (XGlobals.XAddressMetadataMask() & ~XGlobals.XAddressMetadataFinalizable())) != 0L;
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XAttachedArrayForForwarding.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XAttachedArrayForForwarding.java
            deleted file mode 100644
            index 0c8bb38a7767e..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XAttachedArrayForForwarding.java
            +++ /dev/null
            @@ -1,71 +0,0 @@
            -/*
            - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
            - * Copyright (c) 2021, NTT DATA.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.runtime.VMObjectFactory;
            -import sun.jvm.hotspot.types.CIntegerField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XAttachedArrayForForwarding extends VMObject {
            -    private static CIntegerField lengthField;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XAttachedArrayForForwarding");
            -
            -        lengthField = type.getCIntegerField("_length");
            -    }
            -
            -    public XAttachedArrayForForwarding(Address addr) {
            -        super(addr);
            -    }
            -
            -    public long length() {
            -        return lengthField.getValue(addr);
            -    }
            -
            -    // ObjectT: XForwarding
            -    //  ArrayT: XForwardingEntry
            -    //
            -    // template 
            -    // inline size_t XAttachedArray::object_size()
            -    private long objectSize() {
            -        return XUtils.alignUp(XForwarding.getSize(), XForwardingEntry.getSize());
            -    }
            -
            -    // ArrayT* operator()(const ObjectT* obj) const
            -    public XForwardingEntry get(XForwarding obj) {
            -        Address o = obj.getAddress().addOffsetTo(objectSize());
            -        return VMObjectFactory.newObject(XForwardingEntry.class, o);
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XBarrier.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XBarrier.java
            deleted file mode 100644
            index 54f9323a4e67c..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XBarrier.java
            +++ /dev/null
            @@ -1,71 +0,0 @@
            -/*
            - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -
            -class XBarrier {
            -    private static boolean is_weak_good_or_null_fast_path(Address addr) {
            -        return XAddress.is_weak_good_or_null(addr);
            -    }
            -
            -    private static Address weak_load_barrier_on_oop_slow_path(Address addr) {
            -        return XAddress.is_weak_good(addr) ? XAddress.good(addr) : relocate_or_remap(addr);
            -    }
            -
            -    private static boolean during_relocate() {
            -        return XGlobals.XGlobalPhase() == XGlobals.XPhaseRelocate;
            -    }
            -
            -    private static Address relocate(Address addr) {
            -        return zheap().relocate_object(addr);
            -    }
            -
            -    private static XHeap zheap() {
            -        XCollectedHeap zCollectedHeap = (XCollectedHeap)VM.getVM().getUniverse().heap();
            -        return zCollectedHeap.heap();
            -    }
            -
            -    private static Address remap(Address addr) {
            -        return zheap().remapObject(addr);
            -    }
            -
            -    private static Address relocate_or_remap(Address addr) {
            -        return during_relocate() ? relocate(addr) : remap(addr);
            -    }
            -
            -    static Address weak_barrier(Address o) {
            -        // Fast path
            -        if (is_weak_good_or_null_fast_path(o)) {
            -            // Return the good address instead of the weak good address
            -            // to ensure that the currently active heap view is used.
            -            return XAddress.good_or_null(o);
            -        }
            -
            -        // Slow path
            -        return weak_load_barrier_on_oop_slow_path(o);
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XCollectedHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XCollectedHeap.java
            deleted file mode 100644
            index 5455a841fabfa..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XCollectedHeap.java
            +++ /dev/null
            @@ -1,139 +0,0 @@
            -/*
            - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import java.io.PrintStream;
            -import java.util.Iterator;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.debugger.OopHandle;
            -import sun.jvm.hotspot.gc.shared.CollectedHeap;
            -import sun.jvm.hotspot.gc.shared.CollectedHeapName;
            -import sun.jvm.hotspot.gc.shared.LiveRegionsClosure;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObjectFactory;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -import sun.jvm.hotspot.utilities.BitMapInterface;
            -
            -// Mirror class for XCollectedHeap.
            -
            -public class XCollectedHeap extends CollectedHeap {
            -    private static long zHeapFieldOffset;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XCollectedHeap");
            -
            -        zHeapFieldOffset = type.getAddressField("_heap").getOffset();
            -    }
            -
            -    public XHeap heap() {
            -        Address heapAddr = addr.addOffsetTo(zHeapFieldOffset);
            -        return VMObjectFactory.newObject(XHeap.class, heapAddr);
            -    }
            -
            -    @Override
            -    public CollectedHeapName kind() {
            -        return CollectedHeapName.Z;
            -    }
            -
            -    @Override
            -    public void printOn(PrintStream tty) {
            -        heap().printOn(tty);
            -    }
            -
            -    public XCollectedHeap(Address addr) {
            -        super(addr);
            -    }
            -
            -    @Override
            -    public long capacity() {
            -        return heap().capacity();
            -    }
            -
            -    @Override
            -    public long used() {
            -        return heap().used();
            -    }
            -
            -    @Override
            -    public boolean isInReserved(Address a) {
            -        return heap().isIn(a);
            -    }
            -
            -    private OopHandle oop_load_barrier(Address oopAddress) {
            -        oopAddress = XBarrier.weak_barrier(oopAddress);
            -        if (oopAddress == null) {
            -            return null;
            -        }
            -
            -        return oopAddress.addOffsetToAsOopHandle(0);
            -    }
            -
            -    @Override
            -    public OopHandle oop_load_at(OopHandle handle, long offset) {
            -        assert(!VM.getVM().isCompressedOopsEnabled());
            -
            -        Address oopAddress = handle.getAddressAt(offset);
            -
            -        return oop_load_barrier(oopAddress);
            -    }
            -
            -    // addr can be either in heap or in native
            -    @Override
            -    public OopHandle oop_load_in_native(Address addr) {
            -        Address oopAddress = addr.getAddressAt(0);
            -        return oop_load_barrier(oopAddress);
            -    }
            -
            -    public String oopAddressDescription(OopHandle handle) {
            -        Address origOop = XOop.to_address(handle);
            -        Address loadBarrieredOop = XBarrier.weak_barrier(origOop);
            -        if (!origOop.equals(loadBarrieredOop)) {
            -            return origOop + " (" + loadBarrieredOop.toString() + ")";
            -        } else {
            -            return handle.toString();
            -        }
            -    }
            -
            -    @Override
            -    public void liveRegionsIterate(LiveRegionsClosure closure) {
            -        Iterator iter = heap().pageTable().activePagesIterator();
            -        while (iter.hasNext()) {
            -            XPage page = iter.next();
            -            closure.doLiveRegions(page);
            -        }
            -    }
            -
            -    @Override
            -    public BitMapInterface createBitMap(long size) {
            -        // Ignores the size
            -        return new XExternalBitMap(this);
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XExternalBitMap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XExternalBitMap.java
            deleted file mode 100644
            index 5a2f033e6a1d5..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XExternalBitMap.java
            +++ /dev/null
            @@ -1,111 +0,0 @@
            -/*
            - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import java.util.HashMap;
            -
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.utilities.BitMap;
            -import sun.jvm.hotspot.utilities.BitMapInterface;
            -
            -/** Discontiguous bitmap for ZGC. */
            -public class XExternalBitMap implements BitMapInterface {
            -    private XPageTable pageTable;
            -    private final long oopSize;
            -
            -    private HashMap pageToBitMap = new HashMap();
            -
            -    public XExternalBitMap(XCollectedHeap collectedHeap) {
            -        pageTable = collectedHeap.heap().pageTable();
            -        oopSize = VM.getVM().getOopSize();
            -    }
            -
            -    private XPage getPage(long zOffset) {
            -        if (zOffset > XGlobals.XAddressOffsetMask()) {
            -            throw new RuntimeException("Not a Z offset: " + zOffset);
            -        }
            -
            -        XPage page = pageTable.get(XUtils.longToAddress(zOffset));
            -        if (page == null) {
            -            throw new RuntimeException("Address not in pageTable: " + zOffset);
            -        }
            -        return page;
            -    }
            -
            -    private BitMap getOrAddBitMap(XPage page) {
            -        BitMap bitMap = pageToBitMap.get(page);
            -        if (bitMap == null) {
            -            long size = page.size();
            -
            -            long maxNumObjects = size >>> page.object_alignment_shift();
            -            if (maxNumObjects > Integer.MAX_VALUE) {
            -                throw new RuntimeException("int overflow");
            -            }
            -            int intMaxNumObjects = (int)maxNumObjects;
            -
            -            bitMap = new BitMap(intMaxNumObjects);
            -            pageToBitMap.put(page,  bitMap);
            -        }
            -
            -        return bitMap;
            -    }
            -
            -    private int pageLocalBitMapIndex(XPage page, long zOffset) {
            -        long pageLocalZOffset = zOffset - page.start();
            -        return (int)(pageLocalZOffset >>> page.object_alignment_shift());
            -    }
            -
            -    private long convertToZOffset(long offset) {
            -        long addr = oopSize * offset;
            -        return addr & XGlobals.XAddressOffsetMask();
            -    }
            -
            -    @Override
            -    public boolean at(long offset) {
            -        long zOffset = convertToZOffset(offset);
            -        XPage page = getPage(zOffset);
            -        BitMap bitMap = getOrAddBitMap(page);
            -        int index = pageLocalBitMapIndex(page, zOffset);
            -
            -        return bitMap.at(index);
            -    }
            -
            -    @Override
            -    public void atPut(long offset, boolean value) {
            -        long zOffset = convertToZOffset(offset);
            -        XPage page = getPage(zOffset);
            -        BitMap bitMap = getOrAddBitMap(page);
            -        int index = pageLocalBitMapIndex(page, zOffset);
            -
            -        bitMap.atPut(index, value);
            -    }
            -
            -    @Override
            -    public void clear() {
            -        for (BitMap bitMap : pageToBitMap.values()) {
            -            bitMap.clear();
            -        }
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwarding.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwarding.java
            deleted file mode 100644
            index 727014a847956..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwarding.java
            +++ /dev/null
            @@ -1,136 +0,0 @@
            -/*
            - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
            - * Copyright (c) 2021, NTT DATA.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import java.util.Iterator;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.runtime.VMObjectFactory;
            -import sun.jvm.hotspot.types.CIntegerField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XForwarding extends VMObject {
            -    private static Type type;
            -    private static long virtualFieldOffset;
            -    private static long entriesFieldOffset;
            -    private static CIntegerField objectAlignmentShiftField;
            -    private static CIntegerField refCountField;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        type = db.lookupType("XForwarding");
            -
            -        virtualFieldOffset = type.getField("_virtual").getOffset();
            -        entriesFieldOffset = type.getField("_entries").getOffset();
            -        objectAlignmentShiftField = type.getCIntegerField("_object_alignment_shift");
            -        refCountField = type.getCIntegerField("_ref_count");
            -    }
            -
            -    public XForwarding(Address addr) {
            -        super(addr);
            -    }
            -
            -    public static long getSize() {
            -        return type.getSize();
            -    }
            -
            -    private XVirtualMemory virtual() {
            -        return VMObjectFactory.newObject(XVirtualMemory.class, addr.addOffsetTo(virtualFieldOffset));
            -    }
            -
            -    private XAttachedArrayForForwarding entries() {
            -        return VMObjectFactory.newObject(XAttachedArrayForForwarding.class, addr.addOffsetTo(entriesFieldOffset));
            -    }
            -
            -    public long start() {
            -        return virtual().start();
            -    }
            -
            -    public int objectAlignmentShift() {
            -        return (int)objectAlignmentShiftField.getValue(addr);
            -    }
            -
            -    public boolean retainPage() {
            -        return refCountField.getValue(addr) > 0;
            -    }
            -
            -    private XForwardingEntry at(long cursor) {
            -        long offset = XForwardingEntry.getSize() * cursor;
            -        Address entryAddress = entries().get(this).getAddress().addOffsetTo(offset);
            -        return VMObjectFactory.newObject(XForwardingEntry.class, entryAddress);
            -    }
            -
            -    private class XForwardEntryIterator implements Iterator {
            -
            -        private long cursor;
            -
            -        private XForwardingEntry nextEntry;
            -
            -        public XForwardEntryIterator(long fromIndex) {
            -            long mask = entries().length() - 1;
            -            long hash = XHash.uint32_to_uint32(fromIndex);
            -            cursor = hash & mask;
            -            nextEntry = at(cursor);
            -        }
            -
            -        @Override
            -        public boolean hasNext() {
            -            return nextEntry.populated();
            -        }
            -
            -        @Override
            -        public XForwardingEntry next() {
            -            XForwardingEntry entry = nextEntry;
            -
            -            long mask = entries().length() - 1;
            -            cursor = (cursor + 1) & mask;
            -            nextEntry = at(cursor);
            -
            -            return entry;
            -        }
            -
            -        public XForwardingEntry peak() {
            -            return nextEntry;
            -        }
            -    }
            -
            -    public XForwardingEntry find(long fromIndex) {
            -        XForwardEntryIterator itr = new XForwardEntryIterator(fromIndex);
            -        while (itr.hasNext()) {
            -            XForwardingEntry entry = itr.next();
            -            if (entry.fromIndex() == fromIndex) {
            -                return entry;
            -            }
            -        }
            -        return itr.peak();
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingEntry.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingEntry.java
            deleted file mode 100644
            index aa4b55775ec79..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingEntry.java
            +++ /dev/null
            @@ -1,97 +0,0 @@
            -/*
            - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
            - * Copyright (c) 2021, NTT DATA.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.runtime.VMObjectFactory;
            -import sun.jvm.hotspot.types.CIntegerField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XForwardingEntry extends VMObject {
            -    private static Type type;
            -    private static CIntegerField entryField;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        type = db.lookupType("XForwardingEntry");
            -
            -        entryField = type.getCIntegerField("_entry");
            -    }
            -
            -    public static long getSize() {
            -        return type.getSize();
            -    }
            -
            -    public XForwardingEntry(Address addr) {
            -        super(addr);
            -    }
            -
            -    public long entry() {
            -        return entryField.getValue(addr);
            -    }
            -
            -    // typedef XBitField field_populated
            -    private boolean fieldPopulatedDecode(long value) {
            -        long FieldMask = (1L << 1) - 1;
            -        int FieldShift = 1;
            -        int ValueShift = 0;
            -        return (((value >>> FieldShift) & FieldMask) << ValueShift) != 0L;
            -    }
            -
            -    // typedef XBitField field_to_offset;
            -    private long fieldToOffsetDecode(long value) {
            -        long FieldMask = (1L << 45) - 1;
            -        int FieldShift = 1;
            -        int ValueShift = 0;
            -        return ((value >>> FieldShift) & FieldMask) << ValueShift;
            -    }
            -
            -    // typedef XBitField field_from_index;
            -    private long fieldFromIndexDecode(long value) {
            -        long FieldMask = (1L << 18) - 1;
            -        int FieldShift = 46;
            -        int ValueShift = 0;
            -        return ((value >>> FieldShift) & FieldMask) << ValueShift;
            -    }
            -
            -    public boolean populated() {
            -        return fieldPopulatedDecode(entry());
            -    }
            -
            -    public long toOffset() {
            -        return fieldToOffsetDecode(entry());
            -    }
            -
            -    public long fromIndex() {
            -        return fieldFromIndexDecode(entry());
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingTable.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingTable.java
            deleted file mode 100644
            index 259f48a37b6cb..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingTable.java
            +++ /dev/null
            @@ -1,60 +0,0 @@
            -/*
            - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.runtime.VMObjectFactory;
            -import sun.jvm.hotspot.types.AddressField;
            -import sun.jvm.hotspot.types.CIntegerField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XForwardingTable extends VMObject {
            -    private static long mapFieldOffset;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XForwardingTable");
            -
            -        mapFieldOffset = type.getAddressField("_map").getOffset();
            -    }
            -
            -    public XForwardingTable(Address addr) {
            -        super(addr);
            -    }
            -
            -    private XGranuleMapForForwarding map() {
            -        return VMObjectFactory.newObject(XGranuleMapForForwarding.class, addr.addOffsetTo(mapFieldOffset));
            -    }
            -
            -    public XForwarding get(Address o) {
            -        return VMObjectFactory.newObject(XForwarding.class, map().get(XAddress.offset(o)));
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingTableCursor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingTableCursor.java
            deleted file mode 100644
            index 40103cd1e4331..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingTableCursor.java
            +++ /dev/null
            @@ -1,29 +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.
            - *
            - */
            -
            -package sun.jvm.hotspot.gc.x;
            -
            -class XForwardingTableCursor {
            -    long _value;
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGlobals.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGlobals.java
            deleted file mode 100644
            index 1cfc6dd76638b..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGlobals.java
            +++ /dev/null
            @@ -1,132 +0,0 @@
            -/*
            - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.types.Field;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XGlobals {
            -    private static Field instanceField;
            -
            -    // Global phase state
            -    public static int XPhaseRelocate;
            -
            -    public static byte XPageTypeSmall;
            -    public static byte XPageTypeMedium;
            -    public static byte XPageTypeLarge;
            -
            -    // Granule size shift
            -    public static long XGranuleSizeShift;
            -
            -    // Page size shifts
            -    public static long XPageSizeSmallShift;
            -    public static long XPageSizeMediumShift;
            -
            -    // Object alignment shifts
            -    public static int  XObjectAlignmentMediumShift;
            -    public static int  XObjectAlignmentLargeShift;
            -
            -    // Pointer part of address
            -    public static long XAddressOffsetShift;
            -
            -    // Pointer part of address
            -    public static long XAddressOffsetBits;
            -    public static long XAddressOffsetMax;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XGlobalsForVMStructs");
            -
            -        instanceField = type.getField("_instance_p");
            -
            -        XPhaseRelocate = db.lookupIntConstant("XPhaseRelocate").intValue();
            -
            -        XPageTypeSmall = db.lookupIntConstant("XPageTypeSmall").byteValue();
            -        XPageTypeMedium = db.lookupIntConstant("XPageTypeMedium").byteValue();
            -        XPageTypeLarge = db.lookupIntConstant("XPageTypeLarge").byteValue();
            -
            -        XGranuleSizeShift = db.lookupLongConstant("XGranuleSizeShift").longValue();
            -
            -        XPageSizeSmallShift = db.lookupLongConstant("XPageSizeSmallShift").longValue();
            -        XPageSizeMediumShift = db.lookupLongConstant("XPageSizeMediumShift").longValue();
            -
            -        XObjectAlignmentMediumShift = db.lookupIntConstant("XObjectAlignmentMediumShift").intValue();
            -        XObjectAlignmentLargeShift = db.lookupIntConstant("XObjectAlignmentLargeShift").intValue();
            -
            -        XAddressOffsetShift = db.lookupLongConstant("XAddressOffsetShift").longValue();
            -
            -        XAddressOffsetBits = db.lookupLongConstant("XAddressOffsetBits").longValue();
            -        XAddressOffsetMax  = db.lookupLongConstant("XAddressOffsetMax").longValue();
            -    }
            -
            -    private static XGlobalsForVMStructs instance() {
            -        return new XGlobalsForVMStructs(instanceField.getAddress());
            -    }
            -
            -    public static int XGlobalPhase() {
            -        return instance().XGlobalPhase();
            -    }
            -
            -    public static int XGlobalSeqNum() {
            -        return instance().XGlobalSeqNum();
            -    }
            -
            -    public static long XAddressOffsetMask() {
            -        return instance().XAddressOffsetMask();
            -    }
            -
            -    public static long XAddressMetadataMask() {
            -        return instance().XAddressMetadataMask();
            -    }
            -
            -    public static long XAddressMetadataFinalizable() {
            -        return instance().XAddressMetadataFinalizable();
            -    }
            -
            -    public static long XAddressGoodMask() {
            -        return instance().XAddressGoodMask();
            -    }
            -
            -    public static long XAddressBadMask() {
            -        return instance().XAddressBadMask();
            -    }
            -
            -    public static long XAddressWeakBadMask() {
            -        return instance().XAddressWeakBadMask();
            -    }
            -
            -    public static int XObjectAlignmentSmallShift() {
            -        return instance().XObjectAlignmentSmallShift();
            -    }
            -
            -    public static int XObjectAlignmentSmall() {
            -        return instance().XObjectAlignmentSmall();
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGlobalsForVMStructs.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGlobalsForVMStructs.java
            deleted file mode 100644
            index d4930dcd5dceb..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGlobalsForVMStructs.java
            +++ /dev/null
            @@ -1,108 +0,0 @@
            -/*
            - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.types.AddressField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -class XGlobalsForVMStructs extends VMObject {
            -    private static AddressField XGlobalPhaseField;
            -    private static AddressField XGlobalSeqNumField;
            -    private static AddressField XAddressOffsetMaskField;
            -    private static AddressField XAddressMetadataMaskField;
            -    private static AddressField XAddressMetadataFinalizableField;
            -    private static AddressField XAddressGoodMaskField;
            -    private static AddressField XAddressBadMaskField;
            -    private static AddressField XAddressWeakBadMaskField;
            -    private static AddressField XObjectAlignmentSmallShiftField;
            -    private static AddressField XObjectAlignmentSmallField;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XGlobalsForVMStructs");
            -
            -        XGlobalPhaseField = type.getAddressField("_XGlobalPhase");
            -        XGlobalSeqNumField = type.getAddressField("_XGlobalSeqNum");
            -        XAddressOffsetMaskField = type.getAddressField("_XAddressOffsetMask");
            -        XAddressMetadataMaskField = type.getAddressField("_XAddressMetadataMask");
            -        XAddressMetadataFinalizableField = type.getAddressField("_XAddressMetadataFinalizable");
            -        XAddressGoodMaskField = type.getAddressField("_XAddressGoodMask");
            -        XAddressBadMaskField = type.getAddressField("_XAddressBadMask");
            -        XAddressWeakBadMaskField = type.getAddressField("_XAddressWeakBadMask");
            -        XObjectAlignmentSmallShiftField = type.getAddressField("_XObjectAlignmentSmallShift");
            -        XObjectAlignmentSmallField = type.getAddressField("_XObjectAlignmentSmall");
            -    }
            -
            -    XGlobalsForVMStructs(Address addr) {
            -        super(addr);
            -    }
            -
            -    int XGlobalPhase() {
            -        return XGlobalPhaseField.getValue(addr).getJIntAt(0);
            -    }
            -
            -    int XGlobalSeqNum() {
            -        return XGlobalSeqNumField.getValue(addr).getJIntAt(0);
            -    }
            -
            -    long XAddressOffsetMask() {
            -        return XAddressOffsetMaskField.getValue(addr).getJLongAt(0);
            -    }
            -
            -    long XAddressMetadataMask() {
            -        return XAddressMetadataMaskField.getValue(addr).getJLongAt(0);
            -    }
            -
            -    long XAddressMetadataFinalizable() {
            -        return XAddressMetadataFinalizableField.getValue(addr).getJLongAt(0);
            -    }
            -
            -    long XAddressGoodMask() {
            -        return XAddressGoodMaskField.getValue(addr).getJLongAt(0);
            -    }
            -
            -    long XAddressBadMask() {
            -        return XAddressBadMaskField.getValue(addr).getJLongAt(0);
            -    }
            -
            -    long XAddressWeakBadMask() {
            -        return XAddressWeakBadMaskField.getValue(addr).getJLongAt(0);
            -    }
            -
            -    int XObjectAlignmentSmallShift() {
            -        return XObjectAlignmentSmallShiftField.getValue(addr).getJIntAt(0);
            -    }
            -
            -    int XObjectAlignmentSmall() {
            -        return XObjectAlignmentSmallField.getValue(addr).getJIntAt(0);
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGranuleMapForForwarding.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGranuleMapForForwarding.java
            deleted file mode 100644
            index 347f1405729a9..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGranuleMapForForwarding.java
            +++ /dev/null
            @@ -1,90 +0,0 @@
            -/*
            - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
            - * Copyright (c) 2021, NTT DATA.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.types.AddressField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XGranuleMapForForwarding  extends VMObject {
            -    private static AddressField mapField;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XGranuleMapForForwarding");
            -
            -        mapField = type.getAddressField("_map");
            -    }
            -
            -    public XGranuleMapForForwarding(Address addr) {
            -        super(addr);
            -    }
            -
            -    private Address map() {
            -        return mapField.getValue(addr);
            -    }
            -
            -    public long size() {
            -        return XGlobals.XAddressOffsetMax >> XGlobals.XGranuleSizeShift;
            -    }
            -
            -    private long index_for_offset(long offset) {
            -        long index = offset >>> XGlobals.XGranuleSizeShift;
            -
            -        return index;
            -    }
            -
            -    Address at(long index) {
            -        return map().getAddressAt(index * VM.getVM().getAddressSize());
            -    }
            -
            -    Address get(long offset) {
            -        long index = index_for_offset(offset);
            -        return at(index);
            -    }
            -
            -    public class Iterator {
            -        private long next = 0;
            -
            -        boolean hasNext() {
            -            return next < size();
            -        }
            -
            -        Address next() {
            -            if (next >= size()) {
            -                throw new RuntimeException("OOIBE");
            -            }
            -
            -            return at(next++);
            -        }
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGranuleMapForPageTable.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGranuleMapForPageTable.java
            deleted file mode 100644
            index 468a3e2457da3..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XGranuleMapForPageTable.java
            +++ /dev/null
            @@ -1,89 +0,0 @@
            -/*
            - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.types.AddressField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XGranuleMapForPageTable  extends VMObject {
            -    private static AddressField mapField;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XGranuleMapForPageTable");
            -
            -        mapField = type.getAddressField("_map");
            -    }
            -
            -    public XGranuleMapForPageTable(Address addr) {
            -        super(addr);
            -    }
            -
            -    private Address map() {
            -        return mapField.getValue(addr);
            -    }
            -
            -    public long size() {
            -        return XGlobals.XAddressOffsetMax >> XGlobals.XGranuleSizeShift;
            -    }
            -
            -    private long index_for_addr(Address addr) {
            -        long index = XAddress.offset(addr) >> XGlobals.XGranuleSizeShift;
            -
            -        return index;
            -    }
            -
            -    Address at(long index) {
            -        return map().getAddressAt(index * VM.getVM().getBytesPerLong());
            -    }
            -
            -    Address get(Address addr) {
            -        long index = index_for_addr(addr);
            -        return at(index);
            -    }
            -
            -    public class Iterator {
            -        private long next = 0;
            -
            -        boolean hasNext() {
            -            return next < size();
            -        }
            -
            -        Address next() {
            -            if (next >= size()) {
            -                throw new RuntimeException("OOIBE");
            -            }
            -
            -            return at(next++);
            -        }
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XHeap.java
            deleted file mode 100644
            index c309ce2194438..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XHeap.java
            +++ /dev/null
            @@ -1,127 +0,0 @@
            -/*
            - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import java.io.PrintStream;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.runtime.VMObjectFactory;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -// Mirror class for XHeap
            -
            -public class XHeap extends VMObject {
            -
            -    private static long pageAllocatorFieldOffset;
            -    private static long pageTableFieldOffset;
            -    private static long forwardingTableFieldOffset;
            -    private static long relocateFieldOffset;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XHeap");
            -
            -        pageAllocatorFieldOffset = type.getAddressField("_page_allocator").getOffset();
            -        pageTableFieldOffset = type.getAddressField("_page_table").getOffset();
            -        forwardingTableFieldOffset = type.getAddressField("_forwarding_table").getOffset();
            -        relocateFieldOffset = type.getAddressField("_relocate").getOffset();
            -    }
            -
            -    public XHeap(Address addr) {
            -        super(addr);
            -    }
            -
            -    private XPageAllocator pageAllocator() {
            -        Address pageAllocatorAddr = addr.addOffsetTo(pageAllocatorFieldOffset);
            -        return VMObjectFactory.newObject(XPageAllocator.class, pageAllocatorAddr);
            -    }
            -
            -    XPageTable pageTable() {
            -        return VMObjectFactory.newObject(XPageTable.class, addr.addOffsetTo(pageTableFieldOffset));
            -    }
            -
            -    XForwardingTable forwardingTable() {
            -        return VMObjectFactory.newObject(XForwardingTable.class, addr.addOffsetTo(forwardingTableFieldOffset));
            -    }
            -
            -    XRelocate relocate() {
            -        return VMObjectFactory.newObject(XRelocate.class, addr.addOffsetTo(relocateFieldOffset));
            -    }
            -
            -    public long maxCapacity() {
            -        return pageAllocator().maxCapacity();
            -    }
            -
            -    public long capacity() {
            -        return pageAllocator().capacity();
            -    }
            -
            -    public long used() {
            -        return pageAllocator().used();
            -    }
            -
            -    boolean is_relocating(Address o) {
            -        return pageTable().is_relocating(o);
            -    }
            -
            -    Address relocate_object(Address addr) {
            -        XForwarding forwarding = forwardingTable().get(addr);
            -        if (forwarding == null) {
            -            return XAddress.good(addr);
            -        }
            -        return relocate().relocateObject(forwarding, XAddress.good(addr));
            -    }
            -
            -    public boolean isIn(Address addr) {
            -        if (XAddress.isIn(addr)) {
            -            XPage page = pageTable().get(addr);
            -            if (page != null) {
            -                return page.isIn(addr);
            -            }
            -        }
            -        return false;
            -    }
            -
            -    public Address remapObject(Address o) {
            -        XForwarding forwarding = forwardingTable().get(addr);
            -        if (forwarding == null) {
            -            return XAddress.good(o);
            -        }
            -        return relocate().forwardObject(forwarding, XAddress.good(o));
            -    }
            -
            -    public void printOn(PrintStream tty) {
            -        tty.print(" ZHeap          ");
            -        tty.print("used " + (used() / 1024 / 1024) + "M, ");
            -        tty.print("capacity " + (capacity() / 1024 / 1024) + "M, ");
            -        tty.println("max capacity " + (maxCapacity() / 1024 / 1024) + "M");
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XOop.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XOop.java
            deleted file mode 100644
            index bbe296f658bc2..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XOop.java
            +++ /dev/null
            @@ -1,34 +0,0 @@
            -/*
            - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.debugger.OopHandle;
            -
            -class XOop {
            -    static Address to_address(OopHandle oop) {
            -        return oop;
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPage.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPage.java
            deleted file mode 100644
            index a6315f10130fc..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPage.java
            +++ /dev/null
            @@ -1,141 +0,0 @@
            -/*
            - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import java.util.ArrayList;
            -import java.util.List;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.debugger.OopHandle;
            -import sun.jvm.hotspot.gc.shared.LiveRegionsProvider;
            -import sun.jvm.hotspot.memory.MemRegion;
            -import sun.jvm.hotspot.oops.Oop;
            -import sun.jvm.hotspot.oops.UnknownOopException;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.runtime.VMObjectFactory;
            -import sun.jvm.hotspot.types.AddressField;
            -import sun.jvm.hotspot.types.CIntegerField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XPage extends VMObject implements LiveRegionsProvider {
            -    private static CIntegerField typeField;
            -    private static CIntegerField seqnumField;
            -    private static long virtualFieldOffset;
            -    private static AddressField topField;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XPage");
            -
            -        typeField = type.getCIntegerField("_type");
            -        seqnumField = type.getCIntegerField("_seqnum");
            -        virtualFieldOffset = type.getField("_virtual").getOffset();
            -        topField = type.getAddressField("_top");
            -    }
            -
            -    public XPage(Address addr) {
            -        super(addr);
            -    }
            -
            -    private byte type() {
            -        return typeField.getJByte(addr);
            -    }
            -
            -    private int seqnum() {
            -        return seqnumField.getJInt(addr);
            -    }
            -
            -    private XVirtualMemory virtual() {
            -        return VMObjectFactory.newObject(XVirtualMemory.class, addr.addOffsetTo(virtualFieldOffset));
            -    }
            -
            -    private Address top() {
            -        return topField.getValue(addr);
            -    }
            -
            -    private boolean is_relocatable() {
            -        return seqnum() < XGlobals.XGlobalSeqNum();
            -    }
            -
            -    long start() {
            -        return virtual().start();
            -    }
            -
            -    long size() {
            -        return virtual().end() - virtual().start();
            -    }
            -
            -    long object_alignment_shift() {
            -        if (type() == XGlobals.XPageTypeSmall) {
            -            return XGlobals.XObjectAlignmentSmallShift();
            -        } else if (type() == XGlobals.XPageTypeMedium) {
            -            return XGlobals.XObjectAlignmentMediumShift;
            -        } else {
            -            assert(type() == XGlobals.XPageTypeLarge);
            -            return XGlobals.XObjectAlignmentLargeShift;
            -        }
            -    }
            -
            -    long objectAlignmentSize() {
            -        return 1 << object_alignment_shift();
            -    }
            -
            -    public boolean isIn(Address addr) {
            -        long offset = XAddress.offset(addr);
            -        // FIXME: it does not consider the sign.
            -        return (offset >= start()) && (offset < top().asLongValue());
            -    }
            -
            -    private long getObjectSize(Address good) {
            -        OopHandle handle = good.addOffsetToAsOopHandle(0);
            -        Oop obj = null;
            -
            -        try {
            -           obj = VM.getVM().getObjectHeap().newOop(handle);
            -        } catch (UnknownOopException exp) {
            -          throw new RuntimeException(" UnknownOopException  " + exp);
            -        }
            -
            -        return VM.getVM().alignUp(obj.getObjectSize(), objectAlignmentSize());
            -    }
            -
            -    public List getLiveRegions() {
            -        Address start = XAddress.good(XUtils.longToAddress(start()));
            -
            -        // Can't convert top() to a "good" address because it might
            -        // be at the top of the "offset" range, and therefore also
            -        // looks like one of the color bits. Instead use the "good"
            -        // address and add the size.
            -        long size = top().asLongValue() - start();
            -        Address end = start.addOffsetTo(size);
            -
            -        return List.of(new MemRegion(start, end));
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPageAllocator.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPageAllocator.java
            deleted file mode 100644
            index 1af19ea875f2a..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPageAllocator.java
            +++ /dev/null
            @@ -1,69 +0,0 @@
            -/*
            - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.types.CIntegerField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -// Mirror class for XPageAllocator
            -
            -public class XPageAllocator extends VMObject {
            -
            -    private static CIntegerField maxCapacityField;
            -    private static CIntegerField capacityField;
            -    private static CIntegerField usedField;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XPageAllocator");
            -
            -        maxCapacityField = type.getCIntegerField("_max_capacity");
            -        capacityField = type.getCIntegerField("_capacity");
            -        usedField = type.getCIntegerField("_used");
            -    }
            -
            -    public long maxCapacity() {
            -        return maxCapacityField.getValue(addr);
            -    }
            -
            -    public long capacity() {
            -        return capacityField.getValue(addr);
            -    }
            -
            -    public long used() {
            -        return usedField.getValue(addr);
            -    }
            -
            -    public XPageAllocator(Address addr) {
            -        super(addr);
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPageTable.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPageTable.java
            deleted file mode 100644
            index c2aba43b91294..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPageTable.java
            +++ /dev/null
            @@ -1,176 +0,0 @@
            -/*
            - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import java.util.Iterator;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.runtime.VMObjectFactory;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XPageTable extends VMObject {
            -    private static long mapFieldOffset;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XPageTable");
            -
            -        mapFieldOffset = type.getAddressField("_map").getOffset();
            -    }
            -
            -    public XPageTable(Address addr) {
            -        super(addr);
            -    }
            -
            -    private XGranuleMapForPageTable map() {
            -        return VMObjectFactory.newObject(XGranuleMapForPageTable.class, addr.addOffsetTo(mapFieldOffset));
            -    }
            -
            -    private XPageTableEntry getEntry(Address o) {
            -        return new XPageTableEntry(map().get(o));
            -    }
            -
            -    XPage get(Address o) {
            -        return VMObjectFactory.newObject(XPage.class, map().get(VM.getVM().getDebugger().newAddress(XAddress.offset(o))));
            -    }
            -
            -    boolean is_relocating(Address o) {
            -        return getEntry(o).relocating();
            -    }
            -
            -    private class XPagesIterator implements Iterator {
            -        private XGranuleMapForPageTable.Iterator mapIter;
            -        private XPage next;
            -
            -        XPagesIterator() {
            -            mapIter = map().new Iterator();
            -            positionToNext();
            -        }
            -
            -        private XPage positionToNext() {
            -            XPage current = next;
            -
            -            // Find next
            -            XPage found = null;
            -            while (mapIter.hasNext()) {
            -                XPageTableEntry entry = new XPageTableEntry(mapIter.next());
            -                if (!entry.isEmpty()) {
            -                    XPage page = entry.page();
            -                    // Medium pages have repeated entries for all covered slots,
            -                    // therefore we need to compare against the current page.
            -                    if (page != null && !page.equals(current)) {
            -                        found = page;
            -                        break;
            -                    }
            -                }
            -            }
            -
            -            next = found;
            -
            -            return current;
            -        }
            -
            -        @Override
            -        public boolean hasNext() {
            -            return next != null;
            -        }
            -
            -        @Override
            -        public XPage next() {
            -            return positionToNext();
            -        }
            -
            -        @Override
            -        public void remove() {
            -            /* not supported */
            -        }
            -    }
            -
            -    abstract class XPageFilter {
            -        public abstract boolean accept(XPage page);
            -    }
            -
            -    class XPagesFilteredIterator implements Iterator {
            -        private XPage next;
            -        private XPagesIterator iter = new XPagesIterator();
            -        private XPageFilter filter;
            -
            -        XPagesFilteredIterator(XPageFilter filter) {
            -            this.filter = filter;
            -            positionToNext();
            -        }
            -
            -        public XPage positionToNext() {
            -            XPage current = next;
            -
            -            // Find next
            -            XPage found = null;
            -            while (iter.hasNext()) {
            -                XPage page = iter.next();
            -                if (filter.accept(page)) {
            -                    found = page;
            -                    break;
            -                }
            -            }
            -
            -            next = found;
            -
            -            return current;
            -        }
            -
            -        @Override
            -        public boolean hasNext() {
            -            return next != null;
            -        }
            -
            -        @Override
            -        public XPage next() {
            -            return positionToNext();
            -        }
            -
            -        @Override
            -        public void remove() {
            -            /* not supported */
            -        }
            -    }
            -
            -    public Iterator iterator() {
            -        return new XPagesIterator();
            -    }
            -
            -    public Iterator activePagesIterator() {
            -        return new XPagesFilteredIterator(new XPageFilter() {
            -            public boolean accept(XPage page) {
            -                return page != null;
            -            }
            -        });
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XRelocate.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XRelocate.java
            deleted file mode 100644
            index a4b0dc1c992ec..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XRelocate.java
            +++ /dev/null
            @@ -1,74 +0,0 @@
            -/*
            - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
            - * Copyright (c) 2021, NTT DATA.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.types.AddressField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XRelocate  extends VMObject {
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XRelocate");
            -    }
            -
            -    public XRelocate(Address addr) {
            -        super(addr);
            -    }
            -
            -    private long forwardingIndex(XForwarding forwarding, Address from) {
            -        long fromOffset = XAddress.offset(from);
            -        return (fromOffset - forwarding.start()) >>> forwarding.objectAlignmentShift();
            -    }
            -
            -    private Address forwardingFind(XForwarding forwarding, Address from) {
            -        long fromIndex = forwardingIndex(forwarding, from);
            -        XForwardingEntry entry = forwarding.find(fromIndex);
            -        return entry.populated() ? XAddress.good(VM.getVM().getDebugger().newAddress(entry.toOffset())) : null;
            -    }
            -
            -    public Address forwardObject(XForwarding forwarding, Address from) {
            -        return forwardingFind(forwarding, from);
            -    }
            -
            -    public Address relocateObject(XForwarding forwarding, Address o) {
            -        Address toAddr = forwardingFind(forwarding, o);
            -        if (toAddr != null) {
            -            // Already relocated.
            -            return toAddr;
            -        } else {
            -            // Return original address because it is not yet relocated.
            -            return o;
            -        }
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XVirtualMemory.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XVirtualMemory.java
            deleted file mode 100644
            index de225ccdcbd22..0000000000000
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XVirtualMemory.java
            +++ /dev/null
            @@ -1,60 +0,0 @@
            -/*
            - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
            - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
            - *
            - * This code is free software; you can redistribute 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 sun.jvm.hotspot.gc.x;
            -
            -import sun.jvm.hotspot.debugger.Address;
            -import sun.jvm.hotspot.runtime.VM;
            -import sun.jvm.hotspot.runtime.VMObject;
            -import sun.jvm.hotspot.types.CIntegerField;
            -import sun.jvm.hotspot.types.Type;
            -import sun.jvm.hotspot.types.TypeDataBase;
            -
            -public class XVirtualMemory extends VMObject {
            -    private static CIntegerField startField;
            -    private static CIntegerField endField;
            -
            -    static {
            -        VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
            -    }
            -
            -    private static synchronized void initialize(TypeDataBase db) {
            -        Type type = db.lookupType("XVirtualMemory");
            -
            -        startField = type.getCIntegerField("_start");
            -        endField = type.getCIntegerField("_end");
            -    }
            -
            -    public XVirtualMemory(Address addr) {
            -        super(addr);
            -    }
            -
            -    long start() {
            -        return startField.getJLong(addr);
            -    }
            -
            -    long end() {
            -        return endField.getJLong(addr);
            -    }
            -}
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java
            index c4ab8e32c0bb0..01fd0f7430afe 100644
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java
            +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java
            @@ -36,7 +36,6 @@
             import sun.jvm.hotspot.gc.serial.SerialHeap;
             import sun.jvm.hotspot.gc.shared.CollectedHeap;
             import sun.jvm.hotspot.gc.shenandoah.ShenandoahHeap;
            -import sun.jvm.hotspot.gc.x.XCollectedHeap;
             import sun.jvm.hotspot.gc.z.ZCollectedHeap;
             import sun.jvm.hotspot.oops.Oop;
             import sun.jvm.hotspot.runtime.BasicType;
            @@ -87,7 +86,6 @@ private static synchronized void initialize(TypeDataBase db) {
                 addHeapTypeIfInDB(db, ParallelScavengeHeap.class);
                 addHeapTypeIfInDB(db, G1CollectedHeap.class);
                 addHeapTypeIfInDB(db, EpsilonHeap.class);
            -    addHeapTypeIfInDB(db, XCollectedHeap.class);
                 addHeapTypeIfInDB(db, ZCollectedHeap.class);
                 addHeapTypeIfInDB(db, ShenandoahHeap.class);
             
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java
            index 2c1ad426b6a05..be6c8522fc58f 100644
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java
            +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java
            @@ -37,7 +37,6 @@
             import sun.jvm.hotspot.gc.g1.*;
             import sun.jvm.hotspot.gc.shenandoah.*;
             import sun.jvm.hotspot.gc.parallel.*;
            -import sun.jvm.hotspot.gc.x.*;
             import sun.jvm.hotspot.memory.*;
             import sun.jvm.hotspot.runtime.*;
             import sun.jvm.hotspot.types.*;
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java
            index cb5e2add58003..1dc67330d3d05 100644
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java
            +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java
            @@ -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
            @@ -75,11 +75,11 @@ private long alignmentReserve() {
               }
             
               private long endReserve() {
            -    long minFillerArraySize = Array.baseOffsetInBytes(BasicType.T_INT);
            +    long labAlignmentReserve = VM.getVM().getLabAlignmentReserve();
                 long reserveForAllocationPrefetch = VM.getVM().getReserveForAllocationPrefetch();
                 long heapWordSize = VM.getVM().getHeapWordSize();
             
            -    return Math.max(minFillerArraySize, reserveForAllocationPrefetch * heapWordSize);
            +    return Math.max(labAlignmentReserve, reserveForAllocationPrefetch) * heapWordSize;
               }
             
               /** Support for iteration over heap -- not sure how this will
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java
            index 232f3e864a3f8..da9008840450c 100644
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java
            +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java
            @@ -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
            @@ -127,6 +127,7 @@ public class VM {
               private ReversePtrs  revPtrs;
               private VMRegImpl    vmregImpl;
               private int          reserveForAllocationPrefetch;
            +  private int          labAlignmentReserve;
             
               // System.getProperties from debuggee VM
               private Properties   sysProps;
            @@ -138,12 +139,12 @@ public class VM {
               private Flag[] commandLineFlags;
               private Map flagsMap;
             
            -  private static Type intType;
            -  private static Type uintType;
            -  private static Type intxType;
            -  private static Type uintxType;
            -  private static Type sizetType;
            -  private static Type uint64tType;
            +  private static CIntegerType intType;
            +  private static CIntegerType uintType;
            +  private static CIntegerType intxType;
            +  private static CIntegerType uintxType;
            +  private static CIntegerType sizetType;
            +  private static CIntegerType uint64tType;
               private static CIntegerType boolType;
               private Boolean sharingEnabled;
               private Boolean compressedOopsEnabled;
            @@ -432,17 +433,29 @@ private VM(TypeDataBase db, JVMDebugger debugger, boolean isBigEndian) {
                    vmRelease = CStringUtilities.getString(releaseAddr);
                    Address vmInternalInfoAddr = vmVersion.getAddressField("_s_internal_vm_info_string").getValue();
                    vmInternalInfo = CStringUtilities.getString(vmInternalInfoAddr);
            -
            -       Type threadLocalAllocBuffer = db.lookupType("ThreadLocalAllocBuffer");
            -       CIntegerType intType = (CIntegerType) db.lookupType("int");
            -       CIntegerField reserveForAllocationPrefetchField = threadLocalAllocBuffer.getCIntegerField("_reserve_for_allocation_prefetch");
            -       reserveForAllocationPrefetch = (int)reserveForAllocationPrefetchField.getCInteger(intType);
                 } catch (Exception exp) {
                    throw new RuntimeException("can't determine target's VM version : " + exp.getMessage());
                 }
             
                 checkVMVersion(vmRelease);
             
            +    // Initialize common primitive types
            +    intType = (CIntegerType) db.lookupType("int");
            +    uintType = (CIntegerType) db.lookupType("uint");
            +    intxType = (CIntegerType) db.lookupType("intx");
            +    uintxType = (CIntegerType) db.lookupType("uintx");
            +    sizetType = (CIntegerType) db.lookupType("size_t");
            +    uint64tType = (CIntegerType) db.lookupType("uint64_t");
            +    boolType = (CIntegerType) db.lookupType("bool");
            +
            +    Type threadLocalAllocBuffer = db.lookupType("ThreadLocalAllocBuffer");
            +    CIntegerField reserveForAllocationPrefetchField = threadLocalAllocBuffer.getCIntegerField("_reserve_for_allocation_prefetch");
            +    reserveForAllocationPrefetch = (int)reserveForAllocationPrefetchField.getCInteger(intType);
            +
            +    Type collectedHeap = db.lookupType("CollectedHeap");
            +    CIntegerField labAlignmentReserveField = collectedHeap.getCIntegerField("_lab_alignment_reserve");
            +    labAlignmentReserve = (int)labAlignmentReserveField.getCInteger(sizetType);
            +
                 invocationEntryBCI = db.lookupIntConstant("InvocationEntryBci").intValue();
             
                 // We infer the presence of JVMTI from the presence of the InstanceKlass::_breakpoints field.
            @@ -493,14 +506,6 @@ private VM(TypeDataBase db, JVMDebugger debugger, boolean isBigEndian) {
                 Flags_WAS_SET_ON_COMMAND_LINE = db.lookupIntConstant("JVMFlag::WAS_SET_ON_COMMAND_LINE").intValue();
                 oopSize  = db.lookupIntConstant("oopSize").intValue();
             
            -    intType = db.lookupType("int");
            -    uintType = db.lookupType("uint");
            -    intxType = db.lookupType("intx");
            -    uintxType = db.lookupType("uintx");
            -    sizetType = db.lookupType("size_t");
            -    uint64tType = db.lookupType("uint64_t");
            -    boolType = (CIntegerType) db.lookupType("bool");
            -
                 minObjAlignmentInBytes = getObjectAlignmentInBytes();
                 if ((minObjAlignmentInBytes & (minObjAlignmentInBytes - 1)) != 0) {
                   throw new RuntimeException("Object alignment " + minObjAlignmentInBytes + " is not power of two");
            @@ -929,6 +934,10 @@ public int getReserveForAllocationPrefetch() {
                 return reserveForAllocationPrefetch;
               }
             
            +  public int getLabAlignmentReserve() {
            +    return labAlignmentReserve;
            +  }
            +
               public boolean isSharingEnabled() {
                 if (sharingEnabled == null) {
                     Address address = VM.getVM().getDebugger().lookup(null, "UseSharedSpaces");
            diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java
            index 86a1216bbd3d4..58a9c1b451954 100644
            --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java
            +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java
            @@ -32,7 +32,6 @@
             import sun.jvm.hotspot.gc.serial.*;
             import sun.jvm.hotspot.gc.shenandoah.*;
             import sun.jvm.hotspot.gc.shared.*;
            -import sun.jvm.hotspot.gc.x.*;
             import sun.jvm.hotspot.gc.z.*;
             import sun.jvm.hotspot.debugger.JVMDebugger;
             import sun.jvm.hotspot.memory.*;
            @@ -145,9 +144,6 @@ public void run() {
                   } else if (heap instanceof EpsilonHeap) {
                      EpsilonHeap eh = (EpsilonHeap) heap;
                      printSpace(eh.space());
            -      } else if (heap instanceof XCollectedHeap) {
            -         XCollectedHeap zheap = (XCollectedHeap) heap;
            -         zheap.printOn(System.out);
                   } else if (heap instanceof ZCollectedHeap) {
                      ZCollectedHeap zheap = (ZCollectedHeap) heap;
                      zheap.printOn(System.out);
            diff --git a/src/jdk.httpserver/share/classes/module-info.java b/src/jdk.httpserver/share/classes/module-info.java
            index 46dbb6ea64f68..23e04405ee863 100644
            --- a/src/jdk.httpserver/share/classes/module-info.java
            +++ b/src/jdk.httpserver/share/classes/module-info.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
            @@ -70,6 +70,16 @@
              * while the headers are being read, then the connection is terminated and the request ignored.
              * If the value is less than or equal to zero, then the default value is used.
              * 
            + * 
          22. {@systemProperty sun.net.httpserver.maxReqHeaderSize} (default: 393216 or 384kB)
            + * The maximum header field section size that the server is prepared to accept. + * This is computed as the sum of the size of the header name, plus + * the size of the header value, plus an overhead of 32 bytes for + * each field section line. The request line counts as a first field section line, + * where the name is empty and the value is the whole line. + * If this limit is exceeded while the headers are being read, then the connection + * is terminated and the request ignored. + * If the value is less than or equal to zero, there is no limit. + *

          23. *
          24. {@systemProperty sun.net.httpserver.maxReqTime} (default: -1)
            * The maximum time in milliseconds allowed to receive a request headers and body. * In practice, the actual time is a function of request size, network speed, and handler diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java index 99dac0547cead..6c0c2c271ed4a 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.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 @@ -44,8 +44,10 @@ class Request { private SocketChannel chan; private InputStream is; private OutputStream os; + private final int maxReqHeaderSize; Request (InputStream rawInputStream, OutputStream rawout) throws IOException { + this.maxReqHeaderSize = ServerConfig.getMaxReqHeaderSize(); is = rawInputStream; os = rawout; do { @@ -75,6 +77,7 @@ public OutputStream outputStream () { public String readLine () throws IOException { boolean gotCR = false, gotLF = false; pos = 0; lineBuf = new StringBuffer(); + long lsize = 32; while (!gotLF) { int c = is.read(); if (c == -1) { @@ -87,20 +90,27 @@ public String readLine () throws IOException { gotCR = false; consume (CR); consume (c); + lsize = lsize + 2; } } else { if (c == CR) { gotCR = true; } else { consume (c); + lsize = lsize + 1; } } + if (maxReqHeaderSize > 0 && lsize > maxReqHeaderSize) { + throw new IOException("Maximum header (" + + "sun.net.httpserver.maxReqHeaderSize) exceeded, " + + ServerConfig.getMaxReqHeaderSize() + "."); + } } lineBuf.append (buf, 0, pos); return new String (lineBuf); } - private void consume (int c) { + private void consume (int c) throws IOException { if (pos == BUF_LEN) { lineBuf.append (buf); pos = 0; @@ -138,13 +148,22 @@ Headers headers () throws IOException { len = 1; firstc = c; } + long hsize = startLine.length() + 32L; while (firstc != LF && firstc != CR && firstc >= 0) { int keyend = -1; int c; boolean inKey = firstc > ' '; s[len++] = (char) firstc; + hsize = hsize + 1; parseloop:{ + // We start parsing for a new name value pair here. + // The max header size includes an overhead of 32 bytes per + // name value pair. + // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2. + long maxRemaining = maxReqHeaderSize > 0 + ? maxReqHeaderSize - hsize - 32 + : Long.MAX_VALUE; while ((c = is.read()) >= 0) { switch (c) { /*fallthrough*/ @@ -178,6 +197,11 @@ Headers headers () throws IOException { s = ns; } s[len++] = (char) c; + if (maxReqHeaderSize > 0 && len > maxRemaining) { + throw new IOException("Maximum header (" + + "sun.net.httpserver.maxReqHeaderSize) exceeded, " + + ServerConfig.getMaxReqHeaderSize() + "."); + } } firstc = -1; } @@ -205,6 +229,13 @@ Headers headers () throws IOException { "sun.net.httpserver.maxReqHeaders) exceeded, " + ServerConfig.getMaxReqHeaders() + "."); } + hsize = hsize + len + 32; + if (maxReqHeaderSize > 0 && hsize > maxReqHeaderSize) { + throw new IOException("Maximum header (" + + "sun.net.httpserver.maxReqHeaderSize) exceeded, " + + ServerConfig.getMaxReqHeaderSize() + "."); + } + if (k == null) { // Headers disallows null keys, use empty string k = ""; // instead to represent invalid key } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java index 21f6165b05eae..9186dd4c168c1 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.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 @@ -49,6 +49,7 @@ class ServerConfig { // timing out request/response if max request/response time is configured private static final long DEFAULT_REQ_RSP_TIMER_TASK_SCHEDULE_MILLIS = 1000; private static final int DEFAULT_MAX_REQ_HEADERS = 200; + private static final int DEFAULT_MAX_REQ_HEADER_SIZE = 380 * 1024; private static final long DEFAULT_DRAIN_AMOUNT = 64 * 1024; private static long idleTimerScheduleMillis; @@ -62,6 +63,9 @@ class ServerConfig { private static int maxIdleConnections; // The maximum number of request headers allowable private static int maxReqHeaders; + // a maximum value for the header list size. This is the + // names size + values size + 32 bytes per field line + private static int maxReqHeadersSize; // max time a request or response is allowed to take private static long maxReqTime; private static long maxRspTime; @@ -107,6 +111,14 @@ public Void run () { maxReqHeaders = DEFAULT_MAX_REQ_HEADERS; } + // a value <= 0 means unlimited + maxReqHeadersSize = Integer.getInteger( + "sun.net.httpserver.maxReqHeaderSize", + DEFAULT_MAX_REQ_HEADER_SIZE); + if (maxReqHeadersSize <= 0) { + maxReqHeadersSize = 0; + } + maxReqTime = Long.getLong("sun.net.httpserver.maxReqTime", DEFAULT_MAX_REQ_TIME); @@ -215,6 +227,10 @@ static int getMaxReqHeaders() { return maxReqHeaders; } + static int getMaxReqHeaderSize() { + return maxReqHeadersSize; + } + /** * @return Returns the maximum amount of time the server will wait for the request to be read * completely. This method can return a value of 0 or negative to imply no maximum limit has diff --git a/src/jdk.incubator.vector/linux/native/libsleef/lib/vector_math_rvv.c b/src/jdk.incubator.vector/linux/native/libsleef/lib/vector_math_rvv.c new file mode 100644 index 0000000000000..438ca0c92ba0f --- /dev/null +++ b/src/jdk.incubator.vector/linux/native/libsleef/lib/vector_math_rvv.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2024, Rivos 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. + */ + +// On riscv, sleef vector apis depend on native vector intrinsic, which is supported on +// some compiler, e.g. gcc 14+. +// __riscv_v_intrinsic is used to tell if the compiler supports vector intrinsic. +// +// At compile-time, if the current compiler does support vector intrinsics, bridge +// functions will be built in the library. In case the current compiler doesn't support +// vector intrinsics (gcc < 14), then the bridge functions won't be compiled. +// At run-time, if the library is found and the bridge functions are available in the +// library, then the java vector API will call into the bridge functions and sleef. + +#if __GNUC__ >= 14 || (defined(__clang_major__) && __clang_major__ >= 17) + +#ifdef __riscv_v_intrinsic + +#include + +#include + +#include "../generated/misc.h" +#include "../generated/sleefinline_rvvm1.h" + +#include + +// We maintain an invariant in java world that default dynamic rounding mode is RNE, +// please check JDK-8330094, JDK-8330266 for more details. +// Currently, sleef source on riscv does not change rounding mode to others except +// of RNE. But we still think it's safer to make sure that after calling into sleef +// the dynamic rounding mode is always RNE. + +#ifdef DEBUG +#define CHECK_FRM __asm__ __volatile__ ( \ + " frrm t0 \n\t" \ + " beqz t0, 2f \n\t" \ + " csrrw x0, cycle, x0 \n\t" \ + "2: \n\t" \ + : : : "memory" ); +#else +#define CHECK_FRM +#endif + +#define DEFINE_VECTOR_MATH_UNARY_RVV(op, type) \ +JNIEXPORT \ +type op##rvv(type input) { \ + type res = Sleef_##op##rvvm1(input); \ + CHECK_FRM \ + return res; \ +} + +#define DEFINE_VECTOR_MATH_BINARY_RVV(op, type) \ +JNIEXPORT \ +type op##rvv(type input1, type input2) { \ + type res = Sleef_##op##rvvm1(input1, input2); \ + CHECK_FRM \ + return res; \ +} + +DEFINE_VECTOR_MATH_UNARY_RVV(tanfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(sinfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(sinhfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(cosfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(coshfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(asinfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(acosfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(atanfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(cbrtfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(logfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(log10fx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(log1pfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(expfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(expm1fx_u10, vfloat_rvvm1_sleef) + +DEFINE_VECTOR_MATH_UNARY_RVV(tandx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(sindx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(sinhdx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(cosdx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(coshdx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(asindx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(acosdx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(atandx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(cbrtdx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(logdx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(log10dx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(log1pdx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(expdx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_UNARY_RVV(expm1dx_u10, vdouble_rvvm1_sleef) + +DEFINE_VECTOR_MATH_BINARY_RVV(atan2fx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_BINARY_RVV(powfx_u10, vfloat_rvvm1_sleef) +DEFINE_VECTOR_MATH_BINARY_RVV(hypotfx_u05, vfloat_rvvm1_sleef) + +DEFINE_VECTOR_MATH_BINARY_RVV(atan2dx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_BINARY_RVV(powdx_u10, vdouble_rvvm1_sleef) +DEFINE_VECTOR_MATH_BINARY_RVV(hypotdx_u05, vdouble_rvvm1_sleef) + +#undef DEFINE_VECTOR_MATH_UNARY_RVV + +#undef DEFINE_VECTOR_MATH_BINARY_RVV + +#endif /* __riscv_v_intrinsic */ + +#endif /* check gcc and clang version */ diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java index 0bc25958a7617..3cf25d46f441e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java @@ -506,6 +506,13 @@ public Byte128Vector selectFrom(Vector v, Byte128Mask.class, (Byte128Mask) m); // specialize } + @Override + @ForceInline + public Byte128Vector selectFrom(Vector v1, + Vector v2) { + return (Byte128Vector) + super.selectFromTemplate((Byte128Vector) v1, (Byte128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java index 639646aa77ad5..cb9f2679dcafa 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java @@ -506,6 +506,13 @@ public Byte256Vector selectFrom(Vector v, Byte256Mask.class, (Byte256Mask) m); // specialize } + @Override + @ForceInline + public Byte256Vector selectFrom(Vector v1, + Vector v2) { + return (Byte256Vector) + super.selectFromTemplate((Byte256Vector) v1, (Byte256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java index 2d8151f6800f3..f5ff05757039d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java @@ -506,6 +506,13 @@ public Byte512Vector selectFrom(Vector v, Byte512Mask.class, (Byte512Mask) m); // specialize } + @Override + @ForceInline + public Byte512Vector selectFrom(Vector v1, + Vector v2) { + return (Byte512Vector) + super.selectFromTemplate((Byte512Vector) v1, (Byte512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java index bc8ed7d704d96..37e8978d7e802 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java @@ -506,6 +506,13 @@ public Byte64Vector selectFrom(Vector v, Byte64Mask.class, (Byte64Mask) m); // specialize } + @Override + @ForceInline + public Byte64Vector selectFrom(Vector v1, + Vector v2) { + return (Byte64Vector) + super.selectFromTemplate((Byte64Vector) v1, (Byte64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java index 597afd8d165b3..17dcf193ceb98 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java @@ -506,6 +506,13 @@ public ByteMaxVector selectFrom(Vector v, ByteMaxMask.class, (ByteMaxMask) m); // specialize } + @Override + @ForceInline + public ByteMaxVector selectFrom(Vector v1, + Vector v2) { + return (ByteMaxVector) + super.selectFromTemplate((ByteMaxVector) v1, (ByteMaxVector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index a23bbc7f70957..f36215ffe1235 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -536,6 +536,19 @@ static ByteVector compressHelper(Vector v, VectorMask m) { return r; } + static ByteVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + byte[] res = new byte[vlen]; + byte[] vecPayload1 = ((ByteVector)indexes).vec(); + byte[] vecPayload2 = ((ByteVector)src1).vec(); + byte[] vecPayload3 = ((ByteVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((ByteVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -871,6 +884,18 @@ private static BinaryOperation> binaryOperations(in v0.bOp(v1, vm, (i, a, n) -> rotateLeft(a, (int)n)); case VECTOR_OP_RROTATE: return (v0, v1, vm) -> v0.bOp(v1, vm, (i, a, n) -> rotateRight(a, (int)n)); + case VECTOR_OP_UMAX: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (byte)VectorMath.maxUnsigned(a, b)); + case VECTOR_OP_UMIN: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (byte)VectorMath.minUnsigned(a, b)); + case VECTOR_OP_SADD: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (byte)(VectorMath.addSaturating(a, b))); + case VECTOR_OP_SSUB: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (byte)(VectorMath.subSaturating(a, b))); + case VECTOR_OP_SUADD: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (byte)(VectorMath.addSaturatingUnsigned(a, b))); + case VECTOR_OP_SUSUB: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (byte)(VectorMath.subSaturatingUnsigned(a, b))); default: return null; } } @@ -2575,6 +2600,22 @@ ByteVector selectFromTemplate(ByteVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + ByteVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final ByteVector selectFromTemplate(ByteVector v1, ByteVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), byte.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations /** diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java index 00840026fff9f..3760749264562 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java @@ -493,6 +493,13 @@ public Double128Vector selectFrom(Vector v, Double128Mask.class, (Double128Mask) m); // specialize } + @Override + @ForceInline + public Double128Vector selectFrom(Vector v1, + Vector v2) { + return (Double128Vector) + super.selectFromTemplate((Double128Vector) v1, (Double128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java index 4b42deba73841..2e31a80255091 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java @@ -493,6 +493,13 @@ public Double256Vector selectFrom(Vector v, Double256Mask.class, (Double256Mask) m); // specialize } + @Override + @ForceInline + public Double256Vector selectFrom(Vector v1, + Vector v2) { + return (Double256Vector) + super.selectFromTemplate((Double256Vector) v1, (Double256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java index c188f990c335f..6ed3dd7325c28 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java @@ -493,6 +493,13 @@ public Double512Vector selectFrom(Vector v, Double512Mask.class, (Double512Mask) m); // specialize } + @Override + @ForceInline + public Double512Vector selectFrom(Vector v1, + Vector v2) { + return (Double512Vector) + super.selectFromTemplate((Double512Vector) v1, (Double512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java index 032fa1ac277d9..2e1b21350012a 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java @@ -493,6 +493,13 @@ public Double64Vector selectFrom(Vector v, Double64Mask.class, (Double64Mask) m); // specialize } + @Override + @ForceInline + public Double64Vector selectFrom(Vector v1, + Vector v2) { + return (Double64Vector) + super.selectFromTemplate((Double64Vector) v1, (Double64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java index 7251ec82aa63c..8d69b6fcbc730 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java @@ -493,6 +493,13 @@ public DoubleMaxVector selectFrom(Vector v, DoubleMaxMask.class, (DoubleMaxMask) m); // specialize } + @Override + @ForceInline + public DoubleMaxVector selectFrom(Vector v1, + Vector v2) { + return (DoubleMaxVector) + super.selectFromTemplate((DoubleMaxVector) v1, (DoubleMaxVector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index 6cc12048d4632..d7fc2cfa97d1c 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -525,6 +525,19 @@ static DoubleVector compressHelper(Vector v, VectorMask m) { return r; } + static DoubleVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + double[] res = new double[vlen]; + double[] vecPayload1 = ((DoubleVector)indexes).vec(); + double[] vecPayload2 = ((DoubleVector)src1).vec(); + double[] vecPayload3 = ((DoubleVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((DoubleVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -2417,6 +2430,22 @@ DoubleVector selectFromTemplate(DoubleVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + DoubleVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final DoubleVector selectFromTemplate(DoubleVector v1, DoubleVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), double.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java index 2e016725f812b..79239532cc69b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java @@ -493,6 +493,13 @@ public Float128Vector selectFrom(Vector v, Float128Mask.class, (Float128Mask) m); // specialize } + @Override + @ForceInline + public Float128Vector selectFrom(Vector v1, + Vector v2) { + return (Float128Vector) + super.selectFromTemplate((Float128Vector) v1, (Float128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java index 00e6083588339..5f5a26fd316a3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java @@ -493,6 +493,13 @@ public Float256Vector selectFrom(Vector v, Float256Mask.class, (Float256Mask) m); // specialize } + @Override + @ForceInline + public Float256Vector selectFrom(Vector v1, + Vector v2) { + return (Float256Vector) + super.selectFromTemplate((Float256Vector) v1, (Float256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java index 1f2a792c52c2e..f8c191ea016e3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java @@ -493,6 +493,13 @@ public Float512Vector selectFrom(Vector v, Float512Mask.class, (Float512Mask) m); // specialize } + @Override + @ForceInline + public Float512Vector selectFrom(Vector v1, + Vector v2) { + return (Float512Vector) + super.selectFromTemplate((Float512Vector) v1, (Float512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java index 6c913ce84a9ba..9496e5988680b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java @@ -493,6 +493,13 @@ public Float64Vector selectFrom(Vector v, Float64Mask.class, (Float64Mask) m); // specialize } + @Override + @ForceInline + public Float64Vector selectFrom(Vector v1, + Vector v2) { + return (Float64Vector) + super.selectFromTemplate((Float64Vector) v1, (Float64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java index b9a0a93f91253..6f093957262aa 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java @@ -493,6 +493,13 @@ public FloatMaxVector selectFrom(Vector v, FloatMaxMask.class, (FloatMaxMask) m); // specialize } + @Override + @ForceInline + public FloatMaxVector selectFrom(Vector v1, + Vector v2) { + return (FloatMaxVector) + super.selectFromTemplate((FloatMaxVector) v1, (FloatMaxVector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index b962dc55ce351..098eed06095af 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -525,6 +525,19 @@ static FloatVector compressHelper(Vector v, VectorMask m) { return r; } + static FloatVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + float[] res = new float[vlen]; + float[] vecPayload1 = ((FloatVector)indexes).vec(); + float[] vecPayload2 = ((FloatVector)src1).vec(); + float[] vecPayload3 = ((FloatVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((FloatVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -2429,6 +2442,22 @@ FloatVector selectFromTemplate(FloatVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + FloatVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final FloatVector selectFromTemplate(FloatVector v1, FloatVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), float.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java index f7135e19cb6e2..4aa1e8044b092 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java @@ -506,6 +506,13 @@ public Int128Vector selectFrom(Vector v, Int128Mask.class, (Int128Mask) m); // specialize } + @Override + @ForceInline + public Int128Vector selectFrom(Vector v1, + Vector v2) { + return (Int128Vector) + super.selectFromTemplate((Int128Vector) v1, (Int128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java index 474ff974b3169..753f96f216ff3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java @@ -506,6 +506,13 @@ public Int256Vector selectFrom(Vector v, Int256Mask.class, (Int256Mask) m); // specialize } + @Override + @ForceInline + public Int256Vector selectFrom(Vector v1, + Vector v2) { + return (Int256Vector) + super.selectFromTemplate((Int256Vector) v1, (Int256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java index 9fec8c0c99f13..8e6ed6fc882e8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java @@ -506,6 +506,13 @@ public Int512Vector selectFrom(Vector v, Int512Mask.class, (Int512Mask) m); // specialize } + @Override + @ForceInline + public Int512Vector selectFrom(Vector v1, + Vector v2) { + return (Int512Vector) + super.selectFromTemplate((Int512Vector) v1, (Int512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java index 3b3c0723ee1a3..98cd39d9beb03 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java @@ -506,6 +506,13 @@ public Int64Vector selectFrom(Vector v, Int64Mask.class, (Int64Mask) m); // specialize } + @Override + @ForceInline + public Int64Vector selectFrom(Vector v1, + Vector v2) { + return (Int64Vector) + super.selectFromTemplate((Int64Vector) v1, (Int64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java index 5738cb7a4bc94..f301161b980af 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java @@ -506,6 +506,13 @@ public IntMaxVector selectFrom(Vector v, IntMaxMask.class, (IntMaxMask) m); // specialize } + @Override + @ForceInline + public IntMaxVector selectFrom(Vector v1, + Vector v2) { + return (IntMaxVector) + super.selectFromTemplate((IntMaxVector) v1, (IntMaxVector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index 16b5ceecba35e..6cb81767cdd60 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java @@ -536,6 +536,19 @@ static IntVector compressHelper(Vector v, VectorMask m) { return r; } + static IntVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + int[] res = new int[vlen]; + int[] vecPayload1 = ((IntVector)indexes).vec(); + int[] vecPayload2 = ((IntVector)src1).vec(); + int[] vecPayload3 = ((IntVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((IntVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -871,6 +884,18 @@ private static BinaryOperation> binaryOperations( v0.bOp(v1, vm, (i, a, n) -> rotateLeft(a, (int)n)); case VECTOR_OP_RROTATE: return (v0, v1, vm) -> v0.bOp(v1, vm, (i, a, n) -> rotateRight(a, (int)n)); + case VECTOR_OP_UMAX: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (int)VectorMath.maxUnsigned(a, b)); + case VECTOR_OP_UMIN: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (int)VectorMath.minUnsigned(a, b)); + case VECTOR_OP_SADD: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (int)(VectorMath.addSaturating(a, b))); + case VECTOR_OP_SSUB: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (int)(VectorMath.subSaturating(a, b))); + case VECTOR_OP_SUADD: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (int)(VectorMath.addSaturatingUnsigned(a, b))); + case VECTOR_OP_SUSUB: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (int)(VectorMath.subSaturatingUnsigned(a, b))); case VECTOR_OP_COMPRESS_BITS: return (v0, v1, vm) -> v0.bOp(v1, vm, (i, a, n) -> Integer.compress(a, n)); case VECTOR_OP_EXPAND_BITS: return (v0, v1, vm) -> @@ -2560,6 +2585,22 @@ IntVector selectFromTemplate(IntVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + IntVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final IntVector selectFromTemplate(IntVector v1, IntVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), int.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations /** diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java index 567789627c6cb..c65816a4d6c88 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java @@ -496,6 +496,13 @@ public Long128Vector selectFrom(Vector v, Long128Mask.class, (Long128Mask) m); // specialize } + @Override + @ForceInline + public Long128Vector selectFrom(Vector v1, + Vector v2) { + return (Long128Vector) + super.selectFromTemplate((Long128Vector) v1, (Long128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java index 5ef0f121464f6..7ca3e43e92b87 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java @@ -496,6 +496,13 @@ public Long256Vector selectFrom(Vector v, Long256Mask.class, (Long256Mask) m); // specialize } + @Override + @ForceInline + public Long256Vector selectFrom(Vector v1, + Vector v2) { + return (Long256Vector) + super.selectFromTemplate((Long256Vector) v1, (Long256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java index acdb471609f22..317cac1f11085 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java @@ -496,6 +496,13 @@ public Long512Vector selectFrom(Vector v, Long512Mask.class, (Long512Mask) m); // specialize } + @Override + @ForceInline + public Long512Vector selectFrom(Vector v1, + Vector v2) { + return (Long512Vector) + super.selectFromTemplate((Long512Vector) v1, (Long512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java index 627f7437367cb..b13712595dbdd 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java @@ -496,6 +496,13 @@ public Long64Vector selectFrom(Vector v, Long64Mask.class, (Long64Mask) m); // specialize } + @Override + @ForceInline + public Long64Vector selectFrom(Vector v1, + Vector v2) { + return (Long64Vector) + super.selectFromTemplate((Long64Vector) v1, (Long64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java index aec3bb89fcd02..9edc442be88ac 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java @@ -496,6 +496,13 @@ public LongMaxVector selectFrom(Vector v, LongMaxMask.class, (LongMaxMask) m); // specialize } + @Override + @ForceInline + public LongMaxVector selectFrom(Vector v1, + Vector v2) { + return (LongMaxVector) + super.selectFromTemplate((LongMaxVector) v1, (LongMaxVector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 15ac2bc7b7f6c..a740c9d49cf83 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -536,6 +536,19 @@ static LongVector compressHelper(Vector v, VectorMask m) { return r; } + static LongVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + long[] res = new long[vlen]; + long[] vecPayload1 = ((LongVector)indexes).vec(); + long[] vecPayload2 = ((LongVector)src1).vec(); + long[] vecPayload3 = ((LongVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((LongVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -829,6 +842,18 @@ private static BinaryOperation> binaryOperations(in v0.bOp(v1, vm, (i, a, n) -> rotateLeft(a, (int)n)); case VECTOR_OP_RROTATE: return (v0, v1, vm) -> v0.bOp(v1, vm, (i, a, n) -> rotateRight(a, (int)n)); + case VECTOR_OP_UMAX: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (long)VectorMath.maxUnsigned(a, b)); + case VECTOR_OP_UMIN: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (long)VectorMath.minUnsigned(a, b)); + case VECTOR_OP_SADD: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (long)(VectorMath.addSaturating(a, b))); + case VECTOR_OP_SSUB: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (long)(VectorMath.subSaturating(a, b))); + case VECTOR_OP_SUADD: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (long)(VectorMath.addSaturatingUnsigned(a, b))); + case VECTOR_OP_SUSUB: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (long)(VectorMath.subSaturatingUnsigned(a, b))); case VECTOR_OP_COMPRESS_BITS: return (v0, v1, vm) -> v0.bOp(v1, vm, (i, a, n) -> Long.compress(a, n)); case VECTOR_OP_EXPAND_BITS: return (v0, v1, vm) -> @@ -2426,6 +2451,22 @@ LongVector selectFromTemplate(LongVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + LongVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final LongVector selectFromTemplate(LongVector v1, LongVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), long.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations /** diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java index fe34886512a13..b013e4b282586 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java @@ -506,6 +506,13 @@ public Short128Vector selectFrom(Vector v, Short128Mask.class, (Short128Mask) m); // specialize } + @Override + @ForceInline + public Short128Vector selectFrom(Vector v1, + Vector v2) { + return (Short128Vector) + super.selectFromTemplate((Short128Vector) v1, (Short128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java index 243e24ad26bef..af4c862eaf3b6 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java @@ -506,6 +506,13 @@ public Short256Vector selectFrom(Vector v, Short256Mask.class, (Short256Mask) m); // specialize } + @Override + @ForceInline + public Short256Vector selectFrom(Vector v1, + Vector v2) { + return (Short256Vector) + super.selectFromTemplate((Short256Vector) v1, (Short256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java index 4114783608960..3bb019f3b7cbf 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java @@ -506,6 +506,13 @@ public Short512Vector selectFrom(Vector v, Short512Mask.class, (Short512Mask) m); // specialize } + @Override + @ForceInline + public Short512Vector selectFrom(Vector v1, + Vector v2) { + return (Short512Vector) + super.selectFromTemplate((Short512Vector) v1, (Short512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java index d80d4c4e2ec52..905e313e95c1c 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java @@ -506,6 +506,13 @@ public Short64Vector selectFrom(Vector v, Short64Mask.class, (Short64Mask) m); // specialize } + @Override + @ForceInline + public Short64Vector selectFrom(Vector v1, + Vector v2) { + return (Short64Vector) + super.selectFromTemplate((Short64Vector) v1, (Short64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java index 799483a667590..5bb1beee6edd2 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java @@ -506,6 +506,13 @@ public ShortMaxVector selectFrom(Vector v, ShortMaxMask.class, (ShortMaxMask) m); // specialize } + @Override + @ForceInline + public ShortMaxVector selectFrom(Vector v1, + Vector v2) { + return (ShortMaxVector) + super.selectFromTemplate((ShortMaxVector) v1, (ShortMaxVector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index fb0512fd5b9ea..0e3ff9aaa8776 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -536,6 +536,19 @@ static ShortVector compressHelper(Vector v, VectorMask m) { return r; } + static ShortVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + short[] res = new short[vlen]; + short[] vecPayload1 = ((ShortVector)indexes).vec(); + short[] vecPayload2 = ((ShortVector)src1).vec(); + short[] vecPayload3 = ((ShortVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((ShortVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -871,6 +884,18 @@ private static BinaryOperation> binaryOperations( v0.bOp(v1, vm, (i, a, n) -> rotateLeft(a, (int)n)); case VECTOR_OP_RROTATE: return (v0, v1, vm) -> v0.bOp(v1, vm, (i, a, n) -> rotateRight(a, (int)n)); + case VECTOR_OP_UMAX: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (short)VectorMath.maxUnsigned(a, b)); + case VECTOR_OP_UMIN: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (short)VectorMath.minUnsigned(a, b)); + case VECTOR_OP_SADD: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (short)(VectorMath.addSaturating(a, b))); + case VECTOR_OP_SSUB: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (short)(VectorMath.subSaturating(a, b))); + case VECTOR_OP_SUADD: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (short)(VectorMath.addSaturatingUnsigned(a, b))); + case VECTOR_OP_SUSUB: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> (short)(VectorMath.subSaturatingUnsigned(a, b))); default: return null; } } @@ -2576,6 +2601,22 @@ ShortVector selectFromTemplate(ShortVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + ShortVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final ShortVector selectFromTemplate(ShortVector v1, ShortVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), short.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations /** diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java index fda073f686389..5b6dd3d09ac10 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java @@ -2756,6 +2756,61 @@ public abstract VectorMask compare(VectorOperators.Comparison op, */ public abstract Vector selectFrom(Vector v); + /** + * Using values stored in the lanes of this vector, + * assemble values stored in the second vector {@code v1} + * and third vector {@code v2}. The second and third vectors thus + * serve as a table, whose elements are selected by indexes + * in this vector. + * + * This is a cross-lane operation that rearranges the lane + * elements of the argument vectors, under the control of + * this vector. + * + * For each lane {@code N} of this vector, and for each lane + * value {@code I=wrapIndex(this.lane(N)} in this vector, + * the output lane {@code N} obtains the value from + * the second vector at lane {@code I} if {@code I < VLENGTH}. + * Otherwise, the output lane {@code N} obtains the value from + * the third vector at lane {@code I - VLENGTH}. + * + * Here, {@code VLENGTH} is the result of {@code this.length()}, + * and for integral values {@code wrapIndex} computes the result of + * {@code Math.floorMod(E, 2 * VLENGTH)}, where {@code E} is the index + * to be wrapped. As long as {@code VLENGTH} is a power of two, then the + * result is also equal to {@code E & (2 * VLENGTH - 1)}. + * + * For floating point values {@code wrapIndex} computes + * {@code Math.floorMod(convert(E), 2 * VLENGTH)}, where {@code convert} + * converts the floating point value to an integral value with the same + * number of representational bits - as in converting a double value to + * a long value ({@code (long)doubleVal}), or a float value to an int value + * ({@code (int)floatVal}). + * + * In this way, the result contains only values stored in the + * argument vectors {@code v1} and {@code v2}, but presented in + * an order which depends on the index values in {@code this}. + * + * The result for integral values is the same as the expression + * {@snippet lang=java : + * v1.rearrange( + * this.lanewise(VectorOperators.AND, 2 * VLENGTH - 1).toShuffle(), + * v2) + * } + * when {@code VLENGTH} is a power of two. + * The lane-wise {@code AND} operation results in a vector whose + * elements are in the range {@code [0, 2 * VLENGTH - 1])}. The shuffle + * conversion results in a partially wrapped shuffle whose indexes are + * in the range {@code [-VLENGTH, VLENGTH - 1])}, where exceptional + * indexes are used to select elements in the third vector. + * + * @param v1 the first input vector + * @param v2 the second input vector + * @return the rearrangement of lane elements of {@code v1} and {@code v2} + * @see #rearrange(VectorShuffle,Vector) + */ + public abstract Vector selectFrom(Vector v1, Vector v2); + /** * Using index values stored in the lanes of this vector, * assemble values stored in second vector, under the control diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMath.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMath.java new file mode 100644 index 0000000000000..0d590d2d49ae1 --- /dev/null +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMath.java @@ -0,0 +1,586 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.incubator.vector; + +/** + * The class {@code VectorMath} contains methods for performing + * scalar numeric operations in support of vector numeric operations. + * @since 24 + */ +public final class VectorMath { + + private VectorMath() { + } + + /** + * Returns the smaller of two {@code long} values numerically treating + * the values as unsigned. That is, the result is the operand closer + * to the value of the expression {@code 0L}. If the operands have the + * same value, the result is that same value. + * + * @param a the first operand. + * @param b the second operand. + * @return the smaller of {@code a} and {@code b}. + * @see VectorOperators#UMIN + */ + public static long minUnsigned(long a, long b) { + return Long.compareUnsigned(a, b) < 0 ? a : b; + } + + /** + * Returns the greater of two {@code long} values numerically treating + * the values as unsigned. That is, the result is the operand closer + * to the value of the expression {@code 0xFFFFFFFF_FFFFFFFFL} numerically + * treating it as unsigned. If the operands have the same value, + * the result is that same value. + * + * @param a the first operand. + * @param b the second operand. + * @return the larger of {@code a} and {@code b}. + * @see VectorOperators#UMAX + */ + public static long maxUnsigned(long a, long b) { + return Long.compareUnsigned(a, b) > 0 ? a : b; + } + + /** + * Adds two {@code long} values using saturation + * arithemetic. The lower and upper (inclusive) bounds are + * {@code Long.MIN_VALUE} and {@code Long.MAX_VALUE}, respectively. + *

            + * If the result of the addition would otherwise overflow from + * a positive value to a negative value then the result is clamped + * to the upper bound {@code Long.MAX_VALUE}. + * If the result of the addition would otherwise underflow from + * a negative value to a positive value then the result is clamped + * to lower bound {@code Long.MIN_VALUE}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating addition of the operands. + * @see VectorOperators#SADD + */ + public static long addSaturating(long a, long b) { + long res = a + b; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((a ^ res) & (b ^ res)) < 0) { + return res < 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } else { + return res; + } + } + + /** + * Subtracts two {@code long} values using saturation + * arithemetic. The lower and upper (inclusive) bounds are + * {@code Long.MIN_VALUE} and {@code Long.MAX_VALUE}, respectively. + *

            + * If the result of the subtraction would otherwise overflow from + * a positive value to a negative value then the result is clamped + * to the upper bound {@code Long.MAX_VALUE}. + * If the result of the subtraction would otherwise underflow from + * a negative value to a positive value then the result is clamped + * to lower bound {@code Long.MIN_VALUE}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating difference of the operands. + * @see VectorOperators#SSUB + */ + public static long subSaturating(long a, long b) { + long res = a - b; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different from the sign of a + if (((a ^ b) & (a ^ res)) < 0) { + return a < 0 ? Long.MIN_VALUE : Long.MAX_VALUE; + } else { + return res; + } + } + + /** + * Adds two {@code long} values using saturation + * arithemetic and numerically treating the values + * as unsigned. The lower and upper (inclusive) bounds + * are {@code 0L} and {@code 0xFFFFFFFF_FFFFFFFFL}, respectively, + * numerically treating them as unsigned. + *

            + * If the result of the unsigned addition would otherwise overflow + * from the greater of the two operands to a lesser value then the + * result is clamped to the upper bound {@code 0xFFFFFFFF_FFFFFFFFL}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating addition of the operands. + * @see VectorOperators#SUADD + */ + public static long addSaturatingUnsigned(long a, long b) { + long res = a + b; + boolean overflow = Long.compareUnsigned(res, (a | b)) < 0; + if (overflow) { + return -1L; + } else { + return res; + } + } + + /** + * Subtracts two {@code long} values using saturation + * arithemetic and numerically treating the values + * as unsigned. The lower and upper (inclusive) bounds + * are {@code 0L} and {@code 0xFFFFFFFF_FFFFFFFFL}, respectively, + * numerically treating them as unsigned. + *

            + * If the result of the unsigned subtraction would otherwise underflow + * from the lesser of the two operands to a greater value then the + * result is clamped to the lower bound {@code 0L}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating difference of the operands. + * @see VectorOperators#SUSUB + */ + public static long subSaturatingUnsigned(long a, long b) { + if (Long.compareUnsigned(b, a) < 0) { + return a - b; + } else { + return 0; + } + } + + + /** + * Returns the smaller of two {@code int} values numerically treating + * the values as unsigned. That is, the result is the operand closer + * to the value of the expression {@code 0}. If the operands have the + * same value, the result is that same value. + * + * @param a the first operand. + * @param b the second operand. + * @return the smaller of {@code a} and {@code b}. + * @see VectorOperators#UMIN + */ + public static int minUnsigned(int a, int b) { + return Integer.compareUnsigned(a, b) < 0 ? a : b; + } + + /** + * Returns the greater of two {@code int} values numerically treating + * the values as unsigned. That is, the result is the operand closer + * to the value of the expression {@code 0xFFFFFFFF} numerically + * treating it as unsigned. If the operands have the same value, + * the result is that same value. + * + * @param a the first operand. + * @param b the second operand. + * @return the larger of {@code a} and {@code b}. + * @see VectorOperators#UMAX + */ + public static int maxUnsigned(int a, int b) { + return Integer.compareUnsigned(a, b) > 0 ? a : b; + } + + /** + * Adds two {@code int} values using saturation + * arithemetic. The lower and upper (inclusive) bounds are + * {@code Integer.MIN_VALUE} and {@code Integer.MAX_VALUE}, respectively. + *

            + * If the result of the addition would otherwise overflow from + * a positive value to a negative value then the result is clamped + * to the upper bound {@code Integer.MAX_VALUE}. + * If the result of the addition would otherwise underflow from + * a negative value to a positive value then the result is clamped + * to lower bound {@code Integer.MIN_VALUE}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating addition of the operands. + * @see VectorOperators#SADD + */ + public static int addSaturating(int a, int b) { + long res = (long)a + (long)b; + if (res > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else if (res < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } else { + return (int)res; + } + } + + /** + * Subtracts two {@code int} values using saturation + * arithemetic. The lower and upper (inclusive) bounds are + * {@code Integer.MIN_VALUE} and {@code Integer.MAX_VALUE}, respectively. + *

            + * If the result of the subtraction would otherwise overflow from + * a positive value to a negative value then the result is clamped + * to the upper bound {@code Integer.MAX_VALUE}. + * If the result of the subtraction would otherwise underflow from + * a negative value to a positive value then the result is clamped + * to lower bound {@code Integer.MIN_VALUE}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating difference of the operands. + * @see VectorOperators#SSUB + */ + public static int subSaturating(int a, int b) { + long res = (long)a - (long)b; + if (res > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else if (res < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } else { + return (int)res; + } + } + + /** + * Adds two {@code int} values using saturation + * arithemetic and numerically treating the values + * as unsigned. The lower and upper (inclusive) bounds + * are {@code 0} and {@code 0xFFFFFFFF}, respectively, + * numerically treating them as unsigned. + *

            + * If the result of the unsigned addition would otherwise overflow + * from the greater of the two operands to a lesser value then the + * result is clamped to the upper bound {@code 0xFFFFFFFF}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating addition of the operands. + * @see VectorOperators#SUADD + */ + public static int addSaturatingUnsigned(int a, int b) { + int res = a + b; + boolean overflow = Integer.compareUnsigned(res, (a | b)) < 0; + if (overflow) { + return -1; + } else { + return res; + } + } + + /** + * Subtracts two {@code int} values using saturation + * arithemetic and numerically treating the values + * as unsigned. The lower and upper (inclusive) bounds + * are {@code 0} and {@code -0xFFFFFFFF}, respectively, + * numerically treating them as unsigned. + *

            + * If the result of the unsigned subtraction would otherwise underflow + * from the lesser of the two operands to a greater value then the + * result is clamped to the lower bound {@code 0}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating difference of the operands. + * @see VectorOperators#SUSUB + */ + public static int subSaturatingUnsigned(int a, int b) { + if (Integer.compareUnsigned(b, a) < 0) { + return a - b; + } else { + return 0; + } + } + + + /** + * Returns the smaller of two {@code short} values numerically treating + * the values as unsigned. That is, the result is the operand closer + * to the value of the expression {@code 0}. If the operands have the + * same value, the result is that same value. + * + * @param a the first operand. + * @param b the second operand. + * @return the smaller of {@code a} and {@code b}. + * @see VectorOperators#UMIN + */ + public static short minUnsigned(short a, short b) { + return Short.compareUnsigned(a, b) < 0 ? a : b; + } + + /** + * Returns the greater of two {@code short} values numerically treating + * the values as unsigned. That is, the result is the operand closer + * to the value of the expression {@code 0xFFFF} numerically + * treating it as unsigned. If the operands have the same value, + * the result is that same value. + * + * @param a the first operand. + * @param b the second operand. + * @return the larger of {@code a} and {@code b}. + * @see VectorOperators#UMAX + */ + public static short maxUnsigned(short a, short b) { + return Short.compareUnsigned(a, b) > 0 ? a : b; + } + + /** + * Adds two {@code short} values using saturation + * arithemetic. The lower and upper (inclusive) bounds are + * {@code Short.MIN_VALUE} and {@code Short.MAX_VALUE}, respectively. + *

            + * If the result of the addition would otherwise overflow from + * a positive value to a negative value then the result is clamped + * to the upper bound {@code Short.MAX_VALUE}. + * If the result of the addition would otherwise underflow from + * a negative value to a positive value then the result is clamped + * to lower bound {@code Short.MIN_VALUE}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating addition of the operands. + * @see VectorOperators#SADD + */ + public static short addSaturating(short a, short b) { + int res = a + b; + if (res > Short.MAX_VALUE) { + return Short.MAX_VALUE; + } else if (res < Short.MIN_VALUE) { + return Short.MIN_VALUE; + } else { + return (short)res; + } + } + + /** + * Subtracts two {@code short} values using saturation + * arithemetic. The lower and upper (inclusive) bounds are + * {@code Short.MIN_VALUE} and {@code Short.MAX_VALUE}, respectively. + *

            + * If the result of the subtraction would otherwise overflow from + * a positive value to a negative value then the result is clamped + * to the upper bound {@code Short.MAX_VALUE}. + * If the result of the subtraction would otherwise underflow from + * a negative value to a positive value then the result is clamped + * to lower bound {@code Short.MIN_VALUE}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating difference of the operands. + * @see VectorOperators#SSUB + */ + public static short subSaturating(short a, short b) { + int res = a - b; + if (res > Short.MAX_VALUE) { + return Short.MAX_VALUE; + } else if (res < Short.MIN_VALUE) { + return Short.MIN_VALUE; + } else { + return (short)res; + } + } + + /** + * Adds two {@code short} values using saturation + * arithemetic and numerically treating the values + * as unsigned. The lower and upper (inclusive) bounds + * are {@code 0} and {@code 0xFFFF}, respectively, + * numerically treating them as unsigned. + *

            + * If the result of the unsigned addition would otherwise overflow + * from the greater of the two operands to a lesser value then the + * result is clamped to the upper bound {@code 0xFFFF}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating addition of the operands. + * @see VectorOperators#SUADD + */ + public static short addSaturatingUnsigned(short a, short b) { + short res = (short)(a + b); + boolean overflow = Short.compareUnsigned(res, (short)(a | b)) < 0; + if (overflow) { + return (short)(-1); + } else { + return res; + } + } + + /** + * Subtracts two {@code short} values using saturation + * arithemetic and numerically treating the values + * as unsigned. The lower and upper (inclusive) bounds + * are {@code 0} and {@code 0xFFFF}, respectively, + * numerically treating them as unsigned. + *

            + * If the result of the unsigned subtraction would otherwise underflow + * from the lesser of the two operands to a greater value then the + * result is clamped to the lower bound {@code 0}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating difference of the operands. + * @see VectorOperators#SUSUB + */ + public static short subSaturatingUnsigned(short a, short b) { + if (Short.compareUnsigned(b, a) < 0) { + return (short)(a - b); + } else { + return 0; + } + } + + + /** + * Returns the smaller of two {@code byte} values numerically treating + * the values as unsigned. That is, the result is the operand closer + * to the value of the expression {@code 0}. If the operands have the + * same value, the result is that same value. + * + * @param a the first operand. + * @param b the second operand. + * @return the smaller of {@code a} and {@code b}. + * @see VectorOperators#UMIN + */ + public static byte minUnsigned(byte a, byte b) { + return Byte.compareUnsigned(a, b) < 0 ? a : b; + } + + /** + * Returns the greater of two {@code byte} values numerically treating + * the values as unsigned. That is, the result is the operand closer + * to the value of the expression {@code 0xFF} numerically + * treating it as unsigned. If the operands have the same value, + * the result is that same value. + * + * @param a the first operand. + * @param b the second operand. + * @return the larger of {@code a} and {@code b}. + * @see VectorOperators#UMAX + */ + public static byte maxUnsigned(byte a, byte b) { + return Byte.compareUnsigned(a, b) > 0 ? a : b; + } + + /** + * Adds two {@code byte} values using saturation + * arithemetic. The lower and upper (inclusive) bounds are + * {@code Byte.MIN_VALUE} and {@code Byte.MAX_VALUE}, respectively. + *

            + * If the result of the addition would otherwise overflow from + * a positive value to a negative value then the result is clamped + * to the upper bound {@code Byte.MAX_VALUE}. + * If the result of the addition would otherwise underflow from + * a negative value to a positive value then the result is clamped + * to lower bound {@code Byte.MIN_VALUE}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating addition of the operands. + * @see VectorOperators#SADD + */ + public static byte addSaturating(byte a, byte b) { + int res = a + b; + if (res > Byte.MAX_VALUE) { + return Byte.MAX_VALUE; + } else if (res < Byte.MIN_VALUE) { + return Byte.MIN_VALUE; + } else { + return (byte)res; + } + } + + /** + * Subtracts two {@code byte} values using saturation + * arithemetic. The lower and upper (inclusive) bounds are + * {@code Byte.MIN_VALUE} and {@code Byte.MAX_VALUE}, respectively. + *

            + * If the result of the subtraction would otherwise overflow from + * a positive value to a negative value then the result is clamped + * to the upper bound {@code Byte.MAX_VALUE}. + * If the result of the subtraction would otherwise underflow from + * a negative value to a positive value then the result is clamped + * to lower bound {@code Byte.MIN_VALUE}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating difference of the operands. + * @see VectorOperators#SSUB + */ + public static byte subSaturating(byte a, byte b) { + int res = a - b; + if (res > Byte.MAX_VALUE) { + return Byte.MAX_VALUE; + } else if (res < Byte.MIN_VALUE) { + return Byte.MIN_VALUE; + } else { + return (byte)res; + } + } + + /** + * Adds two {@code byte} values using saturation + * arithemetic and numerically treating the values + * as unsigned. The lower and upper (inclusive) bounds + * are {@code 0} and {@code 0xFF}, respectively, + * numerically treating them as unsigned. + *

            + * If the result of the unsigned addition would otherwise overflow + * from the greater of the two operands to a lesser value then the + * result is clamped to the upper bound {@code 0xFF}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating addition of the operands. + * @see VectorOperators#SUADD + */ + public static byte addSaturatingUnsigned(byte a, byte b) { + byte res = (byte)(a + b); + boolean overflow = Byte.compareUnsigned(res, (byte)(a | b)) < 0; + if (overflow) { + return (byte)(-1); + } else { + return res; + } + } + + /** + * Subtracts two {@code byte} values using saturation + * arithemetic and numerically treating the values + * as unsigned. The lower and upper (inclusive) bounds + * are {@code 0} and {@code 0xFF}, respectively, + * numerically treating them as unsigned. + *

            + * If the result of the unsigned subtraction would otherwise underflow + * from the lesser of the two operands to a greater value then the + * result is clamped to the lower bound {@code 0}. + * + * @param a the first operand. + * @param b the second operand. + * @return the saturating difference of the operands. + * @see VectorOperators#SUSUB + */ + public static byte subSaturatingUnsigned(byte a, byte b) { + if (Byte.compareUnsigned(b, a) < 0) { + return (byte)(a - b); + } else { + return 0; + } + } +} diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java index 507fe84bfbad3..fa70d65c74251 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.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 @@ -563,9 +563,36 @@ static boolean opKind(Operator op, int bit) { public static final /*bitwise*/ Associative OR = assoc("OR", "|", VectorSupport.VECTOR_OP_OR, VO_NOFP+VO_ASSOC); /*package-private*/ /** Version of OR which works on float and double too. */ static final Associative OR_UNCHECKED = assoc("OR_UNCHECKED", "|", VectorSupport.VECTOR_OP_OR, VO_ASSOC+VO_PRIVATE); + /** Produce {@code a^b}. Integral only. */ public static final /*bitwise*/ Associative XOR = assoc("XOR", "^", VectorSupport.VECTOR_OP_XOR, VO_NOFP+VO_ASSOC); + /** Produce saturating {@code a+b}. Integral only. + * @see VectorMath#addSaturating(int, int) + */ + public static final Binary SADD = binary("SADD", "+", VectorSupport.VECTOR_OP_SADD, VO_NOFP); + /** Produce saturating unsigned {@code a+b}. Integral only. + * @see VectorMath#addSaturatingUnsigned(int, int) + */ + public static final Binary SUADD = binary("SUADD", "+", VectorSupport.VECTOR_OP_SUADD, VO_NOFP); + /** Produce saturating {@code a-b}. Integral only. + * @see VectorMath#subSaturating(int, int) + */ + public static final Binary SSUB = binary("SSUB", "-", VectorSupport.VECTOR_OP_SSUB, VO_NOFP); + /** Produce saturating unsigned {@code a-b}. Integral only. + * @see VectorMath#subSaturatingUnsigned(int, int) + */ + public static final Binary SUSUB = binary("SUSUB", "-", VectorSupport.VECTOR_OP_SUSUB, VO_NOFP); + /** Produce unsigned {@code min(a,b)}. Integral only. + * @see VectorMath#minUnsigned(int, int) (int, int) + */ + public static final Associative UMIN = assoc("UMIN", "umin", VectorSupport.VECTOR_OP_UMIN, VO_NOFP+VO_ASSOC); + /** Produce unsigned {@code max(a,b)}. Integral only. + * @see VectorMath#maxUnsigned(int, int) (int, int) + */ + public static final Associative UMAX = assoc("UMAX", "umax", VectorSupport.VECTOR_OP_UMAX, VO_NOFP+VO_ASSOC); + + /** Produce {@code a<<(n&(ESIZE*8-1))}. Integral only. */ public static final /*bitwise*/ Binary LSHL = binary("LSHL", "<<", VectorSupport.VECTOR_OP_LSHIFT, VO_SHIFT); /** Produce {@code a>>(n&(ESIZE*8-1))}. Integral only. */ @@ -635,22 +662,22 @@ static boolean opKind(Operator op, int bit) { * @see java.lang.Integer#compareUnsigned * @see java.lang.Long#compareUnsigned */ - public static final Comparison UNSIGNED_LT = compare("UNSIGNED_LT", "<", VectorSupport.BT_ult, VO_NOFP); + public static final Comparison ULT = compare("ULT", "<", VectorSupport.BT_ult, VO_NOFP); /** Unsigned compare {@code a<=b}. Integral only. * @see java.lang.Integer#compareUnsigned * @see java.lang.Long#compareUnsigned */ - public static final Comparison UNSIGNED_LE = compare("UNSIGNED_LE", "<=", VectorSupport.BT_ule, VO_NOFP); + public static final Comparison ULE = compare("ULE", "<=", VectorSupport.BT_ule, VO_NOFP); /** Unsigned compare {@code a>b}. Integral only. * @see java.lang.Integer#compareUnsigned * @see java.lang.Long#compareUnsigned */ - public static final Comparison UNSIGNED_GT = compare("UNSIGNED_GT", ">", VectorSupport.BT_ugt, VO_NOFP); + public static final Comparison UGT = compare("UGT", ">", VectorSupport.BT_ugt, VO_NOFP); /** Unsigned compare {@code a>=b}. Integral only. * @see java.lang.Integer#compareUnsigned * @see java.lang.Long#compareUnsigned */ - public static final Comparison UNSIGNED_GE = compare("UNSIGNED_GE", ">=", VectorSupport.BT_uge, VO_NOFP); + public static final Comparison UGE = compare("UGE", ">=", VectorSupport.BT_uge, VO_NOFP); // Conversion operators diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index fcc128ea8c7b0..b5f3a4b7d8707 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -550,6 +550,19 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { return r; } + static $abstractvectortype$ selectFromTwoVectorHelper(Vector<$Boxtype$> indexes, Vector<$Boxtype$> src1, Vector<$Boxtype$> src2) { + int vlen = indexes.length(); + $type$[] res = new $type$[vlen]; + $type$[] vecPayload1 = (($abstractvectortype$)indexes).vec(); + $type$[] vecPayload2 = (($abstractvectortype$)src1).vec(); + $type$[] vecPayload3 = (($abstractvectortype$)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return (($abstractvectortype$)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -967,6 +980,18 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { v0.bOp(v1, vm, (i, a, n) -> rotateLeft(a, (int)n)); case VECTOR_OP_RROTATE: return (v0, v1, vm) -> v0.bOp(v1, vm, (i, a, n) -> rotateRight(a, (int)n)); + case VECTOR_OP_UMAX: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> ($type$)VectorMath.maxUnsigned(a, b)); + case VECTOR_OP_UMIN: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> ($type$)VectorMath.minUnsigned(a, b)); + case VECTOR_OP_SADD: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> ($type$)(VectorMath.addSaturating(a, b))); + case VECTOR_OP_SSUB: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> ($type$)(VectorMath.subSaturating(a, b))); + case VECTOR_OP_SUADD: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> ($type$)(VectorMath.addSaturatingUnsigned(a, b))); + case VECTOR_OP_SUSUB: return (v0, v1, vm) -> + v0.bOp(v1, vm, (i, a, b) -> ($type$)(VectorMath.subSaturatingUnsigned(a, b))); #if[intOrLong] case VECTOR_OP_COMPRESS_BITS: return (v0, v1, vm) -> v0.bOp(v1, vm, (i, a, n) -> $Boxtype$.compress(a, n)); @@ -2952,6 +2977,22 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + $abstractvectortype$ selectFrom(Vector<$Boxtype$> v1, Vector<$Boxtype$> v2); + + + /*package-private*/ + @ForceInline + final $abstractvectortype$ selectFromTemplate($abstractvectortype$ v1, $abstractvectortype$ v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), $type$.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations #if[BITWISE] diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template index 483962b4e0670..9752a795ea79d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template @@ -512,6 +512,13 @@ final class $vectortype$ extends $abstractvectortype$ { $masktype$.class, ($masktype$) m); // specialize } + @Override + @ForceInline + public $vectortype$ selectFrom(Vector<$Boxtype$> v1, + Vector<$Boxtype$> v2) { + return ($vectortype$) + super.selectFromTemplate(($vectortype$) v1, ($vectortype$) v2); // specialize + } #if[FP] @ForceInline diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java index f0ca7a2fc2359..eda1eada737b3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java @@ -256,6 +256,7 @@ public enum CPUFeature implements CPUFeatureName { AVX512_IFMA, AVX_IFMA, APX_F, + SHA512, } private final EnumSet features; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerThreadCanCallJavaScope.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerThreadCanCallJavaScope.java new file mode 100644 index 0000000000000..ff346fa94bcd8 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerThreadCanCallJavaScope.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. + */ +package jdk.vm.ci.hotspot; + +/** + * Scope used to potentially change whether the current thread can make VM-to-Java calls. + * A scope is exited by the {@link #close()} method so it should be used in a + * try-with-resources statement. + * + * The scope does nothing if the current thread is not a HotSpot VM CompilerThread + * for a JVMCI compiler. + */ +public class CompilerThreadCanCallJavaScope implements AutoCloseable { + + /** + * Thread state used during the scope. + */ + private final boolean state; + + /** + * Non-null iff the thread state needs resetting in {@link #close()}. + */ + private final CompilerToVM vm; + + /** + * The thread on which the constructor was called. + */ + private final Thread thread; + + /** + * Opens a scope to allow/disallow the current thread to make VM-to-Java calls. + * The scope is a no-op if the current thread is not a HotSpot VM CompilerThread + * for a JVMCI compiler. + * + * @param newState true/false to allow/disallow VM-to-Java calls within the scope + */ + public CompilerThreadCanCallJavaScope(boolean newState) { + this.state = newState; + this.thread = Thread.currentThread(); + CompilerToVM vm = HotSpotJVMCIRuntime.runtime().getCompilerToVM(); + if (vm.updateCompilerThreadCanCallJava(newState)) { + this.vm = vm; + } else { + this.vm = null; + } + } + + /** + * Resets the state of the current thread with respect to whether it can make + * VM-to-Java calls to what it was before the constructor was called. + * + * @throws IllegalStateException if called on a different thread than the constructor + */ + @Override + public void close() { + if (this.thread != Thread.currentThread()) { + throw new IllegalStateException(); + } + + if (vm != null) { + vm.updateCompilerThreadCanCallJava(!state); + } + } +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index 593697545266d..12c6dfd3f9dcd 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -1514,4 +1514,12 @@ void getOopMapAt(HotSpotResolvedJavaMethodImpl method, int bci, long[] oopMap) { } native void getOopMapAt(HotSpotResolvedJavaMethodImpl method, long methodPointer, int bci, long[] oopMap); + + /** + * If the current thread is a CompilerThread associated with a JVMCI compiler where + * newState != CompilerThread::_can_call_java, then _can_call_java is set to newState. + * + * @returns false if no change was made, otherwise true + */ + native boolean updateCompilerThreadCanCallJava(boolean newState); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java index cc553a39f89ba..8385aaa6560e1 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java @@ -51,13 +51,17 @@ private DirectHotSpotObjectConstantImpl(Object object, boolean compressed) { @Override public JavaConstant compress() { - assert !compressed; + if (compressed) { + throw new IllegalArgumentException("already compressed: " + this); + } return new DirectHotSpotObjectConstantImpl(object, true); } @Override public JavaConstant uncompress() { - assert compressed; + if (!compressed) { + throw new IllegalArgumentException("not compressed: " + this); + } return new DirectHotSpotObjectConstantImpl(object, false); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java index 7c6d94bba999a..0becdf299765d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java @@ -51,9 +51,14 @@ public boolean isCompressed() { return true; } + @Override + public boolean isCompressible() { + return false; + } + @Override public Constant compress() { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("not compressible"); } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstant.java index ee4cb7bb397d0..e0ae6b4c881f3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstant.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstant.java @@ -25,13 +25,34 @@ import jdk.vm.ci.meta.Constant; /** - * Marker interface for hotspot specific constants. + * A value in a space managed by Hotspot (e.g. heap or metaspace). + * Some of these values can be referenced with a compressed pointer + * instead of a full word-sized pointer. */ public interface HotSpotConstant extends Constant { + /** + * Determines if this constant is compressed. + */ boolean isCompressed(); + /** + * Determines if this constant is compressible. + */ + boolean isCompressible(); + + /** + * Gets a compressed version of this uncompressed constant. + * + * @throws IllegalArgumentException if this constant is not compressible + */ Constant compress(); + /** + * Gets an uncompressed version of this compressed constant. + * + * @throws IllegalArgumentException if this is an uncompressed constant + * or this constant is not compressible + */ Constant uncompress(); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java index b819eaf748448..358441d0b2282 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java @@ -43,6 +43,9 @@ static MetaspaceObject getMetaspaceObject(Constant constant) { private HotSpotMetaspaceConstantImpl(MetaspaceObject metaspaceObject, boolean compressed) { this.metaspaceObject = metaspaceObject; this.compressed = compressed; + if (compressed && !canBeStoredInCompressibleMetaSpace()) { + throw new IllegalArgumentException("constant cannot be compressed: " + metaspaceObject); + } } @Override @@ -83,9 +86,28 @@ public boolean isCompressed() { return compressed; } + @Override + public boolean isCompressible() { + if (compressed) { + return false; + } + return canBeStoredInCompressibleMetaSpace(); + } + + private boolean canBeStoredInCompressibleMetaSpace() { + if (metaspaceObject instanceof HotSpotResolvedJavaType t && !t.isArray()) { + // As of JDK-8338526, interface and abstract types are not stored + // in compressible metaspace. + return !t.isInterface() && !t.isAbstract(); + } + return true; + } + @Override public Constant compress() { - assert !isCompressed(); + if (compressed) { + throw new IllegalArgumentException("already compressed: " + this); + } HotSpotMetaspaceConstantImpl res = HotSpotMetaspaceConstantImpl.forMetaspaceObject(metaspaceObject, true); assert res.isCompressed(); return res; @@ -93,7 +115,9 @@ public Constant compress() { @Override public Constant uncompress() { - assert isCompressed(); + if (!compressed) { + throw new IllegalArgumentException("not compressed: " + this); + } HotSpotMetaspaceConstantImpl res = HotSpotMetaspaceConstantImpl.forMetaspaceObject(metaspaceObject, false); assert !res.isCompressed(); return res; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java index 443673a8783bc..e4a77daf0d448 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java @@ -52,6 +52,11 @@ public boolean isCompressed() { return compressed; } + @Override + public boolean isCompressible() { + return !compressed; + } + @Override public abstract JavaConstant compress(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java index 33c6fde3b1880..fe268e9047662 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java @@ -164,13 +164,17 @@ static void clearHandle(long handle) { @Override public JavaConstant compress() { - assert !compressed; + if (compressed) { + throw new IllegalArgumentException("already compressed: " + this); + } return new IndirectHotSpotObjectConstantImpl(this, true); } @Override public JavaConstant uncompress() { - assert compressed; + if (!compressed) { + throw new IllegalArgumentException("not compressed: " + this); + } return new IndirectHotSpotObjectConstantImpl(this, false); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java index d4c657f9cd35e..72c07b3ac989a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java @@ -86,10 +86,12 @@ static void checkJVMCIEnabled() { } /** - * Gets an unmodifiable copy of the system properties parsed by {@code arguments.cpp} - * plus {@code java.specification.version}, {@code os.name} and {@code os.arch}. - * The latter two are forced to be the real OS and architecture. That is, values - * for these two properties set on the command line are ignored. + * Gets an unmodifiable copy of the system properties as of VM startup. + * + * If running on Hotspot, this will be the system properties parsed by {@code arguments.cpp} + * plus {@code java.specification.version}, {@code os.name} and {@code os.arch}. The latter two + * are forced to be the real OS and architecture. That is, values for these two properties set + * on the command line are ignored. */ public static Map getSavedProperties() { checkJVMCIEnabled(); diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java index 78a03a4332d47..014b420e1a237 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java @@ -197,6 +197,7 @@ public ExitException(int errorCode) { private boolean hasExpiringCert = false; private boolean hasExpiringTsaCert = false; private boolean noTimestamp = true; + private boolean hasNonexistentEntries = false; // Expiration date. The value could be null if signed by a trusted cert. private Date expireDate = null; @@ -735,6 +736,7 @@ void verifyJar(String jarName) Map sigMap = new HashMap<>(); Map sigNameMap = new HashMap<>(); Map unparsableSignatures = new HashMap<>(); + Map> entriesInSF = new HashMap<>(); try { jf = new JarFile(jarName, true); @@ -782,6 +784,7 @@ void verifyJar(String jarName) break; } } + entriesInSF.put(alias, sf.getEntries().keySet()); if (!found) { unparsableSignatures.putIfAbsent(alias, String.format( @@ -881,6 +884,9 @@ void verifyJar(String jarName) sb.append('\n'); } } + for (var signed : entriesInSF.values()) { + signed.remove(name); + } } else if (showcerts && !verbose.equals("all")) { // Print no info for unsigned entries when -verbose:all, // to be consistent with old behavior. @@ -1076,6 +1082,13 @@ void verifyJar(String jarName) if (verbose != null) { System.out.println(history); } + var signed = entriesInSF.get(s); + if (!signed.isEmpty()) { + if (verbose != null) { + System.out.println(rb.getString("history.nonexistent.entries") + signed); + } + hasNonexistentEntries = true; + } } else { unparsableSignatures.putIfAbsent(s, String.format( rb.getString("history.nobk"), s)); @@ -1311,6 +1324,9 @@ private void displayMessagesAndResult(boolean isSigning) { } } + if (hasNonexistentEntries) { + warnings.add(rb.getString("nonexistent.entries.found")); + } if (externalFileAttributesDetected) { warnings.add(rb.getString("external.file.attributes.detected")); } diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java index 6a86b72ad1b10..810bd107bdebc 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java @@ -164,6 +164,7 @@ public class Resources extends java.util.ListResourceBundle { {"history.with.ts", "- Signed by \"%1$s\"\n Digest algorithm: %2$s\n Signature algorithm: %3$s, %4$s\n Timestamped by \"%6$s\" on %5$tc\n Timestamp digest algorithm: %7$s\n Timestamp signature algorithm: %8$s, %9$s"}, {"history.without.ts", "- Signed by \"%1$s\"\n Digest algorithm: %2$s\n Signature algorithm: %3$s, %4$s"}, + {"history.nonexistent.entries", " Warning: nonexistent signed entries: "}, {"history.unparsable", "- Unparsable signature-related file %s"}, {"history.nosf", "- Missing signature-related file META-INF/%s.SF"}, {"history.nobk", "- Missing block file for signature-related file META-INF/%s.SF"}, @@ -178,6 +179,7 @@ public class Resources extends java.util.ListResourceBundle { {"key.bit.disabled", "%d-bit key (disabled)"}, {"key.bit.eccurve.disabled", "%1$d-bit %2$s key (disabled)"}, {"unknown.size", "unknown size"}, + {"nonexistent.entries.found", "This jar contains signed entries for files that do not exist. See the -verbose output for more details."}, {"external.file.attributes.detected", "POSIX file permission and/or symlink attributes detected. These attributes are ignored when signing and are not protected by the signature."}, {"jarsigner.", "jarsigner: "}, diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java b/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java index b526f80cb35ca..28f6fccdc3aeb 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.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 @@ -30,6 +30,8 @@ import java.lang.module.ModuleDescriptor.Version; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashSet; +import java.util.Set; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import jdk.internal.module.ModulePath; @@ -212,6 +214,13 @@ void process(Main jartool, String opt, String arg) throws BadArgs { } }, + // Extract options + new Option(false, OptionType.EXTRACT, "--keep-old-files", "-k") { + void process(Main jartool, String opt, String arg) { + jartool.kflag = true; + } + }, + // Hidden options new Option(false, OptionType.OTHER, "-P") { void process(Main jartool, String opt, String arg) { @@ -245,6 +254,14 @@ void process(Main jartool, String opt, String arg) { if (jartool.info == null) jartool.info = GNUStyleOptions::printVersion; } + }, + new Option(true, true, OptionType.EXTRACT, "--dir") { + void process(Main jartool, String opt, String arg) throws BadArgs { + if (jartool.xdestDir != null) { + throw new BadArgs("error.extract.multiple.dest.dir").showUsage(true); + } + jartool.xdestDir = arg; + } } }; @@ -254,6 +271,7 @@ enum OptionType { CREATE("create"), CREATE_UPDATE("create.update"), CREATE_UPDATE_INDEX("create.update.index"), + EXTRACT("extract"), OTHER("other"); /** Resource lookup section prefix. */ diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index 551568ca86f21..d6cc2dbcddeae 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -155,11 +155,15 @@ public int hashCode() { * nflag: Perform jar normalization at the end * pflag: preserve/don't strip leading slash and .. component from file name * dflag: print module descriptor + * kflag: keep existing file */ - boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, pflag, dflag, validate; + boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, pflag, dflag, kflag, validate; boolean suppressDeprecateMsg = false; + // destination directory for extraction + String xdestDir = null; + /* To support additional GNU Style informational options */ Consumer info; @@ -372,6 +376,15 @@ public synchronized boolean run(String[] args) { } } } else if (xflag) { + if (xdestDir != null) { + final Path destPath = Paths.get(xdestDir); + try { + Files.createDirectories(destPath); + } catch (IOException ioe) { + throw new IOException(formatMsg("error.create.dir", + destPath.toString()), ioe); + } + } replaceFSC(filesMap); // For the extract action, when extracting all the entries, // access using the ZipInputStream class is most efficient, @@ -582,6 +595,9 @@ boolean parseArgs(String[] args) { case '0': flag0 = true; break; + case 'k': + kflag = true; + break; case 'i': if (cflag || uflag || xflag || tflag) { usageError(getMsg("error.multiple.main.operations")); @@ -612,6 +628,9 @@ boolean parseArgs(String[] args) { usageError(getMsg("error.bad.option")); return false; } + if (kflag && !xflag) { + warn(formatMsg("warn.option.is.ignored", "--keep-old-files/-k/k")); + } /* parse file arguments */ int n = args.length - count; @@ -631,6 +650,11 @@ boolean parseArgs(String[] args) { } /* change the directory */ String dir = args[++i]; + if (xflag && xdestDir != null) { + // extract option doesn't allow more than one destination directory + usageError(getMsg("error.extract.multiple.dest.dir")); + return false; + } dir = (dir.endsWith(File.separator) ? dir : (dir + File.separator)); dir = dir.replace(File.separatorChar, '/'); @@ -642,8 +666,12 @@ boolean parseArgs(String[] args) { if (hasUNC) { // Restore Windows UNC path. dir = "/" + dir; } - pathsMap.get(version).add(dir); - nameBuf[k++] = dir + args[++i]; + if (xflag) { + xdestDir = dir; + } else { + pathsMap.get(version).add(dir); + nameBuf[k++] = dir + args[++i]; + } } else if (args[i].startsWith("--release")) { int v = BASE_VERSION; try { @@ -702,6 +730,10 @@ boolean parseArgs(String[] args) { return false; } } + if (xflag && pflag && xdestDir != null) { + usageError(getMsg("error.extract.pflag.not.allowed")); + return false; + } return true; } @@ -1355,7 +1387,7 @@ void updateLastModifiedTime(Set zes) throws IOException { if (lastModified != -1) { String name = safeName(ze.getName().replace(File.separatorChar, '/')); if (name.length() != 0) { - File f = new File(name.replace('/', File.separatorChar)); + File f = new File(xdestDir, name.replace('/', File.separatorChar)); f.setLastModified(lastModified); } } @@ -1366,6 +1398,10 @@ void updateLastModifiedTime(Set zes) throws IOException { * Extracts specified entries from JAR file. */ void extract(InputStream in, String[] files) throws IOException { + if (vflag) { + output(formatMsg("out.extract.dir", Path.of(xdestDir == null ? "." : xdestDir).normalize() + .toAbsolutePath().toString())); + } ZipInputStream zis = new ZipInputStream(in); ZipEntry e; Set dirs = newDirSet(); @@ -1394,6 +1430,10 @@ void extract(InputStream in, String[] files) throws IOException { * Extracts specified entries from JAR file, via ZipFile. */ void extract(String fname, String[] files) throws IOException { + if (vflag) { + output(formatMsg("out.extract.dir", Path.of(xdestDir == null ? "." : xdestDir).normalize() + .toAbsolutePath().toString())); + } final Set dirs; try (ZipFile zf = new ZipFile(fname)) { dirs = newDirSet(); @@ -1423,16 +1463,24 @@ void extract(String fname, String[] files) throws IOException { */ ZipEntry extractFile(InputStream is, ZipEntry e) throws IOException { ZipEntry rc = null; - // The spec requres all slashes MUST be forward '/', it is possible + // The spec requires all slashes MUST be forward '/', it is possible // an offending zip/jar entry may uses the backwards slash in its // name. It might cause problem on Windows platform as it skips - // our "safe" check for leading slahs and dot-dot. So replace them + // our "safe" check for leading slash and dot-dot. So replace them // with '/'. String name = safeName(e.getName().replace(File.separatorChar, '/')); if (name.length() == 0) { return rc; // leading '/' or 'dot-dot' only path } - File f = new File(name.replace('/', File.separatorChar)); + // the xdestDir points to the user specified location where the jar needs to + // be extracted. By default xdestDir is null and represents current working + // directory. + // jar extraction using -P option is only allowed when the destination + // directory isn't specified (and hence defaults to current working directory). + // In such cases using this java.io.File constructor which accepts a null parent path + // allows us to extract entries that may have leading slashes and hence may need + // to be extracted outside of the current directory. + File f = new File(xdestDir, name.replace('/', File.separatorChar)); if (e.isDirectory()) { if (f.exists()) { if (!f.isDirectory()) { @@ -1452,6 +1500,12 @@ ZipEntry extractFile(InputStream is, ZipEntry e) throws IOException { output(formatMsg("out.create", name)); } } else { + if (f.exists() && kflag) { + if (vflag) { + output(formatMsg("out.kept", name)); + } + return rc; + } if (f.getParent() != null) { File d = new File(f.getParent()); if (!d.exists() && !d.mkdirs() || !d.isDirectory()) { diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties index 463068c517c23..c7b34abb340d2 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties +++ b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties @@ -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 @@ -62,6 +62,10 @@ error.incorrect.length=\ incorrect length while processing: {0} error.create.tempfile=\ Could not create a temporary file +error.extract.multiple.dest.dir=\ + You may not specify the '-C' or '--dir' option more than once with the '-x' option +error.extract.pflag.not.allowed=\ + You may not specify '-Px' with the '-C' or '--dir' options error.hash.dep=\ Hashing module {0} dependences, unable to find module {1} on module path error.module.options.without.info=\ @@ -143,6 +147,8 @@ warn.index.is.ignored=\ The JAR index (META-INF/INDEX.LIST) is ignored at run-time since JDK 18 warn.flag.is.deprecated=\ Warning: The {0} option is deprecated, and may be ignored or removed in a future release\n +warn.option.is.ignored=\ + Warning: The {0} option is not valid with current usage, will be ignored. out.added.manifest=\ added manifest out.added.module-info=\ @@ -165,10 +171,14 @@ out.create=\ \ \ created: {0} out.extracted=\ extracted: {0} +out.kept=\ + \ \ skipped: {0} exists out.inflated=\ \ inflated: {0} out.size=\ (in = {0}) (out= {1}) +out.extract.dir=\ + extracting to directory: {0} usage.compat=\ \Compatibility Interface:\ @@ -190,6 +200,7 @@ Options:\n\ \ \ -i generate index information for the specified jar files\n\ \ \ -C change to the specified directory and include the following file\n\ If any file is a directory then it is processed recursively.\n\ +When used in extract mode, extracts the jar to the specified directory\n\ The manifest file name, the archive file name and the entry point name are\n\ specified in the same order as the 'm', 'f' and 'e' flags.\n\n\ Example 1: to archive two class files into an archive called classes.jar: \n\ @@ -245,7 +256,10 @@ main.help.opt.main.list=\ main.help.opt.main.update=\ \ -u, --update Update an existing jar archive main.help.opt.main.extract=\ -\ -x, --extract Extract named (or all) files from the archive +\ -x, --extract Extract named (or all) files from the archive.\n\ +\ If a file with the same name appears more than once in\n\ +\ the archive, each copy will be extracted, with later copies\n\ +\ overwriting (replacing) earlier copies unless -k is specified. main.help.opt.main.describe-module=\ \ -d, --describe-module Print the module descriptor, or automatic module name main.help.opt.main.validate=\ @@ -257,7 +271,8 @@ main.help.opt.any=\ \ Operation modifiers valid in any mode:\n\ \n\ \ -C DIR Change to the specified directory and include the\n\ -\ following file +\ following file. When used in extract mode, extracts\n\ +\ the jar to the specified directory main.help.opt.any.file=\ \ -f, --file=FILE The archive file name. When omitted, either stdin or\n\ \ stdout is used based on the operation\n\ @@ -307,6 +322,15 @@ main.help.opt.create.update.index.date=\ \ --date=TIMESTAMP The timestamp in ISO-8601 extended offset date-time with\n\ \ optional time-zone format, to use for the timestamps of\n\ \ entries, e.g. "2022-02-12T12:30:00-05:00" +main.help.opt.extract=\ +\ Operation modifiers valid only in extract mode:\n +main.help.opt.extract.keep-old-files=\ +\ -k, --keep-old-files Do not overwrite existing files.\n\ +\ If a Jar file entry with the same name exists in the target\n\ +\ directory, the existing file will not be overwritten.\n\ +\ As a result, if a file appears more than once in an\n\ +\ archive, later copies will not overwrite earlier copies.\n\ +\ Also note that some file system can be case insensitive. main.help.opt.other=\ \ Other options:\n main.help.opt.other.help=\ @@ -324,3 +348,7 @@ main.help.postopt=\ \n\ \ Mandatory or optional arguments to long options are also mandatory or optional\n\ \ for any corresponding short options. +main.help.opt.extract=\ +\ Operation modifiers valid only in extract mode:\n +main.help.opt.extract.dir=\ +\ --dir Directory into which the jar will be extracted diff --git a/src/jdk.jartool/share/man/jar.1 b/src/jdk.jartool/share/man/jar.1 index 2d983eb561e3b..a88653753eebe 100644 --- a/src/jdk.jartool/share/man/jar.1 +++ b/src/jdk.jartool/share/man/jar.1 @@ -1,4 +1,4 @@ -.\" 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 @@ -118,6 +118,9 @@ Updates an existing JAR file. .TP \f[V]-x\f[R] or \f[V]--extract\f[R] Extracts the named (or all) files from the archive. +If a file with the same name appears more than once in the archive, each +copy will be extracted, with later copies overwriting (replacing) +earlier copies unless -k is specified. .TP \f[V]-d\f[R] or \f[V]--describe-module\f[R] Prints the module descriptor or automatic module name. @@ -127,13 +130,19 @@ You can use the following options to customize the actions of any operation mode included in the \f[V]jar\f[R] command. .TP \f[V]-C\f[R] \f[I]DIR\f[R] -Changes the specified directory and includes the \f[I]files\f[R] -specified at the end of the command line. +When used with the create operation mode, changes the specified +directory and includes the \f[I]files\f[R] specified at the end of the +command line. .RS .PP \f[V]jar\f[R] [\f[I]OPTION\f[R] ...] [ [\f[V]--release\f[R] \f[I]VERSION\f[R]] [\f[V]-C\f[R] \f[I]dir\f[R]] \f[I]files\f[R]] +.PP +When used with the extract operation mode, specifies the destination +directory where the JAR file will be extracted. +Unlike with the create operation mode, this option can be specified only +once with the extract operation mode. .RE .TP \f[V]-f\f[R] \f[I]FILE\f[R] or \f[V]--file=\f[R]\f[I]FILE\f[R] @@ -202,6 +211,18 @@ Stores without using ZIP compression. The timestamp in ISO-8601 extended offset date-time with optional time-zone format, to use for the timestamp of the entries, e.g. \[dq]2022-02-12T12:30:00-05:00\[dq]. +.SH OPERATION MODIFIERS VALID ONLY IN EXTRACT MODE +.TP +\f[V]--dir\f[R] \f[I]DIR\f[R] +Directory into which the JAR file will be extracted. +.TP +\f[V]-k\f[R] or \f[V]--keep-old-files\f[R] +Do not overwrite existing files. +If a Jar file entry with the same name exists in the target directory, +the existing file will not be overwritten. +As a result, if a file appears more than once in an archive, later +copies will not overwrite earlier copies. +Also note that some file system can be case insensitive. .SH OTHER OPTIONS .PP The following options are recognized by the \f[V]jar\f[R] command and @@ -342,3 +363,17 @@ file that lists the files to include in the JAR file and pass it to the If one or more entries in the arg file cannot be found then the jar command fails without creating the JAR file. .RE +.IP \[bu] 2 +Extract the JAR file \f[V]foo.jar\f[R] to \f[V]/tmp/bar/\f[R] directory: +.RS 2 +.RS +.PP +\f[V]jar -xf foo.jar -C /tmp/bar/\f[R] +.RE +.PP +Alternatively, you can also do: +.RS +.PP +\f[V]jar --extract --file foo.jar --dir /tmp/bar/\f[R] +.RE +.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 fdf05489168f7..9bb1ebaaf620b 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 @@ -2642,19 +2642,31 @@ public void addRestrictedInfo(ExecutableElement forWhat, Content target) { //in Java platform: var restrictedDiv = HtmlTree.DIV(HtmlStyles.restrictedBlock); restrictedDiv.setId(htmlIds.forRestrictedSection(forWhat)); - String name = forWhat.getSimpleName().toString(); + var name = forWhat.getSimpleName().toString(); var nameCode = HtmlTree.CODE(Text.of(name)); - String leadingNoteKey = "doclet.RestrictedLeadingNote"; - Content leadingNote = - contents.getContent(leadingNoteKey, nameCode); - restrictedDiv.add(HtmlTree.SPAN(HtmlStyles.restrictedLabel, - leadingNote)); - Content note1 = contents.getContent("doclet.RestrictedTrailingNote1", nameCode); + var restrictedMethodLink = getRestrictedMethodDocLink(); + var leadingNoteKey = "doclet.RestrictedLeadingNote"; + var leadingNote = contents.getContent(leadingNoteKey, nameCode, restrictedMethodLink); + restrictedDiv.add(HtmlTree.SPAN(HtmlStyles.restrictedLabel, leadingNote)); + var note1 = contents.getContent("doclet.RestrictedTrailingNote1", nameCode); restrictedDiv.add(HtmlTree.DIV(HtmlStyles.restrictedComment, note1)); - Content note2 = contents.getContent("doclet.RestrictedTrailingNote2", nameCode); + var note2 = contents.getContent("doclet.RestrictedTrailingNote2", nameCode); restrictedDiv.add(HtmlTree.DIV(HtmlStyles.restrictedComment, note2)); target.add(restrictedDiv); } } + private Content getRestrictedMethodDocLink() { + var restrictedMethodLabel = contents.getContent("doclet.RestrictedMethod"); + var javaLang = utils.elementUtils.getPackageElement("java.lang"); + if (utils.isIncluded(javaLang)) { + var restrictedDocPath = pathToRoot + .resolve(docPaths.forPackage(javaLang)) + .resolve(DocPaths.DOC_FILES) + .resolve(DocPaths.RESTRICTED_DOC); + return links.createLink(restrictedDocPath, restrictedMethodLabel); + } + return restrictedMethodLabel; + } + } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index 633f453bc43b1..2185b1c951f8e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -300,6 +300,7 @@ document.addEventListener("DOMContentLoaded", function(e) { }); var expanded = false; var windowWidth; + var bodyHeight; function collapse(e) { if (expanded) { mainnav.removeAttribute("style"); @@ -365,6 +366,7 @@ document.addEventListener("DOMContentLoaded", function(e) { var scrollTimeoutNeeded; var prevHash; function initSectionData() { + bodyHeight = document.body.offsetHeight; sections = [{ id: "", top: 0 }].concat(Array.from(main.querySelectorAll("section[id], h2[id], h2 a[id], div[id]")) .filter((e) => { return sidebar.querySelector("a[href=\"#" + encodeURI(e.getAttribute("id")) + "\"]") !== null @@ -469,7 +471,7 @@ document.addEventListener("DOMContentLoaded", function(e) { expand(); } } - if (sections) { + if (sections && document.body.offsetHeight !== bodyHeight) { initSectionData(); prevHash = null; handleScroll(); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index 6141ce46fe8fc..bb001912229c2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -424,7 +424,8 @@ doclet.ReflectivePreviewAPI={0} refers to one or more reflective preview APIs: doclet.UsesDeclaredUsingPreview={0} refers to one or more types which are declared using a preview feature of the Java language: {1}. doclet.PreviewTrailingNote1=Programs can only use {0} when preview features are enabled. doclet.PreviewTrailingNote2=Preview features may be removed in a future release, or upgraded to permanent features of the Java platform. -doclet.RestrictedLeadingNote={0} is a restricted method of the Java platform. +doclet.RestrictedMethod=restricted method +doclet.RestrictedLeadingNote={0} is a {1} of the Java platform. doclet.RestrictedTrailingNote1=Programs can only use {0} when access to restricted methods is enabled. doclet.RestrictedTrailingNote2=Restricted methods are unsafe, and, if used incorrectly, might crash \ the JVM or result in memory corruption. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index 97fcc91eadcfd..641a6684444f9 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -28,8 +28,8 @@ /* Line height for continuous text blocks */ --block-line-height: 1.4em; /* Text colors for body and block elements */ - --body-text-color: #353833; - --block-text-color: #474747; + --body-text-color: #282828; + --block-text-color: #282828; /* Background colors for various structural elements */ --body-background-color: #ffffff; --section-background-color: #f8f8f8; @@ -49,8 +49,11 @@ /* Text color for page title */ --title-color: #2c4557; /* Text colors for links */ - --link-color: #4A6782; + --link-color: #437291; --link-color-active: #bb7a2a; + /* Table of contents */ + --toc-background-color: var(--section-background-color); + --toc-link-color: #4a698a; /* Snippet colors */ --snippet-background-color: #ebecee; --snippet-text-color: var(--block-text-color); @@ -99,6 +102,9 @@ a:link, a:visited { text-decoration:none; color:var(--link-color); } +nav a:link, nav a:visited { + color: var(--toc-link-color); +} a[href]:hover, a[href]:active { text-decoration:none; color:var(--link-color-active); @@ -398,7 +404,7 @@ dl.name-value > dd { * Styles for table of contents. */ .main-grid nav.toc { - background-color: var(--section-background-color); + background-color: var(--toc-background-color); border-right: 1px solid var(--border-color); position: sticky; top: calc(var(--nav-height)); @@ -409,8 +415,6 @@ dl.name-value > dd { z-index: 1; } .main-grid nav.toc div.toc-header { - background-color: var(--section-background-color); - border-right: 1px solid var(--border-color); top: var(--nav-height); z-index: 1; padding: 15px 20px; @@ -473,7 +477,6 @@ nav.toc div.toc-header { display: inline-flex; align-items: center; color: var(--body-text-color); - background-color: var(--body-background-color); font-size: 0.856em; font-weight: bold; white-space: nowrap; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java index 5ae2d1590721c..47cf3e81ebed5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java @@ -163,6 +163,9 @@ public static DocPath indexN(int n) { /** The name of the file for restricted methods. */ public static final DocPath RESTRICTED_LIST = DocPath.create("restricted-list.html"); + /** The name of the doc-file for restricted methods. */ + public static final DocPath RESTRICTED_DOC = DocPath.create("RestrictedMethods.html"); + /** The name of the directory for the resource files. */ public static final DocPath RESOURCE_FILES = DocPath.create("resource-files"); diff --git a/src/jdk.jcmd/share/man/jcmd.1 b/src/jdk.jcmd/share/man/jcmd.1 index a639dab16e144..495b629089db9 100644 --- a/src/jdk.jcmd/share/man/jcmd.1 +++ b/src/jdk.jcmd/share/man/jcmd.1 @@ -65,13 +65,6 @@ selected JVM. The list of available commands for \f[V]jcmd\f[R] is obtained by running the \f[V]help\f[R] command (\f[V]jcmd\f[R] \f[I]pid\f[R] \f[V]help\f[R]) where \f[I]pid\f[R] is the process ID for the running Java process. -If the \f[I]pid\f[R] is \f[V]0\f[R], commands will be sent to all Java -processes. -The main class argument will be used to match, either partially or -fully, the class used to start Java. -If no options are given, it lists the running Java process identifiers -with the main class and command-line arguments that were used to launch -the process (the same as using \f[V]-l\f[R]). .TP \f[V]Perfcounter.print\f[R] Prints the performance counters exposed by the specified Java process. @@ -102,9 +95,10 @@ to the JVM. It must be used on the same machine on which the JVM is running, and have the same effective user and group identifiers that were used to launch the JVM. -Each diagnostic command has its own set of arguments. -To display the description, syntax, and a list of available arguments -for a diagnostic command, use the name of the command as the argument. +Each diagnostic command has its own set of options and arguments. +To display the description, syntax, and a list of available options and +arguments for a diagnostic command, use the name of the command as the +argument. For example: .RS .PP @@ -143,6 +137,11 @@ that are not in separate docker processes along with the main class and command-line arguments that were used to launch the process (the same as using \f[V]-l\f[R]). .PP +\f[V]jcmd\f[R] \f[I]commands\f[R] may take options and arguments. +\f[I]Options\f[R] are specified using either \f[I]key\f[R] or +\f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +\f[I]Arguments\f[R] are given as just a value, never name=value. +.PP The following commands are available: .TP \f[V]help\f[R] [\f[I]options\f[R]] [\f[I]arguments\f[R]] @@ -254,13 +253,9 @@ Impact: Low .PP \f[I]arguments\f[R]: .IP \[bu] 2 -\f[I]filename\f[R]: (Optional) The name of the map file (STRING, -/tmp/perf-.map) -.PP -If \f[V]filename\f[R] is not specified, a default file name is chosen -using the pid of the target JVM process. -For example, if the pid is \f[V]12345\f[R], then the default -\f[V]filename\f[R] will be \f[V]/tmp/perf-12345.map\f[R]. +\f[I]filename\f[R]: (Optional) The name of the map file. +If %p is specified in the filename, it is expanded to the JVM\[aq]s PID. +(FILE, \[dq]/tmp/perf-%p.map\[dq]) .RE .TP \f[V]Compiler.queue\f[R] @@ -302,7 +297,7 @@ Provides information about the Java finalization queue. Impact: Medium .RE .TP -\f[V]GC.heap_dump\f[R] [\f[I]options\f[R]] [\f[I]arguments\f[R]] +\f[V]GC.heap_dump\f[R] [\f[I]options\f[R]] \f[I]filename\f[R] Generates a HPROF format dump of the Java heap. .RS .PP @@ -335,7 +330,9 @@ fewer. .PP \f[I]arguments\f[R]: .IP \[bu] 2 -\f[I]filename\f[R]: The name of the dump file (STRING, no default value) +\f[I]filename\f[R]: The name of the dump file. +If %p is specified in the filename, it is expanded to the JVM\[aq]s PID. +(FILE, no default value) .RE .TP \f[V]GC.heap_info\f[R] @@ -511,7 +508,7 @@ The filename may also be a directory in which case, the filename is generated from the PID and the current date in the specified directory. If %p and/or %t is specified in the filename, it expands to the JVM\[aq]s PID and the current timestamp, respectively. -(STRING, no default value) +(FILE, no default value) .IP \[bu] 2 \f[V]maxage\f[R]: (Optional) Length of time for dumping the flight recording data to a file. @@ -581,7 +578,7 @@ The filename may also be a directory in which case, the filename is generated from the PID and the current date in the specified directory. If %p and/or %t is specified in the filename, it expands to the JVM\[aq]s PID and the current timestamp, respectively. -(STRING, no default value) +(FILE, no default value) .IP \[bu] 2 \f[V]maxage\f[R]: (Optional) Maximum time to keep the recorded data on disk. @@ -675,7 +672,7 @@ is written when the recording is stopped. If %p and/or %t is specified in the filename, it expands to the JVM\[aq]s PID and the current timestamp, respectively. If no path is provided, the data from the recording is discarded. -(STRING, no default value) +(FILE, no default value) .IP \[bu] 2 \f[V]name\f[R]: (Optional) Name of the recording (STRING, no default value) @@ -877,8 +874,9 @@ The following \f[I]options\f[R] must be specified using either .IP \[bu] 2 \f[V]-H\f[R]: (Optional) Human readable format (BOOLEAN, false) .IP \[bu] 2 -\f[V]-F\f[R]: (Optional) File path (STRING, -\[dq]vm_memory_map_.txt\[dq]) +\f[V]-F\f[R]: (Optional) File path. +If %p is specified in the filename, it is expanded to the JVM\[aq]s PID. +(FILE, \[dq]vm_memory_map_%p.txt\[dq]) .RE .TP \f[V]System.map\f[R] [\f[I]options\f[R]] (Linux only) @@ -934,8 +932,9 @@ false) .PP \f[I]arguments\f[R]: .IP \[bu] 2 -\f[I]filepath\f[R]: The file path to the output file (STRING, no default -value) +\f[I]filepath\f[R]: The file path to the output file. +If %p is specified in the filename, it is expanded to the JVM\[aq]s PID. +(FILE, no default value) .RE .TP \f[V]Thread.print\f[R] [\f[I]options\f[R]] @@ -970,16 +969,9 @@ Impact: Medium --- pause time depends on number of loaded classes \f[I]subcmd\f[R]: must be either \f[V]static_dump\f[R] or \f[V]dynamic_dump\f[R] (STRING, no default value) .IP \[bu] 2 -\f[I]filename\f[R]: (Optional) Name of the shared archive to be dumped -(STRING, java_pid_.jsa) -.PP -If \f[V]filename\f[R] is not specified, a default file name is chosen -using the pid of the target JVM process. -For example, java_pid1234_static.jsa, java_pid5678_dynamic.jsa, etc. -.PP -If \f[V]filename\f[R] is not specified as an absolute path, the archive -file is created in a directory relative to the current directory of the -target JVM process. +\f[I]filename\f[R]: (Optional) Name of the shared archive to be dumped. +If %p is specified in the filename, it is expanded to the JVM\[aq]s PID. +(FILE, \[dq]java_pid%p_.jsa\[dq]) .PP If \f[V]dynamic_dump\f[R] is specified, the target JVM must be started with the JVM option \f[V]-XX:+RecordDynamicDumpInfo\f[R]. diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java index 77fbce8839e72..92a0c06c1c382 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java @@ -576,9 +576,7 @@ protected void writeMethod(MethodModel m) { attrWriter.write(m.attributes()); } else if (code != null) { if (options.showDisassembled) { - println("Code:"); - codeWriter.writeInstrs(code); - codeWriter.writeExceptionTable(code); + codeWriter.writeMinimal(code); } if (options.showLineAndLocalVariableTables) { diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/CodeWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/CodeWriter.java index 519a5adcf6278..cb401c9f1971c 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/CodeWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/CodeWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, 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 @@ -70,13 +70,11 @@ protected CodeWriter(Context context) { } void write(CodeAttribute attr) { - println("Code:"); - indent(+1); - writeVerboseHeader(attr); - writeInstrs(attr); - writeExceptionTable(attr); - attrWriter.write(attr.attributes(), attr); - indent(-1); + writeInternal(attr, false); + } + + void writeMinimal(CodeAttribute attr) { + writeInternal(attr, true); } public void writeVerboseHeader(CodeAttribute attr) { @@ -92,20 +90,22 @@ public void writeVerboseHeader(CodeAttribute attr) { public void writeInstrs(CodeAttribute attr) { List detailWriters = getDetailWriters(attr); - int pc = 0; + int[] pcState = {0}; try { - for (var coe: attr) { + attr.forEach(coe -> { if (coe instanceof Instruction instr) { - for (InstructionDetailWriter w: detailWriters) + int pc = pcState[0]; + for (InstructionDetailWriter w : detailWriters) w.writeDetails(pc, instr); writeInstr(pc, instr, attr); - pc += instr.sizeInBytes(); + pcState[0] = pc + instr.sizeInBytes(); } - } + }); } catch (IllegalArgumentException e) { - report("error at or after byte " + pc); + report("error at or after address " + pcState[0] + ": " + e.getMessage()); } + int pc = pcState[0]; for (InstructionDetailWriter w: detailWriters) w.flush(pc); } @@ -257,6 +257,20 @@ private List getDetailWriters(CodeAttribute attr) { return detailWriters; } + private void writeInternal(CodeAttribute attr, boolean minimal) { + println("Code:"); + indent(+1); + if (!minimal) { + writeVerboseHeader(attr); + } + writeInstrs(attr); + writeExceptionTable(attr); + if (!minimal) { + attrWriter.write(attr.attributes(), attr); + } + indent(-1); + } + private AttributeWriter attrWriter; private ClassWriter classWriter; private ConstantWriter constantWriter; diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ArrayReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ArrayReference.java index 11b5bdbcf7096..7f445f7c05ace 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ArrayReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ArrayReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, 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 @@ -108,8 +108,8 @@ public interface ArrayReference extends ObjectReference { * See JLS section 5.2 for more information on assignment * compatibility. * - * @param value the new value * @param index the index of the component to set + * @param value the new value * @throws java.lang.IndexOutOfBoundsException if * index is outside the range of this array, * that is, if either of the following are true: diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/request/EventRequestManager.java b/src/jdk.jdi/share/classes/com/sun/jdi/request/EventRequestManager.java index 2ffa7008ee434..3bd363af56ec8 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/request/EventRequestManager.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/request/EventRequestManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, 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 @@ -261,8 +261,8 @@ ExceptionRequest createExceptionRequest(ReferenceType refType, * }

          25. * * @param thread the thread in which to step - * @param depth the step depth * @param size the step size + * @param depth the step depth * @return the created {@link StepRequest} * @throws DuplicateRequestException if there is already a pending * step request for the specified thread. diff --git a/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryConnection.c b/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryConnection.c index af78969e316ac..b6d246d043363 100644 --- a/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryConnection.c +++ b/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryConnection.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, 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 @@ -115,7 +115,7 @@ packetToByteArray(JNIEnv *env, jdwpPacket *str) /* total packet length is header + data */ array = (*env)->NewByteArray(env, total_length); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return NULL; } @@ -144,7 +144,7 @@ packetToByteArray(JNIEnv *env, jdwpPacket *str) if (data_length > 0) { (*env)->SetByteArrayRegion(env, array, JDWP_HEADER_SIZE, data_length, str->type.cmd.data); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return NULL; } } @@ -174,7 +174,7 @@ byteArrayToPacket(JNIEnv *env, jbyteArray b, jdwpPacket *str) * Get the packet header */ (*env)->GetByteArrayRegion(env, b, 0, sizeof(pktHeader), pktHeader); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { /* b shorter than sizeof(pktHeader) */ return; } @@ -221,7 +221,7 @@ byteArrayToPacket(JNIEnv *env, jbyteArray b, jdwpPacket *str) } (*env)->GetByteArrayRegion(env, b, sizeof(pktHeader), /*sizeof(CmdPacket)+4*/ data_length, data); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { free(data); return; } @@ -326,7 +326,7 @@ JNIEXPORT void JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_sendPacket0 jint rc; byteArrayToPacket(env, b, &packet); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return; } diff --git a/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryTransport.c b/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryTransport.c index 7258503f7e173..867ed1d8567fa 100644 --- a/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryTransport.c +++ b/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryTransport.c @@ -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 @@ -51,7 +51,7 @@ void throwException(JNIEnv *env, char *exceptionClassName, char *message) { jclass excClass = (*env)->FindClass(env, exceptionClassName); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return; } (*env)->ThrowNew(env, excClass, message); @@ -109,7 +109,7 @@ JNIEXPORT jlong JNICALL Java_com_sun_tools_jdi_SharedMemoryTransportService_atta const char *addrChars; addrChars = (*env)->GetStringUTFChars(env, address, NULL); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return CONNECTION_TO_ID(connection); } else if (addrChars == NULL) { throwException(env, "java/lang/InternalError", "GetStringUTFChars failed"); @@ -143,7 +143,7 @@ JNIEXPORT jstring JNICALL Java_com_sun_tools_jdi_SharedMemoryTransportService_na throwShmemException(env, "shmemBase_name failed", rc); } else { nameString = (*env)->NewStringUTF(env, namePtr); - if ((nameString == NULL) && !(*env)->ExceptionOccurred(env)) { + if ((nameString == NULL) && !(*env)->ExceptionCheck(env)) { throwException(env, "java/lang/InternalError", "Unable to create string"); } } @@ -190,7 +190,7 @@ JNIEXPORT jlong JNICALL Java_com_sun_tools_jdi_SharedMemoryTransportService_star if (address != NULL) { addrChars = (*env)->GetStringUTFChars(env, address, NULL); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return TRANSPORT_TO_ID(transport); } else if (addrChars == NULL) { throwException(env, "java/lang/InternalError", "GetStringUTFChars failed"); diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c index b221cf6cf2551..73ea9a295e681 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c @@ -81,9 +81,6 @@ static unsigned logflags = 0; /* Log flags */ static char *names; /* strings derived from OnLoad options */ -static jboolean allowStartViaJcmd = JNI_FALSE; /* if true we allow the debugging to be started via a jcmd */ -static jboolean startedViaJcmd = JNI_FALSE; /* if false, we have not yet started debugging via a jcmd */ - /* * Elements of the transports bag */ @@ -983,7 +980,6 @@ parseOptions(char *options) int length; char *str; char *errmsg; - jboolean onJcmd = JNI_FALSE; /* Set defaults */ gdata->assertOn = DEFAULT_ASSERT_ON; @@ -1231,10 +1227,6 @@ parseOptions(char *options) if ( !get_boolean(&str, &useStandardAlloc) ) { goto syntax_error; } - } else if (strcmp(buf, "onjcmd") == 0) { - if (!get_boolean(&str, &onJcmd)) { - goto syntax_error; - } } else { goto syntax_error; } @@ -1285,20 +1277,6 @@ parseOptions(char *options) } } - if (onJcmd) { - if (launchOnInit != NULL) { - errmsg = "Cannot combine onjcmd and launch suboptions"; - goto bad_option_with_errmsg; - } - if (!isServer) { - errmsg = "Can only use onjcmd with server=y"; - goto bad_option_with_errmsg; - } - suspendOnInit = JNI_FALSE; - initOnStartup = JNI_FALSE; - allowStartViaJcmd = JNI_TRUE; - } - return JNI_TRUE; syntax_error: @@ -1367,45 +1345,3 @@ debugInit_exit(jvmtiError error, const char *msg) // Last chance to die, this kills the entire process. forceExit(EXIT_JVMTI_ERROR); } - -static jboolean getFirstTransport(void *item, void *arg) -{ - TransportSpec** store = arg; - *store = item; - - return JNI_FALSE; /* Want the first */ -} - -/* Call to start up debugging. */ -JNIEXPORT char const* JNICALL debugInit_startDebuggingViaCommand(JNIEnv* env, jthread thread, char const** transport_name, - char const** address, jboolean* first_start) { - jboolean is_first_start = JNI_FALSE; - TransportSpec* spec = NULL; - - if (!vmInitialized) { - return "Not yet initialized. Try again later."; - } - - if (!allowStartViaJcmd) { - return "Starting debugging via jcmd was not enabled via the onjcmd option of the jdwp agent."; - } - - if (!startedViaJcmd) { - startedViaJcmd = JNI_TRUE; - is_first_start = JNI_TRUE; - initialize(env, thread, EI_VM_INIT, NULL); - } - - bagEnumerateOver(transports, getFirstTransport, &spec); - - if ((spec != NULL) && (transport_name != NULL) && (address != NULL)) { - *transport_name = spec->name; - *address = spec->address; - } - - if (first_start != NULL) { - *first_start = is_first_start; - } - - return NULL; -} diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c index 7e198be9a4637..335acc62dcf4f 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c @@ -1652,6 +1652,185 @@ setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue) } } +#ifdef DEBUG +// APIs that can be called when debugging the debug agent + +#define check_jvmti_status(err, msg) \ + if (err != JVMTI_ERROR_NONE) { \ + EXIT_ERROR(err, msg); \ + } + +char* +translateThreadState(jint flags) { + char str[15 * 20]; + str[0] = '\0'; + + if (flags & JVMTI_THREAD_STATE_ALIVE) { + strcat(str, " ALIVE"); + } + if (flags & JVMTI_THREAD_STATE_TERMINATED) { + strcat(str, " TERMINATED"); + } + if (flags & JVMTI_THREAD_STATE_RUNNABLE) { + strcat(str, " RUNNABLE"); + } + if (flags & JVMTI_THREAD_STATE_WAITING) { + strcat(str, " WAITING"); + } + if (flags & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) { + strcat(str, " WAITING_INDEFINITELY"); + } + if (flags & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) { + strcat(str, " WAITING_WITH_TIMEOUT"); + } + if (flags & JVMTI_THREAD_STATE_SLEEPING) { + strcat(str, " SLEEPING"); + } + if (flags & JVMTI_THREAD_STATE_IN_OBJECT_WAIT) { + strcat(str, " IN_OBJECT_WAIT"); + } + if (flags & JVMTI_THREAD_STATE_PARKED) { + strcat(str, " PARKED"); + } + if (flags & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) { + strcat(str, " BLOCKED_ON_MONITOR_ENTER"); + } + if (flags & JVMTI_THREAD_STATE_SUSPENDED) { + strcat(str, " SUSPENDED"); + } + if (flags & JVMTI_THREAD_STATE_INTERRUPTED) { + strcat(str, " INTERRUPTED"); + } + if (flags & JVMTI_THREAD_STATE_IN_NATIVE) { + strcat(str, " IN_NATIVE"); + } + + if (strlen(str) == 0) { + strcpy(str, ""); + } + + char* tstate = (char*)jvmtiAllocate((int)strlen(str) + 1); + strcpy(tstate, str); + + return tstate; +} + +char* +getThreadName(jthread thread) { + jvmtiThreadInfo thr_info; + jvmtiError err; + + memset(&thr_info, 0, sizeof(thr_info)); + err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) + (gdata->jvmti, thread, &thr_info); + if (err == JVMTI_ERROR_WRONG_PHASE || err == JVMTI_ERROR_THREAD_NOT_ALIVE) { + return NULL; // VM or target thread completed its work + } + check_jvmti_status(err, "getThreadName: error in JVMTI GetThreadInfo call"); + + char* tname = thr_info.name; + if (tname == NULL) { + const char* UNNAMED_STR = ""; + size_t UNNAMED_LEN = strlen(UNNAMED_STR); + tname = (char*)jvmtiAllocate((int)UNNAMED_LEN + 1); + strcpy(tname, UNNAMED_STR); + } + return tname; +} + +char* +getMethodName(jmethodID method) { + char* mname = NULL; + jvmtiError err; + + err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName) + (gdata->jvmti, method, &mname, NULL, NULL); + check_jvmti_status(err, "getMethodName: error in JVMTI GetMethodName call"); + + return mname; +} + +static char* +get_method_class_name(jmethodID method) { + jclass klass = NULL; + char* cname = NULL; + char* result = NULL; + jvmtiError err; + + err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass) + (gdata->jvmti, method, &klass); + check_jvmti_status(err, "get_method_class_name: error in JVMTI GetMethodDeclaringClass"); + + err = JVMTI_FUNC_PTR(gdata->jvmti,GetClassSignature) + (gdata->jvmti, klass, &cname, NULL); + check_jvmti_status(err, "get_method_class_name: error in JVMTI GetClassSignature"); + + size_t len = strlen(cname) - 2; // get rid of leading 'L' and trailing ';' + result = (char*)jvmtiAllocate((int)len + 1); + strncpy(result, cname + 1, len); // skip leading 'L' + result[len] = '\0'; + jvmtiDeallocate((void*)cname); + return result; +} + +static void +print_method(jmethodID method, jint depth) { + char* cname = NULL; + char* mname = NULL; + char* msign = NULL; + jvmtiError err; + + cname = get_method_class_name(method); + + err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName) + (gdata->jvmti, method, &mname, &msign, NULL); + check_jvmti_status(err, "print_method: error in JVMTI GetMethodName"); + + tty_message("%2d: %s: %s%s", depth, cname, mname, msign); + jvmtiDeallocate((void*)cname); + jvmtiDeallocate((void*)mname); + jvmtiDeallocate((void*)msign); +} + +#define MAX_FRAME_COUNT_PRINT_STACK_TRACE 200 + +void +printStackTrace(jthread thread) { + jvmtiFrameInfo frames[MAX_FRAME_COUNT_PRINT_STACK_TRACE]; + char* tname = getThreadName(thread); + jint count = 0; + + jvmtiError err = JVMTI_FUNC_PTR(gdata->jvmti,GetStackTrace) + (gdata->jvmti, thread, 0, MAX_FRAME_COUNT_PRINT_STACK_TRACE, frames, &count); + check_jvmti_status(err, "printStackTrace: error in JVMTI GetStackTrace"); + + tty_message("JVMTI Stack Trace for thread %s: frame count: %d", tname, count); + for (int depth = 0; depth < count; depth++) { + print_method(frames[depth].method, depth); + } + jvmtiDeallocate((void*)tname); +} + +void +printThreadInfo(jthread thread) { + jvmtiThreadInfo thread_info; + jint thread_state; + jvmtiError err; + err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) + (gdata->jvmti, thread, &thread_info); + check_jvmti_status(err, "Error in GetThreadInfo"); + err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState) + (gdata->jvmti, thread, &thread_state); + check_jvmti_status(err, "Error in GetThreadState"); + const char* state = translateThreadState(thread_state); + tty_message("Thread: %p, name: %s, state(%x): %s, attrs: %s %s", + thread, thread_info.name, thread_state, state, + (isVThread(thread) ? "virtual": "platform"), + (thread_info.is_daemon ? "daemon": "")); +} + +#endif /* DEBUG*/ + /** * Return property value as JDWP allocated string in UTF8 encoding */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.h b/src/jdk.jdwp.agent/share/native/libjdwp/util.h index 75281813709e0..3d499d7d56985 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.h @@ -386,6 +386,15 @@ jvmtiError allNestedClasses(jclass clazz, jclass **ppnested, jint *pcount); void setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue); +#ifdef DEBUG +// APIs that can be called when debugging the debug agent +char* translateThreadState(jint flags); +char* getThreadName(jthread thread); +char* getMethodName(jmethodID method); +void printStackTrace(jthread thread); +void printThreadInfo(jthread thread); +#endif + void *jvmtiAllocate(jint numBytes); void jvmtiDeallocate(void *buffer); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java index 0306541b4f781..7ede3de9d15be 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java @@ -38,6 +38,7 @@ import jdk.jfr.Event; import jdk.jfr.SettingControl; import jdk.jfr.ValueDescriptor; +import jdk.jfr.internal.util.Utils; /** * Internal data structure that describes a type, @@ -185,14 +186,9 @@ public ValueDescriptor getField(String name) { Type type = PrivateAccess.getInstance().getType(subField); return type.getField(post); } - } else { - for (ValueDescriptor v : getFields()) { - if (name.equals(v.getName())) { - return v; - } - } + return null; } - return null; + return Utils.findField(getFields(), name); } public List getFields() { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/FieldBuilder.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/FieldBuilder.java index d91fa62b368ed..c6916bc52efea 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/FieldBuilder.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/FieldBuilder.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 @@ -49,6 +49,9 @@ import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordedFrame; import jdk.jfr.consumer.RecordedStackTrace; +import jdk.jfr.internal.PrivateAccess; +import jdk.jfr.internal.Type; +import jdk.jfr.internal.util.Utils; /** * This is a helper class to QueryResolver. It handles the creation of fields @@ -60,9 +63,9 @@ final class FieldBuilder { private static final Set KNOWN_TYPES = createKnownTypes(); private final List eventTypes; - private final ValueDescriptor descriptor; private final Field field; private final String fieldName; + private ValueDescriptor descriptor; public FieldBuilder(List eventTypes, FilteredType type, String fieldName) { this.eventTypes = eventTypes; @@ -77,12 +80,15 @@ public List build() { return List.of(field); } + configureAliases(); if (descriptor != null) { field.fixedWidth = !descriptor.getTypeName().equals("java.lang.String"); field.dataType = descriptor.getTypeName(); field.label = makeLabel(descriptor, hasDuration()); field.alignLeft = true; - field.valueGetter = valueGetter(field.name); + if (field.valueGetter == null) { + field.valueGetter = valueGetter(field.name); + } configureNumericTypes(); configureTime(); @@ -113,22 +119,6 @@ private boolean hasDuration() { } private boolean configureSyntheticFields() { - if (fieldName.equals("stackTrace.topApplicationFrame")) { - configureTopApplicationFrameField(); - return true; - } - if (fieldName.equals("stackTrace.notInit")) { - configureNotInitFrameField(); - return true; - } - if (fieldName.equals("stackTrace.topFrame.class")) { - configureTopFrameClassField(); - return true; - } - if (fieldName.equals("stackTrace.topFrame")) { - configureTopFrameField(); - return true; - } if (fieldName.equals("id") && field.type.getName().equals("jdk.ActiveSetting")) { configureEventTypeIdField(); return true; @@ -144,6 +134,73 @@ private boolean configureSyntheticFields() { return false; } + private void configureAliases() { + configureFrame("topFrame", FieldBuilder::topFrame); + configureFrame("topApplicationFrame", FieldBuilder::topApplicationFrame); + configureFrame("topNotInitFrame", FieldBuilder::topNotInitFrame); + } + + private void configureFrame(String frameName, Function getter) { + String name = "stackTrace." + frameName; + if (!fieldName.startsWith(name)) { + return; + } + ValueDescriptor stackTrace = Utils.findField(field.type.getFields(), "stackTrace"); + if (stackTrace == null) { + return; + } + ValueDescriptor frames = Utils.findField(stackTrace.getFields(), "frames"); + if (frames == null) { + return; + } + int length = name.length(); + if (fieldName.length() == length) { + descriptor = frames; // Use array descriptor for now + field.valueGetter = getter; + return; + } + String subName = fieldName.substring(length + 1); + Type type = PrivateAccess.getInstance().getType(frames); + ValueDescriptor subField = type.getField(subName); + if (subField != null) { + descriptor = subField; + field.valueGetter = e -> { + if (getter.apply(e) instanceof RecordedFrame frame) { + return frame.getValue(subName); + } + return null; + }; + } + } + + private static RecordedFrame topFrame(RecordedEvent event) { + return findJavaFrame(event, x -> true); + } + + private static RecordedFrame topApplicationFrame(RecordedEvent event) { + return findJavaFrame(event, frame -> { + RecordedClass cl = frame.getMethod().getType(); + RecordedClassLoader classLoader = cl.getClassLoader(); + return classLoader != null && !"bootstrap".equals(classLoader.getName()); + }); + } + + private static Object topNotInitFrame(RecordedEvent event) { + return findJavaFrame(event, frame -> !frame.getMethod().getName().equals("")); + } + + private static RecordedFrame findJavaFrame(RecordedEvent event, Predicate condition) { + RecordedStackTrace st = event.getStackTrace(); + if (st != null) { + for (RecordedFrame frame : st.getFrames()) { + if (frame.isJavaFrame() && condition.test(frame)) { + return frame; + } + } + } + return null; + } + private void configureEventTypeIdField() { Map eventTypes = createEventTypeLookup(); field.alignLeft = true; @@ -166,65 +223,6 @@ private Map createEventTypeLookup() { return map; } - private void configureTopFrameField() { - field.alignLeft = true; - field.label = "Method"; - field.dataType = "jdk.types.Method"; - field.valueGetter = e -> { - RecordedStackTrace t = e.getStackTrace(); - return t != null ? t.getFrames().getFirst() : null; - }; - field.lexicalSort = true; - } - - private void configureTopFrameClassField() { - field.alignLeft = true; - field.label = "Class"; - field.dataType = "java.lang.Class"; - field.valueGetter = e -> { - RecordedStackTrace t = e.getStackTrace(); - if (t == null) { - return null; - } - return t.getFrames().getFirst().getMethod().getType(); - }; - field.lexicalSort = true; - } - - private void configureCustomFrame(Predicate condition) { - field.alignLeft = true; - field.dataType = "jdk.types.Frame"; - field.label = "Method"; - field.lexicalSort = true; - field.valueGetter = e -> { - RecordedStackTrace t = e.getStackTrace(); - if (t != null) { - for (RecordedFrame f : t.getFrames()) { - if (f.isJavaFrame()) { - if (condition.test(f)) { - return f; - } - } - } - } - return null; - }; - } - - private void configureNotInitFrameField() { - configureCustomFrame(frame -> { - return !frame.getMethod().getName().equals(""); - }); - } - - private void configureTopApplicationFrameField() { - configureCustomFrame(frame -> { - RecordedClass cl = frame.getMethod().getType(); - RecordedClassLoader classLoader = cl.getClassLoader(); - return classLoader != null && !"bootstrap".equals(classLoader.getName()); - }); - } - private void configureEventType(Function retriever) { field.alignLeft = true; field.dataType = String.class.getName(); @@ -234,6 +232,9 @@ private void configureEventType(Function retriever) { } private static String makeLabel(ValueDescriptor v, boolean hasDuration) { + if (v.getTypeName().equals("jdk.types.StackFrame")) { + return "Method"; + } String label = v.getLabel(); if (label == null) { return v.getName(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableSorter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableSorter.java index 8869516280960..6a7f2e94be125 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableSorter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableSorter.java @@ -24,6 +24,7 @@ */ package jdk.jfr.internal.query; +import java.math.BigDecimal; import java.util.Comparator; import java.util.function.Predicate; @@ -63,17 +64,80 @@ int sortOrderToFactor(SortOrder order) { @Override public int compare(Row rowA, Row rowB) { if (lexical) { - return compareObjects(rowA.getText(index), rowB.getText(index)); + return factor * compareObjects(rowA.getText(index), rowB.getText(index)); } else { - return compareObjects(rowA.getValue(index), rowB.getValue(index)); + return factor * compareObjects(rowA.getValue(index), rowB.getValue(index)); } } - private int compareObjects(Object a, Object b) { - if (a instanceof Comparable c1 && b instanceof Comparable c2) { - return factor * c1.compareTo(c2); + private static int compareObjects(Object a, Object b) { + if (a == b) { + return 0; } - return factor; + if (a == null) { + return -1; + } + if (b == null) { + return 1; + } + if (a instanceof String s1 && b instanceof String s2) { + return s1.compareTo(s2); + } + + if (a instanceof Number n1 && b instanceof Number n2) { + if (isIntegralType(n1)) { + if (isIntegralType(n2)) { + return Long.compare(n1.longValue(), n2.longValue()); + } + if (isFractionalType(n2)) { + return compare(n1.longValue(), n2.doubleValue()); + } + } + if (isFractionalType(n1)) { + if (isFractionalType(n2)) { + return Double.compare(n1.doubleValue(), n2.doubleValue()); + } + if (isIntegralType(n2)) { + return - compare(n2.longValue(), n1.doubleValue()); + } + } + } + if (a instanceof Number) { + return 1; + } + if (b instanceof Number) { + return -1; + } + // Comparison with the same class + if (a.getClass() == b.getClass() && a instanceof Comparable c1) { + return c1.compareTo((Comparable)b); + } + if (a instanceof Comparable) { + return 1; + } + if (b instanceof Comparable) { + return -1; + } + // Use something that is stable if it's not null, comparable or numeric + return Integer.compare(System.identityHashCode(a), System.identityHashCode(b)); + } + + private static int compare(long integral, double fractional) { + return BigDecimal.valueOf(integral).compareTo(BigDecimal.valueOf(fractional)); + } + + private static boolean isIntegralType(Number value) { + if (value instanceof Long || value instanceof Integer) { + return true; + } + if (value instanceof Short || value instanceof Byte) { + return true; + } + return false; + } + + private static boolean isFractionalType(Number number) { + return number instanceof Float || number instanceof Double; } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini index 8db19fdc239fe..b21b99e2dad91 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini @@ -186,7 +186,7 @@ table = "COLUMN 'Monitor Address', 'Class', 'Threads', 'Max Duration' label = "Deprecated Methods for Removal" table = "COLUMN 'Deprecated Method', 'Called from Class' FORMAT truncate-beginning, cell-height:10000;truncate-beginning - SELECT method AS m, SET(stackTrace.topFrame.class) + SELECT method AS m, SET(stackTrace.topFrame.method.type) FROM DeprecatedInvocation WHERE forRemoval = 'true' GROUP BY m @@ -266,7 +266,7 @@ table = "COLUMN 'Message', 'Count' [application.exception-by-site] label ="Exceptions by Site" table = "COLUMN 'Method', 'Count' - SELECT stackTrace.notInit AS S, COUNT(startTime) AS C + SELECT stackTrace.topNotInitFrame AS S, COUNT(startTime) AS C FROM JavaErrorThrow, JavaExceptionThrow GROUP BY S ORDER BY C DESC" [application.file-reads-by-path] diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java index b5ae906c71cb1..c15e87709c5a8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java @@ -48,6 +48,7 @@ import jdk.jfr.Event; import jdk.jfr.EventType; import jdk.jfr.RecordingState; +import jdk.jfr.ValueDescriptor; import jdk.jfr.internal.LogLevel; import jdk.jfr.internal.LogTag; import jdk.jfr.internal.Logger; @@ -438,4 +439,13 @@ public static long multiplyOverflow(long a, long b, long defaultValue) { return defaultValue; } } + + public static ValueDescriptor findField(List fields, String name) { + for (ValueDescriptor v : fields) { + if (v.getName().equals(name)) { + return v; + } + } + return null; + } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 06796db98847a..ff772ce74b0b9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package jdk.jpackage.internal; -import java.io.IOException; import java.text.MessageFormat; import java.util.Map; import java.util.Optional; @@ -148,20 +147,6 @@ private static void doValidate(Map params) // No need to validate --mac-app-image-sign-identity, since it is // pass through option. - - // Signing will not work without Xcode with command line developer tools - try { - ProcessBuilder pb = new ProcessBuilder("/usr/bin/xcrun", "--help"); - Process p = pb.start(); - int code = p.waitFor(); - if (code != 0) { - throw new ConfigException( - I18N.getString("error.no.xcode.signing"), - I18N.getString("error.no.xcode.signing.advice")); - } - } catch (IOException | InterruptedException ex) { - throw new ConfigException(ex); - } } } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index 472e58cd1a2e3..4b2920391a6a9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -57,7 +57,6 @@ import static jdk.jpackage.internal.MacAppBundler.DEVELOPER_ID_APP_SIGNING_KEY; import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; -import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; @@ -76,8 +75,6 @@ import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; -import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; -import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; public class MacAppImageBuilder extends AbstractAppImageBuilder { @@ -754,6 +751,14 @@ private static void runCodesign( "message.codesign.failed.reason.app.content")); } + // Signing might not work without Xcode with command line + // developer tools. Show user if Xcode is missing as possible + // reason. + if (!isXcodeDevToolsInstalled()) { + Log.info(I18N.getString( + "message.codesign.failed.reason.xcode.tools")); + } + // Log "codesign" output Log.info(MessageFormat.format(I18N.getString( "error.tool.failed.with.output"), "codesign")); @@ -764,6 +769,16 @@ private static void runCodesign( } } + private static boolean isXcodeDevToolsInstalled() { + try { + Executor.of("/usr/bin/xcrun", "--help").executeExpectSuccess(); + } catch (IOException e) { + return false; + } + + return true; + } + static void signAppBundle( Map params, Path appLocation, String signingIdentity, String identifierPrefix, Path entitlements) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index 04a454b03d582..e0a555b369854 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -39,8 +39,6 @@ error.no-app-signing-key.advice=Install your app signing keys into your Mac Keyc error.no-pkg-signing-key=No Mac App Store Installer Signing Key error.no-pkg-signing-key.advice=Install your app signing keys into your Mac Keychain using XCode. error.certificate.expired=Error: Certificate expired {0} -error.no.xcode.signing=Xcode with command line developer tools is required for signing -error.no.xcode.signing.advice=Install Xcode with command line developer tools. error.cert.not.found=No certificate found matching [{0}] using keychain [{1}] error.multiple.certs.found=WARNING: Multiple certificates found matching [{0}] using keychain [{1}], using first one error.app-image.mac-sign.required=Error: --mac-sign option is required with predefined application image and with type [app-image] @@ -95,5 +93,6 @@ message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trus message.setfile.dmg=Setting custom icon on DMG file skipped because 'SetFile' utility was not found. Installing Xcode with Command Line Tools should resolve this issue. message.install-dir-ignored=Warning: "--install-dir" is not supported by DMG and will be default to /Applications. message.codesign.failed.reason.app.content="codesign" failed and additional application content was supplied via the "--app-content" parameter. Probably the additional content broke the integrity of the application bundle and caused the failure. Ensure content supplied via the "--app-content" parameter does not break the integrity of the application bundle, or add it in the post-processing step. +message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem. warning.unsigned.app.image=Warning: Using unsigned app-image to build signed {0}. warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties index 0d2cfb5b6c07b..c0aece573e033 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties @@ -39,8 +39,6 @@ error.no-app-signing-key.advice=Installieren Sie Ihre App-Signaturschlüssel mit error.no-pkg-signing-key=Kein Signaturschlüssel für Mac App Store-Installationsprogramm error.no-pkg-signing-key.advice=Installieren Sie Ihre App-Signaturschlüssel mit XCode in Ihrem Mac-Schlüsselbund. error.certificate.expired=Fehler: Zertifikat abgelaufen {0} -error.no.xcode.signing=Für die Signatur ist Xcode mit Befehlszeilen-Entwicklertools erforderlich -error.no.xcode.signing.advice=Installieren Sie Xcode mit Befehlszeilen-Entwicklertools. error.cert.not.found=Kein Zertifikat gefunden, das [{0}] mit Schlüsselbund [{1}] entspricht error.multiple.certs.found=WARNUNG: Mehrere Zertifikate gefunden, die [{0}] mit Schlüsselbund [{1}] entsprechen. Es wird das erste Zertifikat verwendet error.app-image.mac-sign.required=Fehler: Die Option "--mac-sign" ist mit einem vordefinierten Anwendungsimage und Typ [app-image] erforderlich @@ -95,5 +93,6 @@ message.signing.pkg=Warnung: Zum Signieren von PKG müssen Sie möglicherweise m message.setfile.dmg=Das Festlegen des benutzerdefinierten Symbols für die DMG-Datei wurde übersprungen, weil das Utility "SetFile" nicht gefunden wurde. Durch Installieren von Xcode mit Befehlszeilentools sollte dieses Problem behoben werden. message.install-dir-ignored=Warnung: "--install-dir" wird von DMG nicht unterstützt. Stattdessen wird standardmäßig /Applications verwendet. message.codesign.failed.reason.app.content="codesign" war nicht erfolgreich, und zusätzlicher Anwendungsinhalt wurde über den Parameter "--app-content" angegeben. Wahrscheinlich hat der zusätzliche Inhalt die Integrität des Anwendungs-Bundles beeinträchtigt und den Fehler verursacht. Stellen Sie sicher, das der über den Parameter "--app-content" angegebene Inhalt nicht die Integrität des Anwendungs-Bundles beeinträchtigt, oder fügen Sie ihn im Nachverarbeitungsschritt hinzu. +message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem. warning.unsigned.app.image=Warnung: Nicht signiertes app-image wird zum Erstellen von signiertem {0} verwendet. warning.per.user.app.image.signed=Warnung: Konfiguration der installierten Anwendung pro Benutzer wird nicht unterstützt, da "{0}" im vordefinierten signierten Anwendungsimage fehlt. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties index 08e6dd2b4e8c3..166e7ffb67009 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties @@ -39,8 +39,6 @@ error.no-app-signing-key.advice=XCodeを使用してアプリケーションの error.no-pkg-signing-key=Mac App Storeインストーラの署名キーがありません error.no-pkg-signing-key.advice=XCodeを使用してアプリケーションの署名キーをMacキーチェーンにインストールします。 error.certificate.expired=エラー: 証明書は{0}に期限が切れました -error.no.xcode.signing=署名には、Xcodeとコマンドライン・デベロッパ・ツールが必要です -error.no.xcode.signing.advice=Xcodeとコマンドライン・デベロッパ・ツールをインストールしてください。 error.cert.not.found=キーチェーン[{1}]を使用する[{0}]と一致する証明書が見つかりません error.multiple.certs.found=警告: キーチェーン[{1}]を使用する[{0}]と一致する複数の証明書が見つかりました。最初のものを使用します error.app-image.mac-sign.required=エラー: --mac-signオプションは、事前定義済アプリケーション・イメージおよびタイプ[app-image]で必要です @@ -95,5 +93,6 @@ message.signing.pkg=警告: PKGへの署名の場合、「キーチェーン・ message.setfile.dmg='SetFile'ユーティリティが見つからないため、DMGファイルでのカスタム・アイコンの設定がスキップされました。Xcodeとコマンド・ライン・ツールをインストールすると、この問題は解決されます。 message.install-dir-ignored=警告: "--install-dir"はDMGでサポートされていません。/Applicationsにデフォルト設定されます。 message.codesign.failed.reason.app.content="codesign"が失敗したため、追加のアプリケーション・コンテンツが、"--app-content"パラメータを介して提供されました。追加のコンテンツにより、アプリケーション・バンドルの整合性が損われ、失敗の原因になった可能性があります。"--app-content"パラメータを介して提供されたコンテンツによって、アプリケーション・バンドルの整合性が損われていないことを確認するか、処理後のステップで追加してください。 +message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem. warning.unsigned.app.image=警告: 署名されていないapp-imageを使用して署名された{0}を作成します。 warning.per.user.app.image.signed=警告: 事前定義済の署名付きアプリケーション・イメージに"{0}"がないため、インストール済アプリケーションのユーザーごとの構成はサポートされません。 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties index f4e75caa1ef8c..a620e8dacdd63 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties @@ -39,8 +39,6 @@ error.no-app-signing-key.advice=使用 XCode 将应用程序签名密钥安装 error.no-pkg-signing-key=无 Mac App Store 安装程序签名密钥 error.no-pkg-signing-key.advice=使用 XCode 将应用程序签名密钥安装到 Mac 密钥链中。 error.certificate.expired=错误: 证书已失效 {0} -error.no.xcode.signing=需要使用带命令行开发人员工具的 Xcode 进行签名 -error.no.xcode.signing.advice=安装带命令行开发人员工具的 Xcode。 error.cert.not.found=使用密钥链 [{1}] 找不到与 [{0}] 匹配的证书 error.multiple.certs.found=警告:使用密钥链 [{1}] 找到多个与 [{0}] 匹配的证书,将使用第一个证书 error.app-image.mac-sign.required=错误:预定义的应用程序映像和类型 [app image] 需要 --mac-sign 选项 @@ -95,5 +93,6 @@ message.signing.pkg=警告:要对 PKG 进行签名,可能需要使用“密 message.setfile.dmg=由于未找到 'SetFile' 实用程序,跳过了针对 DMG 文件设置定制图标的操作。安装带命令行工具的 Xcode 应能解决此问题。 message.install-dir-ignored=警告:"--install-dir" 不受 DMG 支持,将默认为 /Applications。 message.codesign.failed.reason.app.content="codesign" 失败,并通过 "--app-content" 参数提供了附加应用程序内容。可能是附加内容破坏了应用程序包的完整性,导致了故障。请确保通过 "--app-content" 参数提供的内容不会破坏应用程序包的完整性,或者在后处理步骤中添加该内容。 +message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem. warning.unsigned.app.image=警告:使用未签名的 app-image 生成已签名的 {0}。 warning.per.user.app.image.signed=警告:由于预定义的已签名应用程序映像中缺少 "{0}",不支持对已安装应用程序的每用户配置提供支持。 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index 4e46d9a59cc52..b507cc955bd75 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.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 @@ -27,14 +27,20 @@ import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Map; import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; +import static jdk.jpackage.internal.StandardBundlerParam.OUTPUT_DIR; +import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; import jdk.jpackage.internal.resources.ResourceLocator; /* @@ -73,8 +79,21 @@ protected void copyApplication(Map params) throws IOException { Path inputPath = SOURCE_DIR.fetchFrom(params); if (inputPath != null) { - IOUtils.copyRecursive(SOURCE_DIR.fetchFrom(params), - appLayout.appDirectory()); + inputPath = inputPath.toAbsolutePath(); + + List excludes = new ArrayList<>(); + + for (var path : List.of(TEMP_ROOT.fetchFrom(params), OUTPUT_DIR.fetchFrom(params), root)) { + if (Files.isDirectory(path)) { + path = path.toAbsolutePath(); + if (path.startsWith(inputPath) && !Files.isSameFile(path, inputPath)) { + excludes.add(path); + } + } + } + + IOUtils.copyRecursive(inputPath, + appLayout.appDirectory().toAbsolutePath(), excludes); } AppImageFile.save(root, params); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index 16cd89d9d52d0..52579f5029666 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,9 +89,6 @@ public class Arguments { private List allOptions = null; - private String input = null; - private Path output = null; - private boolean hasMainJar = false; private boolean hasMainClass = false; private boolean hasMainModule = false; @@ -135,9 +132,6 @@ public Arguments(String[] args) { allOptions = new ArrayList<>(); addLaunchers = new ArrayList<>(); - - output = Paths.get("").toAbsolutePath(); - deployParams.setOutput(output); } // CLIOptions is public for DeployParamsTest @@ -147,13 +141,12 @@ public enum CLIOptions { }), INPUT ("input", "i", OptionCategories.PROPERTY, () -> { - context().input = popArg(); - setOptionValue("input", context().input); + setOptionValue("input", popArg()); }), OUTPUT ("dest", "d", OptionCategories.PROPERTY, () -> { - context().output = Path.of(popArg()); - context().deployParams.setOutput(context().output); + var path = Path.of(popArg()); + setOptionValue("dest", path); }), DESCRIPTION ("description", OptionCategories.PROPERTY), @@ -711,7 +704,8 @@ private void generateBundle(Map params) Map localParams = new HashMap<>(params); try { bundler.validate(localParams); - Path result = bundler.execute(localParams, deployParams.outdir); + Path result = bundler.execute(localParams, + StandardBundlerParam.OUTPUT_DIR.fetchFrom(params)); if (result == null) { throw new PackagerException("MSG_BundlerFailed", bundler.getID(), bundler.getName()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java index 3a96703e1b557..18645f17a6dfd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.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 @@ -49,15 +49,9 @@ public class DeployParams { String targetFormat = null; // means default type for this platform - Path outdir = null; - // raw arguments to the bundler Map bundlerArguments = new LinkedHashMap<>(); - public void setOutput(Path output) { - outdir = output; - } - static class Template { Path in; Path out; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java index 0262ae1ac73ff..dd1cc4a24b450 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -112,7 +112,10 @@ int execute() throws IOException { pb.redirectOutput(ProcessBuilder.Redirect.DISCARD); } - Log.verbose(String.format("Running %s", createLogMessage(pb, true))); + if (!quietCommand) { + Log.verbose(String.format("Running %s", createLogMessage(pb, true))); + } + Process p = pb.start(); int code = 0; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java index f4b0483bf98ea..573109a004bc0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -121,29 +121,52 @@ public static void copyRecursive(Path src, Path dest, CopyOption... options) } public static void copyRecursive(Path src, Path dest, - final List excludes, CopyOption... options) + final List excludes, CopyOption... options) throws IOException { + + List copyActions = new ArrayList<>(); + Files.walkFileTree(src, new SimpleFileVisitor() { @Override public FileVisitResult preVisitDirectory(final Path dir, - final BasicFileAttributes attrs) throws IOException { - if (excludes.contains(dir.toFile().getName())) { + final BasicFileAttributes attrs) { + if (isPathMatch(dir, excludes)) { return FileVisitResult.SKIP_SUBTREE; } else { - Files.createDirectories(dest.resolve(src.relativize(dir))); + copyActions.add(new CopyAction(null, dest.resolve(src. + relativize(dir)))); return FileVisitResult.CONTINUE; } } @Override public FileVisitResult visitFile(final Path file, - final BasicFileAttributes attrs) throws IOException { - if (!excludes.contains(file.toFile().getName())) { - Files.copy(file, dest.resolve(src.relativize(file)), options); + final BasicFileAttributes attrs) { + if (!isPathMatch(file, excludes)) { + copyActions.add(new CopyAction(file, dest.resolve(src. + relativize(file)))); } return FileVisitResult.CONTINUE; } }); + + for (var copyAction : copyActions) { + copyAction.apply(options); + } + } + + private static record CopyAction(Path src, Path dest) { + void apply(CopyOption... options) throws IOException { + if (src == null) { + Files.createDirectories(dest); + } else { + Files.copy(src, dest, options); + } + } + } + + private static boolean isPathMatch(Path what, List paths) { + return paths.stream().anyMatch(what::endsWith); } public static void copyFile(Path sourceFile, Path destFile) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index a50293aedb5b8..718f186c9547a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.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 @@ -43,7 +43,6 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -100,6 +99,14 @@ class StandardBundlerParam extends BundlerParamInfo { (s, p) -> Path.of(s) ); + static final StandardBundlerParam OUTPUT_DIR = + new StandardBundlerParam<>( + Arguments.CLIOptions.OUTPUT.getId(), + Path.class, + p -> Path.of("").toAbsolutePath(), + (s, p) -> Path.of(s) + ); + // note that each bundler is likely to replace this one with // their own converter static final StandardBundlerParam MAIN_JAR = @@ -596,7 +603,7 @@ static void copyPredefinedRuntimeImage(Map params, } // copy whole runtime, need to skip jmods and src.zip - final List excludes = Arrays.asList("jmods", "src.zip"); + final List excludes = Arrays.asList(Path.of("jmods"), Path.of("src.zip")); IOUtils.copyRecursive(topImage, appLayout.runtimeHomeDirectory(), excludes, LinkOption.NOFOLLOW_LINKS); diff --git a/src/jdk.jpackage/share/native/common/Log.cpp b/src/jdk.jpackage/share/native/common/Log.cpp index 66154ee8247e2..8227bb1cce4dd 100644 --- a/src/jdk.jpackage/share/native/common/Log.cpp +++ b/src/jdk.jpackage/share/native/common/Log.cpp @@ -40,10 +40,6 @@ namespace { // variables are initialized if any. This will result in AV. To avoid such // use cases keep logging module free from static variables that require // initialization with functions called by CRT. - // - - // by default log everything - const Logger::LogLevel defaultLogLevel = Logger::LOG_TRACE; char defaultLogAppenderMemory[sizeof(StreamLogAppender)] = {}; diff --git a/src/jdk.jsobject/share/classes/module-info.java b/src/jdk.jsobject/share/classes/module-info.java index 7903dbb2c2433..22ee6576af3c7 100644 --- a/src/jdk.jsobject/share/classes/module-info.java +++ b/src/jdk.jsobject/share/classes/module-info.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 @@ -28,7 +28,10 @@ * * @moduleGraph * @since 9 + * @deprecated The jdk.jsobject module will be delivered with JavaFX. */ +@Deprecated(since = "24", forRemoval = true) +@SuppressWarnings("removal") module jdk.jsobject { exports netscape.javascript; } diff --git a/src/jdk.jsobject/share/classes/netscape/javascript/JSException.java b/src/jdk.jsobject/share/classes/netscape/javascript/JSException.java index 5d677cccec8f4..7fe8ad8dd04ae 100644 --- a/src/jdk.jsobject/share/classes/netscape/javascript/JSException.java +++ b/src/jdk.jsobject/share/classes/netscape/javascript/JSException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,10 @@ * a marker class to indicate an exception relating to the JavaScript * interface. * @since 1.5 + * @deprecated The jdk.jsobject module will be delivered with JavaFX. */ +@Deprecated(since = "24", forRemoval = true) +@SuppressWarnings("removal") public class JSException extends RuntimeException { private static final long serialVersionUID = 2778103758223661489L; diff --git a/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java b/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java index 0eff2d18e264d..f038728d7bd85 100644 --- a/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java +++ b/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,10 @@ * engine is converted to JavaScript data types. *

            * @since 1.5 + * @deprecated The jdk.jsobject module will be delivered with JavaFX. */ +@Deprecated(since = "24", forRemoval = true) +@SuppressWarnings("removal") public abstract class JSObject { /** * Constructs a new JSObject. Users should neither call this method nor diff --git a/src/jdk.jsobject/share/classes/netscape/javascript/package-info.java b/src/jdk.jsobject/share/classes/netscape/javascript/package-info.java index fcc97132a5074..f7aae37db50b0 100644 --- a/src/jdk.jsobject/share/classes/netscape/javascript/package-info.java +++ b/src/jdk.jsobject/share/classes/netscape/javascript/package-info.java @@ -24,6 +24,12 @@ */ /** + *

            + * Deprecated, for removal: This API element is subject to removal + * in a future version.
            + * The jdk.jsobject module will be delivered with JavaFX. + *

            + * *

            * Provides Java code the ability to access the JavaScript engine and the * HTML DOM in the web browser. diff --git a/src/jdk.management/share/classes/com/sun/management/internal/DiagnosticCommandImpl.java b/src/jdk.management/share/classes/com/sun/management/internal/DiagnosticCommandImpl.java index be84beb03bb46..eee0ea051d4fe 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/DiagnosticCommandImpl.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/DiagnosticCommandImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, 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 @@ -317,7 +317,7 @@ private Descriptor commandDescriptor(Wrapper w) throws IllegalArgumentException for (DiagnosticCommandArgumentInfo arginfo : w.info.getArgumentsInfo()) { HashMap argmap = new HashMap<>(); argmap.put("dcmd.arg.name", arginfo.getName()); - argmap.put("dcmd.arg.type", arginfo.getType()); + argmap.put("dcmd.arg.type", sanitiseType(arginfo.getType())); argmap.put("dcmd.arg.description", arginfo.getDescription()); argmap.put("dcmd.arg.isMandatory", arginfo.isMandatory()); argmap.put("dcmd.arg.isMultiple", arginfo.isMultiple()); @@ -335,6 +335,22 @@ private Descriptor commandDescriptor(Wrapper w) throws IllegalArgumentException return new ImmutableDescriptor(map); } + // Type names that will be published in dcmd.arg.type: + private static final String [] publicTypes = new String [] { "INT", "STRING", "BOOLEAN", "STRING SET", "MEMORY SIZE", "NANOTIME" }; + + private static final String sanitiseType(String typeName) { + // For any typeName not in the set to be made public, return "STRING". + if (typeName == null) { + return null; + } + for (String t : publicTypes) { + if (typeName.equals(t)) { + return t; + } + } + return "STRING"; + } + private static final String notifName = "javax.management.Notification"; diff --git a/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsClient.java b/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsClient.java index 0d5ca39c6f74b..3d55186bac882 100644 --- a/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsClient.java +++ b/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsClient.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 @@ -46,11 +46,15 @@ import javax.naming.OperationNotSupportedException; import javax.naming.ServiceUnavailableException; +import java.time.Duration; import java.util.Arrays; import java.util.Collections; import java.util.Map; import java.util.HashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.IntStream; import jdk.internal.ref.CleanerFactory; import sun.security.jca.JCAUtil; @@ -95,7 +99,7 @@ public class DnsClient { private static final int DEFAULT_PORT = 53; private static final int TRANSACTION_ID_BOUND = 0x10000; - private static final int MIN_TIMEOUT = 50; // msec after which there are no retries. + private static final int MIN_TIMEOUT = 0; // msec after which there are no retries. private static final SecureRandom random = JCAUtil.getSecureRandom(); private InetAddress[] servers; private int[] serverPorts; @@ -223,20 +227,28 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, Exception caughtException = null; boolean[] doNotRetry = new boolean[servers.length]; - + // Holder for unfulfilled timeouts left for each server + AtomicLong[] unfulfilledUdpTimeouts = IntStream.range(0, servers.length) + .mapToObj(_ -> new AtomicLong()) + .toArray(AtomicLong[]::new); try { // // The UDP retry strategy is to try the 1st server, and then // each server in order. If no answer, double the timeout // and try each server again. // - for (int retry = 0; retry < retries; retry++) { - + for (int retry = 0; retry <= retries; retry++) { + boolean isLastRetry = retry == retries; // Try each name server. for (int i = 0; i < servers.length; i++) { if (doNotRetry[i]) { continue; } + // unfulfilledServerTimeout is always >= 0 + AtomicLong unfulfilledServerTimeout = unfulfilledUdpTimeouts[i]; + if (isLastRetry && unfulfilledServerTimeout.get() == 0) { + continue; + } // send the request packet and wait for a response. try { @@ -245,7 +257,7 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, } byte[] msg = doUdpQuery(pkt, servers[i], serverPorts[i], - retry, xid); + retry, xid, unfulfilledServerTimeout, isLastRetry); assert msg != null; Header hdr = new Header(msg, msg.length); @@ -259,7 +271,12 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, // Try each server, starting with the one that just // provided the truncated message. - int retryTimeout = (timeout * (1 << retry)); + long retryTimeout = Math.clamp( + timeout * (1L << (isLastRetry + ? retry - 1 + : retry)), + 0L, Integer.MAX_VALUE); + ; for (int j = 0; j < servers.length; j++) { int ij = (i + j) % servers.length; if (doNotRetry[ij]) { @@ -301,15 +318,23 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, if (debug) { dprint("Caught Exception:" + ex); } - if (caughtException == null) { + if (caughtException == null || servers.length == 1) { + // If there are several servers we continue trying with other + // servers, otherwise this exception will be reported caughtException = ex; + } else { + // Best reporting effort + caughtException.addSuppressed(ex); } doNotRetry[i] = true; } catch (IOException e) { if (debug) { dprint("Caught IOException:" + e); } - if (caughtException == null) { + if (caughtException instanceof CommunicationException ce) { + e.addSuppressed(ce); + caughtException = e; + } else if (caughtException == null) { caughtException = e; } } catch (ClosedSelectorException e) { @@ -327,8 +352,13 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, caughtException = e; } } catch (NamingException e) { - if (caughtException == null) { + if (caughtException == null || servers.length == 1) { + // If there are several servers we continue trying with other + // servers, otherwise this exception will be reported caughtException = e; + } else { + // Best reporting effort + caughtException.addSuppressed(e); } doNotRetry[i] = true; } @@ -339,8 +369,8 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, reqs.remove(xid); // cleanup } - if (caughtException instanceof NamingException) { - throw (NamingException) caughtException; + if (caughtException instanceof NamingException ne) { + throw ne; } // A network timeout or other error occurred. NamingException ne = new CommunicationException("DNS error"); @@ -424,10 +454,32 @@ ResourceRecords queryZone(DnsName zone, int qclass, boolean recursion) * is enqueued with the corresponding xid in 'resps'. */ private byte[] doUdpQuery(Packet pkt, InetAddress server, - int port, int retry, int xid) + int port, int retry, int xid, + AtomicLong unfulfilledTimeout, + boolean unfulfilledOnly) throws IOException, NamingException { udpChannelLock.lock(); + + + // use 1L below to ensure conversion to long and avoid potential + // integer overflow (timeout is an int). + // no point in supporting timeout > Integer.MAX_VALUE, clamp if needed + // timeout remaining after successive 'blockingReceive()'. + long thisIterationTimeout = unfulfilledOnly + ? 0L + : Math.clamp(timeout * (1L << retry), 0L, Integer.MAX_VALUE); + + // Compensate with server's positive unfulfilled timeout. + // Calling method never supplies zero 'unfulfilledTimeout' when + // 'unfulfilledOnly' is 'true', therefore 'thisIterationTimeout' + // will always be a positive number, ie infinite timeout + // is not possible. + thisIterationTimeout += unfulfilledTimeout.get(); + + // Track left timeout for the current retry + long timeoutLeft = thisIterationTimeout; + long start = 0; try { try (DatagramChannel udpChannel = getDatagramChannel()) { ByteBuffer opkt = ByteBuffer.wrap(pkt.getData(), 0, pkt.length()); @@ -436,13 +488,11 @@ private byte[] doUdpQuery(Packet pkt, InetAddress server, // Packets may only be sent to or received from this server address InetSocketAddress target = new InetSocketAddress(server, port); udpChannel.connect(target); - int pktTimeout = (timeout * (1 << retry)); udpChannel.write(opkt); - // timeout remaining after successive 'blockingReceive()' - int timeoutLeft = pktTimeout; int cnt = 0; boolean gotData = false; + start = System.nanoTime(); do { // prepare for retry if (gotData) { @@ -456,9 +506,7 @@ private byte[] doUdpQuery(Packet pkt, InetAddress server, ") for:" + xid + " sock-timeout:" + timeoutLeft + " ms."); } - long start = System.currentTimeMillis(); - gotData = blockingReceive(udpChannel, ipkt, timeoutLeft); - long end = System.currentTimeMillis(); + gotData = blockingReceive(udpChannel, target, ipkt, timeoutLeft); assert gotData || ipkt.position() == 0; if (gotData && isMatchResponse(data, xid)) { return data; @@ -471,17 +519,23 @@ private byte[] doUdpQuery(Packet pkt, InetAddress server, return cachedMsg; } } - timeoutLeft = pktTimeout - ((int) (end - start)); + long elapsedMillis = TimeUnit.NANOSECONDS + .toMillis(System.nanoTime() - start); + timeoutLeft = thisIterationTimeout - elapsedMillis; } while (timeoutLeft > MIN_TIMEOUT); // no matching packets received within the timeout throw new SocketTimeoutException(); } } finally { + long carryoverTimeout = thisIterationTimeout - + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); + unfulfilledTimeout.set(Math.max(0, carryoverTimeout)); udpChannelLock.unlock(); } } - boolean blockingReceive(DatagramChannel dc, ByteBuffer buffer, long timeout) throws IOException { + boolean blockingReceive(DatagramChannel dc, InetSocketAddress target, + ByteBuffer buffer, long timeout) throws IOException { boolean dataReceived = false; // The provided datagram channel will be used by the caller only to receive data after // it is put to non-blocking mode @@ -491,10 +545,15 @@ boolean blockingReceive(DatagramChannel dc, ByteBuffer buffer, long timeout) thr udpChannelSelector.select(timeout); var keys = udpChannelSelector.selectedKeys(); if (keys.contains(selectionKey) && selectionKey.isReadable()) { - dc.receive(buffer); - dataReceived = true; + int before = buffer.position(); + var senderAddress = dc.receive(buffer); + // Empty packets are ignored + dataReceived = target.equals(senderAddress) && buffer.position() > before; + } + // Avoid contention with Selector.close() if called by a clean-up thread + synchronized (keys) { + keys.clear(); } - keys.clear(); } finally { selectionKey.cancel(); // Flush the canceled key out of the selected key set @@ -750,14 +809,19 @@ class Tcp { private final Socket sock; private final java.io.InputStream in; final java.io.OutputStream out; - private int timeoutLeft; + private long timeoutLeft; - Tcp(InetAddress server, int port, int timeout) throws IOException { + Tcp(InetAddress server, int port, long timeout) throws IOException { sock = new Socket(); try { - long start = System.currentTimeMillis(); - sock.connect(new InetSocketAddress(server, port), timeout); - timeoutLeft = (int) (timeout - (System.currentTimeMillis() - start)); + long start = System.nanoTime(); + // It is safe to cast to int since the value is + // clamped by the caller + int intTimeout = (int) timeout; + sock.connect(new InetSocketAddress(server, port), intTimeout); + timeoutLeft = Duration.ofMillis(timeout) + .minus(Duration.ofNanos((System.nanoTime() - start))) + .toMillis(); if (timeoutLeft <= 0) throw new SocketTimeoutException(); @@ -785,14 +849,16 @@ private interface SocketReadOp { private int readWithTimeout(SocketReadOp reader) throws IOException { if (timeoutLeft <= 0) throw new SocketTimeoutException(); - - sock.setSoTimeout(timeoutLeft); - long start = System.currentTimeMillis(); + // It is safe to cast to int since the value is clamped + int intTimeout = (int) timeoutLeft; + sock.setSoTimeout(intTimeout); + long start = System.nanoTime(); try { return reader.read(); } finally { - timeoutLeft -= (int) (System.currentTimeMillis() - start); + timeoutLeft -= TimeUnit.NANOSECONDS.toMillis( + System.nanoTime() - start); } } diff --git a/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsContext.java b/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsContext.java index 028108494af87..fe35a4979cc3b 100644 --- a/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsContext.java +++ b/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsContext.java @@ -176,13 +176,13 @@ public Object addToEnvironment(String propName, Object propVal) } else if (propName.equals(INIT_TIMEOUT)) { int val = Integer.parseInt((String) propVal); if (timeout != val) { - timeout = val; + timeout = Math.max(val, 0); resolver = null; } } else if (propName.equals(RETRIES)) { int val = Integer.parseInt((String) propVal); if (retries != val) { - retries = val; + retries = Math.clamp(val, 1, 30); resolver = null; } } @@ -257,11 +257,11 @@ private void initFromEnvironment() val = (String) environment.get(INIT_TIMEOUT); timeout = (val == null) ? DEFAULT_INIT_TIMEOUT - : Integer.parseInt(val); + : Math.max(Integer.parseInt(val), 0); val = (String) environment.get(RETRIES); retries = (val == null) ? DEFAULT_RETRIES - : Integer.parseInt(val); + : Math.clamp(Integer.parseInt(val), 1, 30); } private CT getLookupCT(String attrId) diff --git a/src/jdk.sctp/share/classes/com/sun/nio/sctp/SctpMultiChannel.java b/src/jdk.sctp/share/classes/com/sun/nio/sctp/SctpMultiChannel.java index b906917393852..290838755cd87 100644 --- a/src/jdk.sctp/share/classes/com/sun/nio/sctp/SctpMultiChannel.java +++ b/src/jdk.sctp/share/classes/com/sun/nio/sctp/SctpMultiChannel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -481,14 +481,14 @@ public abstract T getOption(SctpSocketOption name, * @param name * The socket option * - * @param association - * The association whose option should be set, or {@code null} - * if this option should be set at the channel's socket level. - * * @param value * The value of the socket option. A value of {@code null} may be * a valid value for some socket options. * + * @param association + * The association whose option should be set, or {@code null} + * if this option should be set at the channel's socket level. + * * @return This channel * * @throws UnsupportedOperationException diff --git a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java index 24f26d4364b94..18016a07260fb 100644 --- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java +++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java @@ -43,7 +43,7 @@ import sun.security.jgss.krb5.Krb5Util; import sun.security.krb5.Credentials; import sun.security.util.Debug; -import sun.security.util.HexDumpEncoder; + import static sun.security.util.ResourcesMgr.getAuthResourceString; /** @@ -769,15 +769,11 @@ private void attemptAuthentication(boolean getPasswdFromSharedState) if (debug != null) { debug.println("principal is " + principal); - HexDumpEncoder hd = new HexDumpEncoder(); if (ktab != null) { debug.println("Will use keytab"); } else if (storeKey) { for (int i = 0; i < encKeys.length; i++) { - debug.println("EncryptionKey: keyType=" + - encKeys[i].getEType() + - " keyBytes (hex dump)=" + - hd.encodeBuffer(encKeys[i].getBytes())); + debug.println(encKeys[i].toString()); } } } @@ -868,7 +864,7 @@ private void promptForPass(boolean getPasswdFromSharedState) } if (debug != null) { debug.println - ("password is " + new String(password)); + ("Get password from shared state"); } return; } diff --git a/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/helper.js b/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/helper.js index 78c71c0fdb079..3426e74ba4115 100644 --- a/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/helper.js +++ b/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/helper.js @@ -57,6 +57,11 @@ function hasAnyNode(selector) { return new AnySelector(selector); } +// Select the nodes for which the given property is defined. +function hasProperty(property) { + return new MatcherSelector(new Properties.InvertPropertyMatcher(new Properties.RegexpPropertyMatcher(property, ""))); +} + // Select the nodes whose given property matches a given regular expression. function matches(property, regexp) { return new MatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp)); diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/customNodeInfo.filter b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/customNodeInfo.filter index 3f7956dc1ee07..bcdd86ba7d37b 100644 --- a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/customNodeInfo.filter +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/customNodeInfo.filter @@ -30,3 +30,7 @@ editProperty(matches("name", "CallLeaf|CallLeafNoFP"), ["dump_spec"], "extra_lab function(dump_spec) {return callLeafInfo(dump_spec[0], 1);}); editProperty(matches("name", "CallLeafDirect|CallLeafDirectVector|CallLeafNoFPDirect"), ["dump_spec"], "extra_label", function(dump_spec) {return callLeafInfo(dump_spec[0], 0);}); + +// Show pre/main/post at CountedLoopNodes. +editProperty(hasProperty("loop_kind"), ["loop_kind"], "extra_label", + function(loop_kind) { return loop_kind[0]; }); diff --git a/test/jdk/ProblemList-generational-zgc.txt b/test/docs/ProblemList.txt similarity index 55% rename from test/jdk/ProblemList-generational-zgc.txt rename to test/docs/ProblemList.txt index 9fa9874d20c64..914ae21d49fae 100644 --- a/test/jdk/ProblemList-generational-zgc.txt +++ b/test/docs/ProblemList.txt @@ -1,5 +1,6 @@ +########################################################################### # -# Copyright (c) 2020, 2024, 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,21 +21,21 @@ # or visit www.oracle.com if you need additional information or have any # questions. # +########################################################################### ############################################################################# # -# List of quarantined tests for testing with Generational ZGC. +# List of quarantined tests -- tests that should not be run by default, because +# they may fail due to known reason. The reason (CR#) must be mandatory specified. +# +# List items are testnames followed by labels, all MUST BE commented +# as to why they are here and use a label: +# generic-all Problems on all platforms +# generic-ARCH Where ARCH is one of: x64, i586, ppc64, ppc64le, s390x etc. +# OSNAME-all Where OSNAME is one of: linux, windows, macosx, aix +# OSNAME-ARCH Specific on to one OSNAME and ARCH, e.g. macosx-x64 +# OSNAME-REV Specific on to one OSNAME and REV, e.g. macosx-10.7.4 +# +# More than one label is allowed but must be on the same line. # ############################################################################# - -# Quiet all SA tests - -sun/tools/jhsdb/HeapDumpTest.java 8307393 generic-all -sun/tools/jhsdb/BasicLauncherTest.java 8307393 generic-all -sun/tools/jhsdb/JStackStressTest.java 8307393 generic-all -sun/tools/jhsdb/JShellHeapDumpTest.java 8307393 generic-all -sun/tools/jhsdb/SAGetoptTest.java 8307393 generic-all -sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java 8307393 generic-all -sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java 8307393 generic-all - -com/sun/jdi/ThreadMemoryLeakTest.java 8307402 generic-all diff --git a/test/docs/TEST.ROOT b/test/docs/TEST.ROOT new file mode 100644 index 0000000000000..af2e589677954 --- /dev/null +++ b/test/docs/TEST.ROOT @@ -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. +# + +# + +# This file identifies the root of the test-suite hierarchy. +# It also contains test-suite configuration information. + +# The list of keywords supported in the entire test suite. The +# "intermittent" keyword marks tests known to fail intermittently. +# The "randomness" keyword marks tests using randomness with test +# cases differing from run to run. (A test using a fixed random seed +# would not count as "randomness" by this definition.) Extra care +# should be taken to handle test failures of intermittent or +# randomness tests. + +# Group definitions +groups=TEST.groups + +# Minimum jtreg version +requiredVersion=7.4+1 + +# Use new module options +useNewOptions=true + +# Use --patch-module instead of -Xmodule: +useNewPatchModule=true + +# Path to libraries in the topmost test directory. This is needed so @library +# does not need ../../ notation to reach them +external.lib.roots = ../../ diff --git a/test/docs/TEST.groups b/test/docs/TEST.groups new file mode 100644 index 0000000000000..e7c2215dc6952 --- /dev/null +++ b/test/docs/TEST.groups @@ -0,0 +1,29 @@ +# 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. +# + +# Docs-specific test groups + +docs_all = \ + / + +tier2 = \ + :docs_all diff --git a/src/hotspot/os/windows/gc/x/xLargePages_windows.cpp b/test/docs/jdk/javadoc/TestDocs.java similarity index 58% rename from src/hotspot/os/windows/gc/x/xLargePages_windows.cpp rename to test/docs/jdk/javadoc/TestDocs.java index 20b3c4911fc68..3ccd89ab2e05b 100644 --- a/src/hotspot/os/windows/gc/x/xLargePages_windows.cpp +++ b/test/docs/jdk/javadoc/TestDocs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,20 +21,24 @@ * questions. */ -#include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/x/xLargePages.hpp" -#include "gc/x/xSyscall_windows.hpp" -#include "runtime/globals.hpp" +/* + * @test + * @library /test/lib ../../tools/tester + * @build jtreg.SkippedException + * @summary example of a test on the generated documentation + * @run main TestDocs + */ -void XLargePages::pd_initialize() { - if (UseLargePages) { - if (XSyscall::is_large_pages_supported()) { - _state = Explicit; - return; - } - log_info_p(gc, init)("Shared large pages not supported on this OS version"); - } +import java.nio.file.Files; - _state = Disabled; +public class TestDocs { + public static void main(String... args) throws Exception { + var docs = DocTester.resolveDocs(); + System.err.println("Path to the docs is: " + docs); + System.err.println("Do docs exits?"); + System.err.println(Files.exists(docs)); + System.err.println("tidy location"); + System.err.println(System.getProperty("tidy")); + System.err.println("End of test"); + } } diff --git a/test/docs/tools/tester/DocTester.java b/test/docs/tools/tester/DocTester.java new file mode 100644 index 0000000000000..11364ce9f4f5f --- /dev/null +++ b/test/docs/tools/tester/DocTester.java @@ -0,0 +1,47 @@ +/* + * 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 jtreg.SkippedException; + +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * Test framework for performing tests on the generated documentation. + */ +public class DocTester { + private final static String DIR = System.getenv("DOCS_JDK_IMAGE_DIR"); + private static final Path firstCandidate = Path.of(System.getProperty("test.jdk")) + .getParent().resolve("docs"); + + public static Path resolveDocs() { + if (DIR != null && !DIR.isBlank() && Files.exists(Path.of(DIR))) { + return Path.of(DIR); + } else if (Files.exists(firstCandidate)) { + return firstCandidate; + }else { + throw new SkippedException("docs folder not found in either location"); + } + } +} diff --git a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp index a4ac2fee66ba4..d55d6dbfc2320 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp @@ -93,6 +93,18 @@ class OopStorage::TestAccess : public AllStatic { static void block_array_set_block_count(ActiveArray* blocks, size_t count) { blocks->_block_count = count; } + + static const oop* get_block_pointer(const Block& block, unsigned index) { + return block.get_pointer(index); + } + + static Block* new_block(const OopStorage& owner) { + return Block::new_block(&owner); + } + + static void delete_block(const Block& block) { + Block::delete_block(block); + } }; typedef OopStorage::TestAccess TestAccess; @@ -518,24 +530,35 @@ TEST_VM_F(OopStorageTest, bulk_allocation) { } } -#ifndef DISABLE_GARBAGE_ALLOCATION_STATUS_TESTS -TEST_VM_F(OopStorageTest, invalid_pointer) { - { - char* mem = NEW_C_HEAP_ARRAY(char, 1000, mtInternal); - oop* ptr = reinterpret_cast(align_down(mem + 250, sizeof(oop))); - // Predicate returns false for some malloc'ed block. - EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); - FREE_C_HEAP_ARRAY(char, mem); - } +TEST_VM_F(OopStorageTest, invalid_malloc_pointer) { + char* mem = NEW_C_HEAP_ARRAY(char, 1000, mtInternal); + oop* ptr = reinterpret_cast(align_down(mem + 250, sizeof(oop))); + // Predicate returns false for some malloc'ed block. + EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); + FREE_C_HEAP_ARRAY(char, mem); +} - { - oop obj; - oop* ptr = &obj; - // Predicate returns false for some "random" location. - EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); - } +TEST_VM_F(OopStorageTest, invalid_random_pointer) { + oop obj; + oop* ptr = &obj; + // Predicate returns false for some "random" location. + EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); +} + +TEST_VM_F(OopStorageTest, invalid_block_pointer) { + // Allocate a block for storage, but don't insert it into the storage. This + // also tests the false positive case of block_for_ptr where we have a + // reference to storage at just the "right" place. + const OopBlock* block = TestAccess::new_block(storage()); + ASSERT_NE(block, NULL_BLOCK); + const oop* ptr = TestAccess::get_block_pointer(*block, 0); + EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); + TestAccess::delete_block(*block); +} + +TEST_VM_F(OopStorageTest, invalid_null_pointer) { + EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(nullptr)); } -#endif // DISABLE_GARBAGE_ALLOCATION_STATUS_TESTS class OopStorageTest::CountingIterateClosure { public: diff --git a/test/hotspot/gtest/gc/x/test_xAddress.cpp b/test/hotspot/gtest/gc/x/test_xAddress.cpp deleted file mode 100644 index 3f769dc7eead9..0000000000000 --- a/test/hotspot/gtest/gc/x/test_xAddress.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "unittest.hpp" - -class XAddressTest : public ::testing::Test { -protected: - static void is_good_bit(uintptr_t bit_mask) { - // Setup - XAddress::initialize(); - XAddress::set_good_mask(bit_mask); - - // Test that a pointer with only the given bit is considered good. - EXPECT_EQ(XAddress::is_good(XAddressMetadataMarked0), (bit_mask == XAddressMetadataMarked0)); - EXPECT_EQ(XAddress::is_good(XAddressMetadataMarked1), (bit_mask == XAddressMetadataMarked1)); - EXPECT_EQ(XAddress::is_good(XAddressMetadataRemapped), (bit_mask == XAddressMetadataRemapped)); - - // Test that a pointer with the given bit and some extra bits is considered good. - EXPECT_EQ(XAddress::is_good(XAddressMetadataMarked0 | 0x8),(bit_mask == XAddressMetadataMarked0)); - EXPECT_EQ(XAddress::is_good(XAddressMetadataMarked1 | 0x8), (bit_mask == XAddressMetadataMarked1)); - EXPECT_EQ(XAddress::is_good(XAddressMetadataRemapped | 0x8), (bit_mask == XAddressMetadataRemapped)); - - // Test that null is not considered good. - EXPECT_FALSE(XAddress::is_good(0)); - } - - static void is_good_or_null_bit(uintptr_t bit_mask) { - // Setup - XAddress::initialize(); - XAddress::set_good_mask(bit_mask); - - // Test that a pointer with only the given bit is considered good. - EXPECT_EQ(XAddress::is_good_or_null(XAddressMetadataMarked0), (bit_mask == XAddressMetadataMarked0)); - EXPECT_EQ(XAddress::is_good_or_null(XAddressMetadataMarked1), (bit_mask == XAddressMetadataMarked1)); - EXPECT_EQ(XAddress::is_good_or_null(XAddressMetadataRemapped), (bit_mask == XAddressMetadataRemapped)); - - // Test that a pointer with the given bit and some extra bits is considered good. - EXPECT_EQ(XAddress::is_good_or_null(XAddressMetadataMarked0 | 0x8), (bit_mask == XAddressMetadataMarked0)); - EXPECT_EQ(XAddress::is_good_or_null(XAddressMetadataMarked1 | 0x8), (bit_mask == XAddressMetadataMarked1)); - EXPECT_EQ(XAddress::is_good_or_null(XAddressMetadataRemapped | 0x8), (bit_mask == XAddressMetadataRemapped)); - - // Test that null is considered good_or_null. - EXPECT_TRUE(XAddress::is_good_or_null(0)); - } - - static void finalizable() { - // Setup - XAddress::initialize(); - XAddress::flip_to_marked(); - - // Test that a normal good pointer is good and weak good, but not finalizable - const uintptr_t addr1 = XAddress::good(1); - EXPECT_FALSE(XAddress::is_finalizable(addr1)); - EXPECT_TRUE(XAddress::is_marked(addr1)); - EXPECT_FALSE(XAddress::is_remapped(addr1)); - EXPECT_TRUE(XAddress::is_weak_good(addr1)); - EXPECT_TRUE(XAddress::is_weak_good_or_null(addr1)); - EXPECT_TRUE(XAddress::is_good(addr1)); - EXPECT_TRUE(XAddress::is_good_or_null(addr1)); - - // Test that a finalizable good pointer is finalizable and weak good, but not good - const uintptr_t addr2 = XAddress::finalizable_good(1); - EXPECT_TRUE(XAddress::is_finalizable(addr2)); - EXPECT_TRUE(XAddress::is_marked(addr2)); - EXPECT_FALSE(XAddress::is_remapped(addr2)); - EXPECT_TRUE(XAddress::is_weak_good(addr2)); - EXPECT_TRUE(XAddress::is_weak_good_or_null(addr2)); - EXPECT_FALSE(XAddress::is_good(addr2)); - EXPECT_FALSE(XAddress::is_good_or_null(addr2)); - - // Flip to remapped and test that it's no longer weak good - XAddress::flip_to_remapped(); - EXPECT_TRUE(XAddress::is_finalizable(addr2)); - EXPECT_TRUE(XAddress::is_marked(addr2)); - EXPECT_FALSE(XAddress::is_remapped(addr2)); - EXPECT_FALSE(XAddress::is_weak_good(addr2)); - EXPECT_FALSE(XAddress::is_weak_good_or_null(addr2)); - EXPECT_FALSE(XAddress::is_good(addr2)); - EXPECT_FALSE(XAddress::is_good_or_null(addr2)); - } -}; - -TEST_F(XAddressTest, is_good) { - is_good_bit(XAddressMetadataMarked0); - is_good_bit(XAddressMetadataMarked1); - is_good_bit(XAddressMetadataRemapped); -} - -TEST_F(XAddressTest, is_good_or_null) { - is_good_or_null_bit(XAddressMetadataMarked0); - is_good_or_null_bit(XAddressMetadataMarked1); - is_good_or_null_bit(XAddressMetadataRemapped); -} - -TEST_F(XAddressTest, is_weak_good_or_null) { -#define check_is_weak_good_or_null(value) \ - EXPECT_EQ(XAddress::is_weak_good_or_null(value), \ - (XAddress::is_good_or_null(value) || XAddress::is_remapped(value))) \ - << "is_good_or_null: " << XAddress::is_good_or_null(value) \ - << " is_remaped: " << XAddress::is_remapped(value) \ - << " is_good_or_null_or_remapped: " << XAddress::is_weak_good_or_null(value) - - check_is_weak_good_or_null((uintptr_t)nullptr); - check_is_weak_good_or_null(XAddressMetadataMarked0); - check_is_weak_good_or_null(XAddressMetadataMarked1); - check_is_weak_good_or_null(XAddressMetadataRemapped); - check_is_weak_good_or_null((uintptr_t)0x123); -} - -TEST_F(XAddressTest, finalizable) { - finalizable(); -} diff --git a/test/hotspot/gtest/gc/x/test_xArray.cpp b/test/hotspot/gtest/gc/x/test_xArray.cpp deleted file mode 100644 index 36c0b73ad6f51..0000000000000 --- a/test/hotspot/gtest/gc/x/test_xArray.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xArray.inline.hpp" -#include "unittest.hpp" - -TEST(XArray, sanity) { - XArray a; - - // Add elements - for (int i = 0; i < 10; i++) { - a.append(i); - } - - XArray b; - - b.swap(&a); - - // Check size - ASSERT_EQ(a.length(), 0); - ASSERT_EQ(a.capacity(), 0); - ASSERT_EQ(a.is_empty(), true); - - ASSERT_EQ(b.length(), 10); - ASSERT_GE(b.capacity(), 10); - ASSERT_EQ(b.is_empty(), false); - - // Clear elements - a.clear(); - - // Check that b is unaffected - ASSERT_EQ(b.length(), 10); - ASSERT_GE(b.capacity(), 10); - ASSERT_EQ(b.is_empty(), false); - - a.append(1); - - // Check that b is unaffected - ASSERT_EQ(b.length(), 10); - ASSERT_GE(b.capacity(), 10); - ASSERT_EQ(b.is_empty(), false); -} - -TEST(XArray, iterator) { - XArray a; - - // Add elements - for (int i = 0; i < 10; i++) { - a.append(i); - } - - // Iterate - int count = 0; - XArrayIterator iter(&a); - for (int value; iter.next(&value);) { - ASSERT_EQ(a.at(count), count); - count++; - } - - // Check count - ASSERT_EQ(count, 10); -} diff --git a/test/hotspot/gtest/gc/x/test_xBitField.cpp b/test/hotspot/gtest/gc/x/test_xBitField.cpp deleted file mode 100644 index 248322b2a0715..0000000000000 --- a/test/hotspot/gtest/gc/x/test_xBitField.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xBitField.hpp" -#include "unittest.hpp" - -TEST(XBitFieldTest, test) { - typedef XBitField field_bool; - typedef XBitField field_uint8; - typedef XBitField field_uint16; - typedef XBitField field_uint32; - typedef XBitField field_uint64; - typedef XBitField field_pointer; - - uint64_t entry; - - { - const bool value = false; - entry = field_bool::encode(value); - EXPECT_EQ(field_bool::decode(entry), value) << "Should be equal"; - } - - { - const bool value = true; - entry = field_bool::encode(value); - EXPECT_EQ(field_bool::decode(entry), value) << "Should be equal"; - } - - { - const uint8_t value = ~(uint8_t)0; - entry = field_uint8::encode(value); - EXPECT_EQ(field_uint8::decode(entry), value) << "Should be equal"; - } - - { - const uint16_t value = ~(uint16_t)0; - entry = field_uint16::encode(value); - EXPECT_EQ(field_uint16::decode(entry), value) << "Should be equal"; - } - - { - const uint32_t value = ~(uint32_t)0; - entry = field_uint32::encode(value); - EXPECT_EQ(field_uint32::decode(entry), value) << "Should be equal"; - } - - { - const uint64_t value = ~(uint64_t)0 >> 1; - entry = field_uint64::encode(value); - EXPECT_EQ(field_uint64::decode(entry), value) << "Should be equal"; - } - - { - void* const value = (void*)(~(uintptr_t)0 << 3); - entry = field_pointer::encode(value); - EXPECT_EQ(field_pointer::decode(entry), value) << "Should be equal"; - } -} diff --git a/test/hotspot/gtest/gc/x/test_xBitMap.cpp b/test/hotspot/gtest/gc/x/test_xBitMap.cpp deleted file mode 100644 index 2d3cb09c7ed8b..0000000000000 --- a/test/hotspot/gtest/gc/x/test_xBitMap.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xBitMap.inline.hpp" -#include "unittest.hpp" - -class XBitMapTest : public ::testing::Test { -protected: - static void test_set_pair_unset(size_t size, bool finalizable) { - XBitMap bitmap(size); - - for (BitMap::idx_t i = 0; i < size - 1; i++) { - if ((i + 1) % BitsPerWord == 0) { - // Can't set pairs of bits in different words. - continue; - } - - // XBitMaps are not cleared when constructed. - bitmap.clear(); - - bool inc_live = false; - - bool ret = bitmap.par_set_bit_pair(i, finalizable, inc_live); - EXPECT_TRUE(ret) << "Failed to set bit"; - EXPECT_TRUE(inc_live) << "Should have set inc_live"; - - // First bit should always be set - EXPECT_TRUE(bitmap.at(i)) << "Should be set"; - - // Second bit should only be set when marking strong - EXPECT_NE(bitmap.at(i + 1), finalizable); - } - } - - static void test_set_pair_set(size_t size, bool finalizable) { - XBitMap bitmap(size); - - for (BitMap::idx_t i = 0; i < size - 1; i++) { - if ((i + 1) % BitsPerWord == 0) { - // Can't set pairs of bits in different words. - continue; - } - - // Fill the bitmap with ones. - bitmap.set_range(0, size); - - bool inc_live = false; - - bool ret = bitmap.par_set_bit_pair(i, finalizable, inc_live); - EXPECT_FALSE(ret) << "Should not succeed setting bit"; - EXPECT_FALSE(inc_live) << "Should not have set inc_live"; - - // Both bits were pre-set. - EXPECT_TRUE(bitmap.at(i)) << "Should be set"; - EXPECT_TRUE(bitmap.at(i + 1)) << "Should be set"; - } - } - - static void test_set_pair_set(bool finalizable) { - test_set_pair_set(2, finalizable); - test_set_pair_set(62, finalizable); - test_set_pair_set(64, finalizable); - test_set_pair_set(66, finalizable); - test_set_pair_set(126, finalizable); - test_set_pair_set(128, finalizable); - } - - static void test_set_pair_unset(bool finalizable) { - test_set_pair_unset(2, finalizable); - test_set_pair_unset(62, finalizable); - test_set_pair_unset(64, finalizable); - test_set_pair_unset(66, finalizable); - test_set_pair_unset(126, finalizable); - test_set_pair_unset(128, finalizable); - } - -}; - -TEST_F(XBitMapTest, test_set_pair_set) { - test_set_pair_set(false); - test_set_pair_set(true); -} - -TEST_F(XBitMapTest, test_set_pair_unset) { - test_set_pair_unset(false); - test_set_pair_unset(true); -} diff --git a/test/hotspot/gtest/gc/x/test_xForwarding.cpp b/test/hotspot/gtest/gc/x/test_xForwarding.cpp deleted file mode 100644 index de850304ebb0d..0000000000000 --- a/test/hotspot/gtest/gc/x/test_xForwarding.cpp +++ /dev/null @@ -1,205 +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. - */ - -#include "precompiled.hpp" -#include "gc/x/xAddress.inline.hpp" -#include "gc/x/xForwarding.inline.hpp" -#include "gc/x/xForwardingAllocator.inline.hpp" -#include "gc/x/xGlobals.hpp" -#include "gc/x/xPage.inline.hpp" -#include "unittest.hpp" - -using namespace testing; - -#define CAPTURE_DELIM "\n" -#define CAPTURE1(expression) #expression << " evaluates to " << expression -#define CAPTURE2(e0, e1) CAPTURE1(e0) << CAPTURE_DELIM << CAPTURE1(e1) - -#define CAPTURE(expression) CAPTURE1(expression) - -class XForwardingTest : public Test { -public: - // Helper functions - - class SequenceToFromIndex : AllStatic { - public: - static uintptr_t even(size_t sequence_number) { - return sequence_number * 2; - } - static uintptr_t odd(size_t sequence_number) { - return even(sequence_number) + 1; - } - static uintptr_t one_to_one(size_t sequence_number) { - return sequence_number; - } - }; - - // Test functions - - static void setup(XForwarding* forwarding) { - EXPECT_PRED1(is_power_of_2, forwarding->_entries.length()) << CAPTURE(forwarding->_entries.length()); - } - - static void find_empty(XForwarding* forwarding) { - size_t size = forwarding->_entries.length(); - size_t entries_to_check = size * 2; - - for (size_t i = 0; i < entries_to_check; i++) { - uintptr_t from_index = SequenceToFromIndex::one_to_one(i); - - XForwardingCursor cursor; - XForwardingEntry entry = forwarding->find(from_index, &cursor); - EXPECT_FALSE(entry.populated()) << CAPTURE2(from_index, size); - } - } - - static void find_full(XForwarding* forwarding) { - size_t size = forwarding->_entries.length(); - size_t entries_to_populate = size; - - // Populate - for (size_t i = 0; i < entries_to_populate; i++) { - uintptr_t from_index = SequenceToFromIndex::one_to_one(i); - - XForwardingCursor cursor; - XForwardingEntry entry = forwarding->find(from_index, &cursor); - ASSERT_FALSE(entry.populated()) << CAPTURE2(from_index, size); - - forwarding->insert(from_index, from_index, &cursor); - } - - // Verify - for (size_t i = 0; i < entries_to_populate; i++) { - uintptr_t from_index = SequenceToFromIndex::one_to_one(i); - - XForwardingCursor cursor; - XForwardingEntry entry = forwarding->find(from_index, &cursor); - ASSERT_TRUE(entry.populated()) << CAPTURE2(from_index, size); - - ASSERT_EQ(entry.from_index(), from_index) << CAPTURE(size); - ASSERT_EQ(entry.to_offset(), from_index) << CAPTURE(size); - } - } - - static void find_every_other(XForwarding* forwarding) { - size_t size = forwarding->_entries.length(); - size_t entries_to_populate = size / 2; - - // Populate even from indices - for (size_t i = 0; i < entries_to_populate; i++) { - uintptr_t from_index = SequenceToFromIndex::even(i); - - XForwardingCursor cursor; - XForwardingEntry entry = forwarding->find(from_index, &cursor); - ASSERT_FALSE(entry.populated()) << CAPTURE2(from_index, size); - - forwarding->insert(from_index, from_index, &cursor); - } - - // Verify populated even indices - for (size_t i = 0; i < entries_to_populate; i++) { - uintptr_t from_index = SequenceToFromIndex::even(i); - - XForwardingCursor cursor; - XForwardingEntry entry = forwarding->find(from_index, &cursor); - ASSERT_TRUE(entry.populated()) << CAPTURE2(from_index, size); - - ASSERT_EQ(entry.from_index(), from_index) << CAPTURE(size); - ASSERT_EQ(entry.to_offset(), from_index) << CAPTURE(size); - } - - // Verify empty odd indices - // - // This check could be done on a larger range of sequence numbers, - // but currently entries_to_populate is used. - for (size_t i = 0; i < entries_to_populate; i++) { - uintptr_t from_index = SequenceToFromIndex::odd(i); - - XForwardingCursor cursor; - XForwardingEntry entry = forwarding->find(from_index, &cursor); - - ASSERT_FALSE(entry.populated()) << CAPTURE2(from_index, size); - } - } - - static void test(void (*function)(XForwarding*), uint32_t size) { - // Create page - const XVirtualMemory vmem(0, XPageSizeSmall); - const XPhysicalMemory pmem(XPhysicalMemorySegment(0, XPageSizeSmall, true)); - XPage page(XPageTypeSmall, vmem, pmem); - - page.reset(); - - const size_t object_size = 16; - const uintptr_t object = page.alloc_object(object_size); - - XGlobalSeqNum++; - - bool dummy = false; - page.mark_object(XAddress::marked(object), dummy, dummy); - - const uint32_t live_objects = size; - const size_t live_bytes = live_objects * object_size; - page.inc_live(live_objects, live_bytes); - - // Setup allocator - XForwardingAllocator allocator; - const uint32_t nentries = XForwarding::nentries(&page); - allocator.reset((sizeof(XForwarding)) + (nentries * sizeof(XForwardingEntry))); - - // Setup forwarding - XForwarding* const forwarding = XForwarding::alloc(&allocator, &page); - - // Actual test function - (*function)(forwarding); - } - - // Run the given function with a few different input values. - static void test(void (*function)(XForwarding*)) { - test(function, 1); - test(function, 2); - test(function, 3); - test(function, 4); - test(function, 7); - test(function, 8); - test(function, 1023); - test(function, 1024); - test(function, 1025); - } -}; - -TEST_F(XForwardingTest, setup) { - test(&XForwardingTest::setup); -} - -TEST_F(XForwardingTest, find_empty) { - test(&XForwardingTest::find_empty); -} - -TEST_F(XForwardingTest, find_full) { - test(&XForwardingTest::find_full); -} - -TEST_F(XForwardingTest, find_every_other) { - test(&XForwardingTest::find_every_other); -} diff --git a/test/hotspot/gtest/gc/x/test_xList.cpp b/test/hotspot/gtest/gc/x/test_xList.cpp deleted file mode 100644 index f4766ce99e249..0000000000000 --- a/test/hotspot/gtest/gc/x/test_xList.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -#include "precompiled.hpp" -#include "gc/x/xList.inline.hpp" -#include "unittest.hpp" - -#ifndef PRODUCT - -class XTestEntry { - friend class XList; - -private: - const int _id; - XListNode _node; - -public: - XTestEntry(int id) : - _id(id), - _node() {} - - int id() const { - return _id; - } -}; - -class XListTest : public ::testing::Test { -protected: - static void assert_sorted(XList* list) { - // Iterate forward - { - int count = list->first()->id(); - XListIterator iter(list); - for (XTestEntry* entry; iter.next(&entry);) { - ASSERT_EQ(entry->id(), count); - count++; - } - } - - // Iterate backward - { - int count = list->last()->id(); - XListReverseIterator iter(list); - for (XTestEntry* entry; iter.next(&entry);) { - EXPECT_EQ(entry->id(), count); - count--; - } - } - } -}; - -TEST_F(XListTest, test_insert) { - XList list; - XTestEntry e0(0); - XTestEntry e1(1); - XTestEntry e2(2); - XTestEntry e3(3); - XTestEntry e4(4); - XTestEntry e5(5); - - list.insert_first(&e2); - list.insert_before(&e2, &e1); - list.insert_after(&e2, &e3); - list.insert_last(&e4); - list.insert_first(&e0); - list.insert_last(&e5); - - EXPECT_EQ(list.size(), 6u); - assert_sorted(&list); - - for (int i = 0; i < 6; i++) { - XTestEntry* e = list.remove_first(); - EXPECT_EQ(e->id(), i); - } - - EXPECT_EQ(list.size(), 0u); -} - -TEST_F(XListTest, test_remove) { - // Remove first - { - XList list; - XTestEntry e0(0); - XTestEntry e1(1); - XTestEntry e2(2); - XTestEntry e3(3); - XTestEntry e4(4); - XTestEntry e5(5); - - list.insert_last(&e0); - list.insert_last(&e1); - list.insert_last(&e2); - list.insert_last(&e3); - list.insert_last(&e4); - list.insert_last(&e5); - - EXPECT_EQ(list.size(), 6u); - - for (int i = 0; i < 6; i++) { - XTestEntry* e = list.remove_first(); - EXPECT_EQ(e->id(), i); - } - - EXPECT_EQ(list.size(), 0u); - } - - // Remove last - { - XList list; - XTestEntry e0(0); - XTestEntry e1(1); - XTestEntry e2(2); - XTestEntry e3(3); - XTestEntry e4(4); - XTestEntry e5(5); - - list.insert_last(&e0); - list.insert_last(&e1); - list.insert_last(&e2); - list.insert_last(&e3); - list.insert_last(&e4); - list.insert_last(&e5); - - EXPECT_EQ(list.size(), 6u); - - for (int i = 5; i >= 0; i--) { - XTestEntry* e = list.remove_last(); - EXPECT_EQ(e->id(), i); - } - - EXPECT_EQ(list.size(), 0u); - } -} - -#endif // PRODUCT diff --git a/test/hotspot/gtest/gc/x/test_xLiveMap.cpp b/test/hotspot/gtest/gc/x/test_xLiveMap.cpp deleted file mode 100644 index d57790e9dabf9..0000000000000 --- a/test/hotspot/gtest/gc/x/test_xLiveMap.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xLiveMap.inline.hpp" -#include "unittest.hpp" - -class XLiveMapTest : public ::testing::Test { -protected: - static void strongly_live_for_large_xpage() { - // Large XPages only have room for one object. - XLiveMap livemap(1); - - bool inc_live; - uintptr_t object = 0u; - - // Mark the object strong. - livemap.set(object, false /* finalizable */, inc_live); - - // Check that both bits are in the same segment. - ASSERT_EQ(livemap.index_to_segment(0), livemap.index_to_segment(1)); - - // Check that the object was marked. - ASSERT_TRUE(livemap.get(0)); - - // Check that the object was strongly marked. - ASSERT_TRUE(livemap.get(1)); - - ASSERT_TRUE(inc_live); - } -}; - -TEST_F(XLiveMapTest, strongly_live_for_large_xpage) { - strongly_live_for_large_xpage(); -} diff --git a/test/hotspot/gtest/gc/x/test_xPhysicalMemory.cpp b/test/hotspot/gtest/gc/x/test_xPhysicalMemory.cpp deleted file mode 100644 index f22032632e9d4..0000000000000 --- a/test/hotspot/gtest/gc/x/test_xPhysicalMemory.cpp +++ /dev/null @@ -1,174 +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. - */ - -#include "precompiled.hpp" -#include "gc/x/xPhysicalMemory.inline.hpp" -#include "unittest.hpp" - -TEST(XPhysicalMemoryTest, copy) { - const XPhysicalMemorySegment seg0(0, 100, true); - const XPhysicalMemorySegment seg1(200, 100, true); - - XPhysicalMemory pmem0; - pmem0.add_segment(seg0); - EXPECT_EQ(pmem0.nsegments(), 1); - EXPECT_EQ(pmem0.segment(0).size(), 100u); - - XPhysicalMemory pmem1; - pmem1.add_segment(seg0); - pmem1.add_segment(seg1); - EXPECT_EQ(pmem1.nsegments(), 2); - EXPECT_EQ(pmem1.segment(0).size(), 100u); - EXPECT_EQ(pmem1.segment(1).size(), 100u); - - XPhysicalMemory pmem2(pmem0); - EXPECT_EQ(pmem2.nsegments(), 1); - EXPECT_EQ(pmem2.segment(0).size(), 100u); - - pmem2 = pmem1; - EXPECT_EQ(pmem2.nsegments(), 2); - EXPECT_EQ(pmem2.segment(0).size(), 100u); - EXPECT_EQ(pmem2.segment(1).size(), 100u); -} - -TEST(XPhysicalMemoryTest, add) { - const XPhysicalMemorySegment seg0(0, 1, true); - const XPhysicalMemorySegment seg1(1, 1, true); - const XPhysicalMemorySegment seg2(2, 1, true); - const XPhysicalMemorySegment seg3(3, 1, true); - const XPhysicalMemorySegment seg4(4, 1, true); - const XPhysicalMemorySegment seg5(5, 1, true); - const XPhysicalMemorySegment seg6(6, 1, true); - - XPhysicalMemory pmem0; - EXPECT_EQ(pmem0.nsegments(), 0); - EXPECT_EQ(pmem0.is_null(), true); - - XPhysicalMemory pmem1; - pmem1.add_segment(seg0); - pmem1.add_segment(seg1); - pmem1.add_segment(seg2); - pmem1.add_segment(seg3); - pmem1.add_segment(seg4); - pmem1.add_segment(seg5); - pmem1.add_segment(seg6); - EXPECT_EQ(pmem1.nsegments(), 1); - EXPECT_EQ(pmem1.segment(0).size(), 7u); - EXPECT_EQ(pmem1.is_null(), false); - - XPhysicalMemory pmem2; - pmem2.add_segment(seg0); - pmem2.add_segment(seg1); - pmem2.add_segment(seg2); - pmem2.add_segment(seg4); - pmem2.add_segment(seg5); - pmem2.add_segment(seg6); - EXPECT_EQ(pmem2.nsegments(), 2); - EXPECT_EQ(pmem2.segment(0).size(), 3u); - EXPECT_EQ(pmem2.segment(1).size(), 3u); - EXPECT_EQ(pmem2.is_null(), false); - - XPhysicalMemory pmem3; - pmem3.add_segment(seg0); - pmem3.add_segment(seg2); - pmem3.add_segment(seg3); - pmem3.add_segment(seg4); - pmem3.add_segment(seg6); - EXPECT_EQ(pmem3.nsegments(), 3); - EXPECT_EQ(pmem3.segment(0).size(), 1u); - EXPECT_EQ(pmem3.segment(1).size(), 3u); - EXPECT_EQ(pmem3.segment(2).size(), 1u); - EXPECT_EQ(pmem3.is_null(), false); - - XPhysicalMemory pmem4; - pmem4.add_segment(seg0); - pmem4.add_segment(seg2); - pmem4.add_segment(seg4); - pmem4.add_segment(seg6); - EXPECT_EQ(pmem4.nsegments(), 4); - EXPECT_EQ(pmem4.segment(0).size(), 1u); - EXPECT_EQ(pmem4.segment(1).size(), 1u); - EXPECT_EQ(pmem4.segment(2).size(), 1u); - EXPECT_EQ(pmem4.segment(3).size(), 1u); - EXPECT_EQ(pmem4.is_null(), false); -} - -TEST(XPhysicalMemoryTest, remove) { - XPhysicalMemory pmem; - - pmem.add_segment(XPhysicalMemorySegment(10, 10, true)); - pmem.add_segment(XPhysicalMemorySegment(30, 10, true)); - pmem.add_segment(XPhysicalMemorySegment(50, 10, true)); - EXPECT_EQ(pmem.nsegments(), 3); - EXPECT_EQ(pmem.size(), 30u); - EXPECT_FALSE(pmem.is_null()); - - pmem.remove_segments(); - EXPECT_EQ(pmem.nsegments(), 0); - EXPECT_EQ(pmem.size(), 0u); - EXPECT_TRUE(pmem.is_null()); -} - -TEST(XPhysicalMemoryTest, split) { - XPhysicalMemory pmem; - - pmem.add_segment(XPhysicalMemorySegment(0, 10, true)); - pmem.add_segment(XPhysicalMemorySegment(10, 10, true)); - pmem.add_segment(XPhysicalMemorySegment(30, 10, true)); - EXPECT_EQ(pmem.nsegments(), 2); - EXPECT_EQ(pmem.size(), 30u); - - XPhysicalMemory pmem0 = pmem.split(1); - EXPECT_EQ(pmem0.nsegments(), 1); - EXPECT_EQ(pmem0.size(), 1u); - EXPECT_EQ(pmem.nsegments(), 2); - EXPECT_EQ(pmem.size(), 29u); - - XPhysicalMemory pmem1 = pmem.split(25); - EXPECT_EQ(pmem1.nsegments(), 2); - EXPECT_EQ(pmem1.size(), 25u); - EXPECT_EQ(pmem.nsegments(), 1); - EXPECT_EQ(pmem.size(), 4u); - - XPhysicalMemory pmem2 = pmem.split(4); - EXPECT_EQ(pmem2.nsegments(), 1); - EXPECT_EQ(pmem2.size(), 4u); - EXPECT_EQ(pmem.nsegments(), 0); - EXPECT_EQ(pmem.size(), 0u); -} - -TEST(XPhysicalMemoryTest, split_committed) { - XPhysicalMemory pmem0; - pmem0.add_segment(XPhysicalMemorySegment(0, 10, true)); - pmem0.add_segment(XPhysicalMemorySegment(10, 10, false)); - pmem0.add_segment(XPhysicalMemorySegment(20, 10, true)); - pmem0.add_segment(XPhysicalMemorySegment(30, 10, false)); - EXPECT_EQ(pmem0.nsegments(), 4); - EXPECT_EQ(pmem0.size(), 40u); - - XPhysicalMemory pmem1 = pmem0.split_committed(); - EXPECT_EQ(pmem0.nsegments(), 2); - EXPECT_EQ(pmem0.size(), 20u); - EXPECT_EQ(pmem1.nsegments(), 2); - EXPECT_EQ(pmem1.size(), 20u); -} diff --git a/test/hotspot/gtest/gc/x/test_xVirtualMemory.cpp b/test/hotspot/gtest/gc/x/test_xVirtualMemory.cpp deleted file mode 100644 index 6698ccfa045b8..0000000000000 --- a/test/hotspot/gtest/gc/x/test_xVirtualMemory.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2016, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/x/xVirtualMemory.inline.hpp" -#include "unittest.hpp" - -TEST(XVirtualMemory, split) { - XVirtualMemory vmem(0, 10); - - XVirtualMemory vmem0 = vmem.split(0); - EXPECT_EQ(vmem0.size(), 0u); - EXPECT_EQ(vmem.size(), 10u); - - XVirtualMemory vmem1 = vmem.split(5); - EXPECT_EQ(vmem1.size(), 5u); - EXPECT_EQ(vmem.size(), 5u); - - XVirtualMemory vmem2 = vmem.split(5); - EXPECT_EQ(vmem2.size(), 5u); - EXPECT_EQ(vmem.size(), 0u); - - XVirtualMemory vmem3 = vmem.split(0); - EXPECT_EQ(vmem3.size(), 0u); -} diff --git a/test/hotspot/gtest/logging/test_logDefaultDecorators.cpp b/test/hotspot/gtest/logging/test_logDefaultDecorators.cpp new file mode 100644 index 0000000000000..8ffe97da0dbc5 --- /dev/null +++ b/test/hotspot/gtest/logging/test_logDefaultDecorators.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "jvm.h" +#include "logging/logDecorators.hpp" +#include "logging/logTag.hpp" +#include "unittest.hpp" + + +class TestLogDecorators : public testing::Test { + using LD = LogDecorators; + + static const size_t defaults_cnt = 3; + LD::DefaultUndecoratedSelection defaults[defaults_cnt] = { + LD::DefaultUndecoratedSelection::make(), + LD::DefaultUndecoratedSelection::make(), + LD::DefaultUndecoratedSelection::make(), + }; + +public: + void test_default_decorators() { + LogTagType tags[LogTag::MaxTags] = { LogTag::__NO_TAG, LogTag::__NO_TAG, LogTag::__NO_TAG, LogTag::__NO_TAG, LogTag::__NO_TAG }; + bool result; + + // If a -Xlog selection matches one of the undecorated defaults, the default decorators will be disabled + tags[0] = LogTagType::_jit; + result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Trace), defaults, defaults_cnt); + EXPECT_TRUE(result); + + + // If a -Xlog selection contains one of the undecorated defaults, the default decorators will be disabled + tags[0] = LogTagType::_jit; + tags[1] = LogTagType::_inlining; + result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Trace), defaults, defaults_cnt); + EXPECT_TRUE(result); + + + // Wildcards are ignored + tags[0] = LogTag::_compilation; + result = LD::has_disabled_default_decorators(LogSelection(tags, true, LogLevelType::Debug), defaults, defaults_cnt); + EXPECT_FALSE(result); + + + // If there is no level match, default decorators are kept + tags[0] = LogTagType::_gc; + result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Info), defaults, defaults_cnt); + EXPECT_FALSE(result); + + + // If NotMentioned is specified, it will match every level and so default decorators will never be added if there is a positive tagset match + tags[0] = LogTagType::_ref; + result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Error), defaults, defaults_cnt); + EXPECT_TRUE(result); + result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Warning), defaults, defaults_cnt); + EXPECT_TRUE(result); + result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Info), defaults, defaults_cnt); + EXPECT_TRUE(result); + result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Debug), defaults, defaults_cnt); + EXPECT_TRUE(result); + result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Trace), defaults, defaults_cnt); + EXPECT_TRUE(result); + } + + void test_mask_from_decorators() { + // Single tags should yield 2^{decorator_value_in_enum} + EXPECT_EQ(LD::mask_from_decorators(LD::time_decorator), (uint)(1 << LD::time_decorator)); + EXPECT_EQ(LD::mask_from_decorators(LD::pid_decorator), (uint)(1 << LD::pid_decorator)); + EXPECT_EQ(LD::mask_from_decorators(LD::tid_decorator), (uint)(1 << LD::tid_decorator)); + EXPECT_EQ(LD::mask_from_decorators(LD::tags_decorator), (uint)(1 << LD::tags_decorator)); + + // Combinations of decorators should fill the mask accordingly to their bitmask positions + uint mask = (1 << LD::time_decorator) | (1 << LD::uptimemillis_decorator) | (1 << LD::tid_decorator); + EXPECT_EQ(LD::mask_from_decorators(LD::time_decorator, LD::uptimemillis_decorator, LD::tid_decorator), mask); + } +}; + +TEST_VM_F(TestLogDecorators, MaskFromDecorators) { + test_mask_from_decorators(); +} + +TEST_VM_F(TestLogDecorators, HasDefaultDecorators) { + test_default_decorators(); +} diff --git a/test/hotspot/gtest/metaspace/test_arenagrowthpolicy.cpp b/test/hotspot/gtest/metaspace/test_arenagrowthpolicy.cpp index a37af058e092d..80e6c1d77da29 100644 --- a/test/hotspot/gtest/metaspace/test_arenagrowthpolicy.cpp +++ b/test/hotspot/gtest/metaspace/test_arenagrowthpolicy.cpp @@ -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. * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -61,8 +61,6 @@ TEST_VM(metaspace, arena_growth_policy_##spacetype##_##is_class) { \ test_arena_growth_policy(Metaspace::spacetype, is_class); \ } -DEFINE_GROWTH_POLICY_TEST(ReflectionMetaspaceType, true) -DEFINE_GROWTH_POLICY_TEST(ReflectionMetaspaceType, false) DEFINE_GROWTH_POLICY_TEST(ClassMirrorHolderMetaspaceType, true) DEFINE_GROWTH_POLICY_TEST(ClassMirrorHolderMetaspaceType, false) DEFINE_GROWTH_POLICY_TEST(StandardMetaspaceType, true) diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp index aee53ea32aa16..2e5a6d40ce79c 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp @@ -218,7 +218,8 @@ class MetaspaceArenaTestHelper { static void test_basics(size_t commit_limit, bool is_micro) { MetaspaceGtestContext context(commit_limit); - MetaspaceArenaTestHelper helper(context, is_micro ? Metaspace::ReflectionMetaspaceType : Metaspace::StandardMetaspaceType, false); + const Metaspace::MetaspaceType type = is_micro ? Metaspace::ClassMirrorHolderMetaspaceType : Metaspace::StandardMetaspaceType; + MetaspaceArenaTestHelper helper(context, type, false); helper.allocate_from_arena_with_tests(1); helper.allocate_from_arena_with_tests(128); @@ -278,11 +279,11 @@ TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_standard_nc) { } TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_micro_c) { - test_chunk_enlargment_simple(Metaspace::ReflectionMetaspaceType, true); + test_chunk_enlargment_simple(Metaspace::ClassMirrorHolderMetaspaceType, true); } TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_micro_nc) { - test_chunk_enlargment_simple(Metaspace::ReflectionMetaspaceType, false); + test_chunk_enlargment_simple(Metaspace::ClassMirrorHolderMetaspaceType, false); } // Test chunk enlargement: @@ -434,8 +435,8 @@ static void test_recover_from_commit_limit_hit() { // The first MetaspaceArena mimicks a micro loader. This will fill the free // chunk list with very small chunks. We allocate from them in an interleaved // way to cause fragmentation. - MetaspaceArenaTestHelper helper1(context, Metaspace::ReflectionMetaspaceType, false); - MetaspaceArenaTestHelper helper2(context, Metaspace::ReflectionMetaspaceType, false); + MetaspaceArenaTestHelper helper1(context, Metaspace::ClassMirrorHolderMetaspaceType, false); + MetaspaceArenaTestHelper helper2(context, Metaspace::ClassMirrorHolderMetaspaceType, false); // This MetaspaceArena should hit the limit. We use BootMetaspaceType here since // it gets a large initial chunk which is committed @@ -495,7 +496,9 @@ static void test_controlled_growth(Metaspace::MetaspaceType type, bool is_class, MetaspaceGtestContext context; MetaspaceArenaTestHelper smhelper(context, type, is_class, "Grower"); - MetaspaceArenaTestHelper smhelper_harrasser(context, Metaspace::ReflectionMetaspaceType, true, "Harasser"); + const Metaspace::MetaspaceType other_type = + (type == Metaspace::StandardMetaspaceType) ? Metaspace::ClassMirrorHolderMetaspaceType : Metaspace::StandardMetaspaceType; + MetaspaceArenaTestHelper smhelper_harrasser(context, other_type, true, "Harasser"); size_t used = 0, committed = 0, capacity = 0; const size_t alloc_words = 16; @@ -617,16 +620,6 @@ static void test_controlled_growth(Metaspace::MetaspaceType type, bool is_class, } // these numbers have to be in sync with arena policy numbers (see memory/metaspace/arenaGrowthPolicy.cpp) -TEST_VM(metaspace, MetaspaceArena_growth_refl_c_inplace) { - test_controlled_growth(Metaspace::ReflectionMetaspaceType, true, - word_size_for_level(CHUNK_LEVEL_1K), true); -} - -TEST_VM(metaspace, MetaspaceArena_growth_refl_c_not_inplace) { - test_controlled_growth(Metaspace::ReflectionMetaspaceType, true, - word_size_for_level(CHUNK_LEVEL_1K), false); -} - TEST_VM(metaspace, MetaspaceArena_growth_anon_c_inplace) { test_controlled_growth(Metaspace::ClassMirrorHolderMetaspaceType, true, word_size_for_level(CHUNK_LEVEL_1K), true); @@ -660,16 +653,6 @@ TEST_VM(metaspace, MetaspaceArena_growth_boot_c_not_inplace) { } */ -TEST_VM(metaspace, MetaspaceArena_growth_refl_nc_inplace) { - test_controlled_growth(Metaspace::ReflectionMetaspaceType, false, - word_size_for_level(CHUNK_LEVEL_2K), true); -} - -TEST_VM(metaspace, MetaspaceArena_growth_refl_nc_not_inplace) { - test_controlled_growth(Metaspace::ReflectionMetaspaceType, false, - word_size_for_level(CHUNK_LEVEL_2K), false); -} - TEST_VM(metaspace, MetaspaceArena_growth_anon_nc_inplace) { test_controlled_growth(Metaspace::ClassMirrorHolderMetaspaceType, false, word_size_for_level(CHUNK_LEVEL_1K), true); diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp index e94f733e45b2d..bb536dfd0e2c0 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp @@ -227,7 +227,7 @@ class MetaspaceArenaTest { void create_random_test_bed_at(int slotindex) { SizeRange allocation_range(1, 100); // randomize too? const ArenaGrowthPolicy* growth_policy = ArenaGrowthPolicy::policy_for_space_type( - (fifty_fifty() ? Metaspace::StandardMetaspaceType : Metaspace::ReflectionMetaspaceType), + (fifty_fifty() ? Metaspace::StandardMetaspaceType : Metaspace::ClassMirrorHolderMetaspaceType), fifty_fifty()); create_new_test_bed_at(slotindex, growth_policy, allocation_range); } diff --git a/test/hotspot/gtest/nmt/test_vmatree.cpp b/test/hotspot/gtest/nmt/test_vmatree.cpp index 08b4340ae4fb7..7a5a98b786305 100644 --- a/test/hotspot/gtest/nmt/test_vmatree.cpp +++ b/test/hotspot/gtest/nmt/test_vmatree.cpp @@ -171,7 +171,6 @@ class NMTVMATreeTest : public testing::Test { }; - TEST_VM_F(NMTVMATreeTest, OverlappingReservationsResultInTwoNodes) { VMATree::RegionData rd{si[0], mtTest}; Tree tree; @@ -181,6 +180,23 @@ TEST_VM_F(NMTVMATreeTest, OverlappingReservationsResultInTwoNodes) { EXPECT_EQ(2, count_nodes(tree)); } +TEST_VM_F(NMTVMATreeTest, UseFlagInplace) { + Tree tree; + VMATree::RegionData rd1(si[0], mtTest); + VMATree::RegionData rd2(si[1], mtNone); + tree.reserve_mapping(0, 100, rd1); + tree.commit_mapping(20, 50, rd2, true); + tree.uncommit_mapping(30, 10, rd2); + tree.visit_in_order([&](Node* node) { + if (node->key() != 100) { + EXPECT_EQ(mtTest, node->val().out.mem_tag()) << "failed at: " << node->key(); + if (node->key() != 20 && node->key() != 40) { + EXPECT_EQ(VMATree::StateType::Reserved, node->val().out.type()); + } + } + }); +} + // Low-level tests inspecting the state of the tree. TEST_VM_F(NMTVMATreeTest, LowLevel) { adjacent_2_nodes(VMATree::empty_regiondata); diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 78e5212ab3709..fe3c634056c2f 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -405,6 +405,86 @@ TEST_VM(os, jio_snprintf) { test_snprintf(jio_snprintf, false); } +#ifndef MAX_PATH +#define MAX_PATH (2 * K) +#endif + +TEST_VM(os, realpath) { + // POSIX requires that the file exists; Windows tests for a valid drive letter + // but may or may not test if the file exists. */ + static const char* nosuchpath = "/1234567890123456789"; + static const char* tmppath = "/tmp"; + + char buffer[MAX_PATH]; + + // Test a non-existant path, but provide a short buffer. + errno = 0; + const char* returnedBuffer = os::realpath(nosuchpath, buffer, sizeof(nosuchpath) - 2); + // Reports ENOENT on Linux, ENAMETOOLONG on Windows. + EXPECT_TRUE(returnedBuffer == nullptr); +#ifdef _WINDOWS + EXPECT_TRUE(errno == ENAMETOOLONG); +#else + EXPECT_TRUE(errno == ENOENT); +#endif + + // Test a non-existant path, but provide an adequate buffer. + errno = 0; + buffer[0] = 0; + returnedBuffer = os::realpath(nosuchpath, buffer, sizeof(nosuchpath) + 3); + // Reports ENOENT on Linux, may return 0 (and report an error) or buffer on some versions of Windows. +#ifdef _WINDOWS + if (returnedBuffer != nullptr) { + EXPECT_TRUE(returnedBuffer == buffer); + } else { + EXPECT_TRUE(errno != 0); + } +#else + EXPECT_TRUE(returnedBuffer == nullptr); + EXPECT_TRUE(errno == ENOENT); +#endif + + // Test an existing path using a large buffer. + errno = 0; + returnedBuffer = os::realpath(tmppath, buffer, MAX_PATH); + EXPECT_TRUE(returnedBuffer == buffer); + + // Test an existing path using a buffer that is too small on a normal macOS install. + errno = 0; + returnedBuffer = os::realpath(tmppath, buffer, strlen(tmppath) + 3); + // On MacOS, /tmp is a symlink to /private/tmp, so doesn't fit in a small buffer. +#ifndef __APPLE__ + EXPECT_TRUE(returnedBuffer == buffer); +#else + EXPECT_TRUE(returnedBuffer == nullptr); + EXPECT_TRUE(errno == ENAMETOOLONG); +#endif + + // Test an existing path using a buffer that is too small. + errno = 0; + returnedBuffer = os::realpath(tmppath, buffer, strlen(tmppath) - 1); + EXPECT_TRUE(returnedBuffer == nullptr); + EXPECT_TRUE(errno == ENAMETOOLONG); + + // The following tests cause an assert inside os::realpath() in fastdebug mode: +#ifndef ASSERT + errno = 0; + returnedBuffer = os::realpath(nullptr, buffer, sizeof(buffer)); + EXPECT_TRUE(returnedBuffer == nullptr); + EXPECT_TRUE(errno == EINVAL); + + errno = 0; + returnedBuffer = os::realpath(tmppath, nullptr, sizeof(buffer)); + EXPECT_TRUE(returnedBuffer == nullptr); + EXPECT_TRUE(errno == EINVAL); + + errno = 0; + returnedBuffer = os::realpath(tmppath, buffer, 0); + EXPECT_TRUE(returnedBuffer == nullptr); + EXPECT_TRUE(errno == EINVAL); +#endif +} + #ifdef __APPLE__ // Not all macOS versions can use os::reserve_memory (i.e. anon_mmap) API // to reserve executable memory, so before attempting to use it, diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp index 69c3d991b2a4f..77b83ac1bd74d 100644 --- a/test/hotspot/gtest/runtime/test_os_linux.cpp +++ b/test/hotspot/gtest/runtime/test_os_linux.cpp @@ -360,10 +360,10 @@ TEST_VM(os_linux, pretouch_thp_and_use_concurrent) { EXPECT_TRUE(os::commit_memory(heap, size, false)); { - auto pretouch = [heap, size](Thread*, int) { + auto pretouch = [&](Thread*, int) { os::pretouch_memory(heap, heap + size, os::vm_page_size()); }; - auto useMemory = [heap, size](Thread*, int) { + auto useMemory = [&](Thread*, int) { int* iptr = reinterpret_cast(heap); for (int i = 0; i < 1000; i++) *iptr++ = i; }; diff --git a/test/hotspot/gtest/runtime/test_os_windows.cpp b/test/hotspot/gtest/runtime/test_os_windows.cpp index d611b5287a9da..c7e99bcdbc5dd 100644 --- a/test/hotspot/gtest/runtime/test_os_windows.cpp +++ b/test/hotspot/gtest/runtime/test_os_windows.cpp @@ -722,6 +722,114 @@ TEST_VM(os_windows, processor_count) { } } +TEST_VM(os_windows, large_page_init_multiple_sizes) { + // Call request_lock_memory_privilege() and check the result + if (!os::win32::request_lock_memory_privilege()) { + GTEST_SKIP() << "Skipping test because lock memory privilege is not granted."; + } + // Set globals to make sure we hit the correct code path + AutoSaveRestore guardUseLargePages(UseLargePages); + AutoSaveRestore guardEnableAllLargePageSizesForWindows(EnableAllLargePageSizesForWindows); + AutoSaveRestore guardLargePageSizeInBytes(LargePageSizeInBytes); + FLAG_SET_CMDLINE(UseLargePages, true); + FLAG_SET_CMDLINE(EnableAllLargePageSizesForWindows, true); + + // Determine the minimum page size + const size_t min_size = GetLargePageMinimum(); + + // End the test if GetLargePageMinimum returns 0 + if (min_size == 0) { + GTEST_SKIP() << "Large pages are not supported on this system."; + return; + } + + // Set LargePageSizeInBytes to 4 times the minimum page size + FLAG_SET_CMDLINE(LargePageSizeInBytes, 4 * min_size); // Set a value for multiple page sizes + + // Initialize large page settings + os::large_page_init(); + + // Verify that large pages are enabled + EXPECT_TRUE(UseLargePages) << "UseLargePages should be true after initialization for LargePageSizeInBytes = 4 * min_size"; + + // Verify that decided_large_page_size is greater than the default page size + const size_t default_page_size = os::vm_page_size(); + size_t decided_large_page_size = os::win32::large_page_init_decide_size(); + EXPECT_GT(decided_large_page_size, default_page_size) << "Large page size should be greater than the default page size for LargePageSizeInBytes = 4 * min_size"; + +#if !defined(IA32) + size_t page_size_count = 0; + size_t page_size = os::page_sizes().largest(); + + do { + ++page_size_count; + page_size = os::page_sizes().next_smaller(page_size); + } while (page_size >= os::page_sizes().smallest()); + + EXPECT_GT(page_size_count, 1u) << "There should be multiple large page sizes available."; + + size_t large_page_size = decided_large_page_size; + + for (size_t page_size = os::page_sizes().largest(); page_size >= min_size; page_size = os::page_sizes().next_smaller(page_size)) { + EXPECT_TRUE(page_size % min_size == 0) << "Each page size should be a multiple of the minimum large page size."; + EXPECT_LE(page_size, large_page_size) << "Page size should not exceed the determined large page size."; + } +#endif +} + +TEST_VM(os_windows, large_page_init_decide_size) { + // Initial setup + // Call request_lock_memory_privilege() and check the result + if (!os::win32::request_lock_memory_privilege()) { + GTEST_SKIP() << "Skipping test because lock memory privilege is not granted."; + } + AutoSaveRestore guardUseLargePages(UseLargePages); + AutoSaveRestore guardLargePageSizeInBytes(LargePageSizeInBytes); + FLAG_SET_CMDLINE(UseLargePages, true); + FLAG_SET_CMDLINE(LargePageSizeInBytes, 0); // Reset to default + + // Test for large page support + size_t decided_size = os::win32::large_page_init_decide_size(); + size_t min_size = GetLargePageMinimum(); + if (min_size == 0) { + EXPECT_EQ(decided_size, 0) << "Expected decided size to be 0 when large page is not supported by the processor"; + return; + } + + // Scenario 1: Test with 2MB large page size + if (min_size == 2 * M) { + FLAG_SET_CMDLINE(LargePageSizeInBytes, 2 * M); // Set large page size to 2MB + decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size + EXPECT_EQ(decided_size, 2 * M) << "Expected decided size to be 2M when large page and OS reported size are both 2M"; + } + + // Scenario 2: Test with 1MB large page size + if (min_size == 2 * M) { + FLAG_SET_CMDLINE(LargePageSizeInBytes, 1 * M); // Set large page size to 1MB + decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size + EXPECT_EQ(decided_size, 2 * M) << "Expected decided size to be 2M when large page is 1M and OS reported size is 2M"; + } + +#if defined(IA32) || defined(AMD64) + FLAG_SET_CMDLINE(LargePageSizeInBytes, 5 * M); // Set large page size to 5MB + if (!EnableAllLargePageSizesForWindows) { + decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size + EXPECT_EQ(decided_size, 0) << "Expected decided size to be 0 for large pages bigger than 4mb on IA32 or AMD64"; + } +#endif + + // Additional check for non-multiple of minimum size + // Set an arbitrary large page size which is not a multiple of min_size + FLAG_SET_CMDLINE(LargePageSizeInBytes, 5 * min_size + 1); + + // Recalculate decided size + decided_size = os::win32::large_page_init_decide_size(); + + // Assert that the decided size defaults to minimum page size when LargePageSizeInBytes + // is not a multiple of the minimum size, assuming conditions are always met + EXPECT_EQ(decided_size, 0) << "Expected decided size to default to 0 when LargePageSizeInBytes is not a multiple of minimum size"; +} + class ReserveMemorySpecialRunnable : public TestRunnable { public: void runUnitTest() const { diff --git a/test/hotspot/gtest/x86/asmtest.out.h b/test/hotspot/gtest/x86/asmtest.out.h new file mode 100644 index 0000000000000..5c59f0b8d769d --- /dev/null +++ b/test/hotspot/gtest/x86/asmtest.out.h @@ -0,0 +1,1293 @@ +// BEGIN Generated code -- do not edit +// Generated by x86-asmtest.py +#ifdef _LP64 + __ shldl(r22, r14); // {load}shld r22d, r14d IID0 +#endif // _LP64 + __ shrdl(rcx, rbx); // {load}shrd ecx, ebx IID1 +#ifdef _LP64 + __ adcl(r24, r18); // {load}adc r24d, r18d IID2 + __ cmpl(r8, r19); // {load}cmp r8d, r19d IID3 + __ imull(r25, r19); // {load}imul r25d, r19d IID4 + __ popcntl(r19, r15); // {load}popcnt r19d, r15d IID5 + __ sbbl(r21, r19); // {load}sbb r21d, r19d IID6 + __ subl(r17, r29); // {load}sub r17d, r29d IID7 + __ tzcntl(r21, rdx); // {load}tzcnt r21d, edx IID8 + __ lzcntl(rcx, r23); // {load}lzcnt ecx, r23d IID9 + __ addl(r10, r11); // {load}add r10d, r11d IID10 + __ andl(r21, r14); // {load}and r21d, r14d IID11 + __ orl(r12, r30); // {load}or r12d, r30d IID12 + __ xorl(r19, r30); // {load}xor r19d, r30d IID13 + __ movl(r27, r11); // {load}mov r27d, r11d IID14 + __ bsfl(r10, r12); // {load}bsf r10d, r12d IID15 + __ bsrl(r16, r10); // {load}bsr r16d, r10d IID16 + __ xchgl(r16, r28); // {load}xchg r16d, r28d IID17 + __ testl(r25, r16); // {load}test r25d, r16d IID18 + __ addb(Address(r27, rdx, (Address::ScaleFactor)1, +0x6f304723), rcx); // add byte ptr [r27+rdx*2+0x6f304723], cl IID19 + __ addw(Address(r19, rcx, (Address::ScaleFactor)2, +0x17244c57), r17); // add word ptr [r19+rcx*4+0x17244c57], r17w IID20 + __ addl(Address(r23, r16, (Address::ScaleFactor)1, +0x138df419), r19); // add dword ptr [r23+r16*2+0x138df419], r19d IID21 + __ adcl(Address(r8, r11, (Address::ScaleFactor)3, -0x164f7a73), rcx); // adc dword ptr [r8+r11*8-0x164f7a73], ecx IID22 + __ andb(Address(rdx, r17, (Address::ScaleFactor)3, +0x4df7f181), r22); // and byte ptr [rdx+r17*8+0x4df7f181], r22b IID23 + __ andl(Address(r15, -0x41884769), r23); // and dword ptr [r15-0x41884769], r23d IID24 + __ cmpb(Address(r20, r18, (Address::ScaleFactor)0, -0x1b827588), r8); // cmp byte ptr [r20+r18*1-0x1b827588], r8b IID25 + __ cmpw(Address(r9, r22, (Address::ScaleFactor)3, +0x564ead70), r31); // cmp word ptr [r9+r22*8+0x564ead70], r31w IID26 + __ cmpl(Address(r10, r24, (Address::ScaleFactor)2, +0xf08ffec), rcx); // cmp dword ptr [r10+r24*4+0xf08ffec], ecx IID27 + __ orb(Address(r27, r15, (Address::ScaleFactor)0, +0xf18eac7), r19); // or byte ptr [r27+r15*1+0xf18eac7], r19b IID28 + __ orl(Address(r16, r31, (Address::ScaleFactor)2, +0x3a452790), r12); // or dword ptr [r16+r31*4+0x3a452790], r12d IID29 + __ xorb(Address(r20, r13, (Address::ScaleFactor)0, +0x61dde6b7), r10); // xor byte ptr [r20+r13*1+0x61dde6b7], r10b IID30 + __ xorl(Address(r27, -0x77a99463), rbx); // xor dword ptr [r27-0x77a99463], ebx IID31 + __ subl(Address(r9, r11, (Address::ScaleFactor)0, +0x4e20f145), r10); // sub dword ptr [r9+r11*1+0x4e20f145], r10d IID32 + __ movb(Address(r23, r23, (Address::ScaleFactor)0, -0x3f51b77), r10); // mov byte ptr [r23+r23*1-0x3f51b77], r10b IID33 + __ movl(Address(r31, r22, (Address::ScaleFactor)0, +0xfac5466), r30); // mov dword ptr [r31+r22*1+0xfac5466], r30d IID34 + __ xaddb(Address(rbx, -0x70025991), r31); // xadd byte ptr [rbx-0x70025991], r31b IID35 + __ xaddw(Address(r17, r26, (Address::ScaleFactor)1, -0x530c0221), r29); // xadd word ptr [r17+r26*2-0x530c0221], r29w IID36 + __ xaddl(Address(r9, r21, (Address::ScaleFactor)0, -0x7b7336bf), r17); // xadd dword ptr [r9+r21*1-0x7b7336bf], r17d IID37 + __ adcl(Address(r24, r12, (Address::ScaleFactor)2, +0x691b07e5), 65536); // adc dword ptr [r24+r12*4+0x691b07e5], 65536 IID38 + __ andl(Address(r14, r9, (Address::ScaleFactor)0, -0x115d5957), 16); // and dword ptr [r14+r9*1-0x115d5957], 16 IID39 + __ addb(Address(r21, -0x1d3e83ad), 64); // add byte ptr [r21-0x1d3e83ad], 64 IID40 + __ addw(Address(r12, +0x3a7acf9a), 4096); // add word ptr [r12+0x3a7acf9a], 4096 IID41 + __ addl(Address(r30, r14, (Address::ScaleFactor)1, -0x2073ed16), 256); // add dword ptr [r30+r14*2-0x2073ed16], 256 IID42 + __ cmpb(Address(r28, r18, (Address::ScaleFactor)0, +0x6fd326d5), 16); // cmp byte ptr [r28+r18*1+0x6fd326d5], 16 IID43 + __ cmpw(Address(r12, r14, (Address::ScaleFactor)1, +0x2ae6568f), 256); // cmp word ptr [r12+r14*2+0x2ae6568f], 256 IID44 + __ cmpl(Address(r24, r30, (Address::ScaleFactor)3, -0x11b9aeac), 1048576); // cmp dword ptr [r24+r30*8-0x11b9aeac], 1048576 IID45 + __ sarl(Address(r22, r30, (Address::ScaleFactor)2, +0x60cb9115), 1); // sar dword ptr [r22+r30*4+0x60cb9115], 1 IID46 + __ sall(Address(r31, r8, (Address::ScaleFactor)1, +0x236d8ab9), 16); // sal dword ptr [r31+r8*2+0x236d8ab9], 16 IID47 + __ sbbl(Address(r21, r12, (Address::ScaleFactor)1, -0x7d9b9f18), 16777216); // sbb dword ptr [r21+r12*2-0x7d9b9f18], 16777216 IID48 + __ shrl(Address(r29, r17, (Address::ScaleFactor)0, -0x7c54f216), 8); // shr dword ptr [r29+r17*1-0x7c54f216], 8 IID49 + __ subl(Address(r8, r27, (Address::ScaleFactor)2, -0x1190e2c6), 16); // sub dword ptr [r8+r27*4-0x1190e2c6], 16 IID50 + __ xorl(Address(rdx, +0x50dd3396), 1048576); // xor dword ptr [rdx+0x50dd3396], 1048576 IID51 + __ orb(Address(r20, -0x7dd1f614), 64); // or byte ptr [r20-0x7dd1f614], 64 IID52 + __ orl(Address(r18, +0x6f852a9f), 16); // or dword ptr [r18+0x6f852a9f], 16 IID53 + __ movb(Address(r20, r8, (Address::ScaleFactor)2, +0x436e2aa), 1); // mov byte ptr [r20+r8*4+0x436e2aa], 1 IID54 + __ movl(Address(rcx, r14, (Address::ScaleFactor)1, +0x883df84), 16); // mov dword ptr [rcx+r14*2+0x883df84], 16 IID55 + __ testb(Address(r11, r10, (Address::ScaleFactor)1, -0x1fc2039b), 16); // test byte ptr [r11+r10*2-0x1fc2039b], 16 IID56 + __ testl(Address(r29, +0x73b9f003), 67108864); // test dword ptr [r29+0x73b9f003], 67108864 IID57 + __ cmpl_imm32(Address(r29, rcx, (Address::ScaleFactor)2, +0x4ca2b092), 4194304); // cmp dword ptr [r29+rcx*4+0x4ca2b092], 4194304 IID58 + __ addl(r8, Address(rdx, r24, (Address::ScaleFactor)2, -0x1e1524dc)); // add r8d, dword ptr [rdx+r24*4-0x1e1524dc] IID59 + __ andl(r19, Address(r20, r20, (Address::ScaleFactor)1, +0x6286892)); // and r19d, dword ptr [r20+r20*2+0x6286892] IID60 + __ cmpb(r11, Address(r13, -0x42e0bf9e)); // cmp r11b, byte ptr [r13-0x42e0bf9e] IID61 + __ cmpl(r20, Address(rbx, r30, (Address::ScaleFactor)3, -0x30497735)); // cmp r20d, dword ptr [rbx+r30*8-0x30497735] IID62 + __ lzcntl(r8, Address(rdx, r9, (Address::ScaleFactor)1, +0xe2e99e)); // lzcnt r8d, dword ptr [rdx+r9*2+0xe2e99e] IID63 + __ orl(r9, Address(r29, r25, (Address::ScaleFactor)1, +0x50169f63)); // or r9d, dword ptr [r29+r25*2+0x50169f63] IID64 + __ adcl(r17, Address(r31, r21, (Address::ScaleFactor)3, +0x79efd170)); // adc r17d, dword ptr [r31+r21*8+0x79efd170] IID65 + __ imull(r23, Address(r8, -0xa521f73)); // imul r23d, dword ptr [r8-0xa521f73] IID66 + __ popcntl(r30, Address(r10, +0x44352901)); // popcnt r30d, dword ptr [r10+0x44352901] IID67 + __ sbbl(r16, Address(r18, r14, (Address::ScaleFactor)1, -0xda8278a)); // sbb r16d, dword ptr [r18+r14*2-0xda8278a] IID68 + __ subl(r17, Address(r22, +0x2d63aab3)); // sub r17d, dword ptr [r22+0x2d63aab3] IID69 + __ tzcntl(r23, Address(r21, r11, (Address::ScaleFactor)0, -0x18bc7469)); // tzcnt r23d, dword ptr [r21+r11*1-0x18bc7469] IID70 + __ xorb(r9, Address(r19, rdx, (Address::ScaleFactor)0, -0x5f6207ed)); // xor r9b, byte ptr [r19+rdx*1-0x5f6207ed] IID71 + __ xorw(r11, Address(r21, r10, (Address::ScaleFactor)2, -0x63c79f2b)); // xor r11w, word ptr [r21+r10*4-0x63c79f2b] IID72 + __ xorl(r29, Address(r31, rcx, (Address::ScaleFactor)3, +0x34d93c0f)); // xor r29d, dword ptr [r31+rcx*8+0x34d93c0f] IID73 + __ movb(r17, Address(r8, r18, (Address::ScaleFactor)2, -0x38ff3ad7)); // mov r17b, byte ptr [r8+r18*4-0x38ff3ad7] IID74 + __ movl(r31, Address(r20, r11, (Address::ScaleFactor)2, -0x1d23470c)); // mov r31d, dword ptr [r20+r11*4-0x1d23470c] IID75 + __ leal(r31, Address(rbx, r12, (Address::ScaleFactor)2, -0x3b4a4215)); // lea r31d, dword ptr [rbx+r12*4-0x3b4a4215] IID76 + __ xchgb(r20, Address(r30, r24, (Address::ScaleFactor)0, -0x5c4e82bc)); // xchg r20b, byte ptr [r30+r24*1-0x5c4e82bc] IID77 + __ xchgw(r13, Address(r10, r21, (Address::ScaleFactor)3, +0x19bd4a03)); // xchg r13w, word ptr [r10+r21*8+0x19bd4a03] IID78 + __ xchgl(r23, Address(r16, r13, (Address::ScaleFactor)2, -0x6a0293d6)); // xchg r23d, dword ptr [r16+r13*4-0x6a0293d6] IID79 + __ testl(r13, Address(r9, +0x34a6ff61)); // test r13d, dword ptr [r9+0x34a6ff61] IID80 + __ addb(r23, 4); // add r23b, 4 IID81 + __ addl(r28, 65536); // add r28d, 65536 IID82 +#endif // _LP64 + __ andl(rdx, 65536); // and edx, 65536 IID83 +#ifdef _LP64 + __ adcl(r27, 1048576); // adc r27d, 1048576 IID84 + __ cmpb(r13, 4); // cmp r13b, 4 IID85 + __ cmpl(r29, 268435456); // cmp r29d, 268435456 IID86 + __ rcll(r20, 16); // rcl r20d, 16 IID87 + __ roll(r25, 2); // rol r25d, 2 IID88 +#endif // _LP64 + __ rorl(rdx, 4); // ror edx, 4 IID89 + __ sarl(rcx, 1); // sar ecx, 1 IID90 +#ifdef _LP64 + __ sall(r19, 16); // sal r19d, 16 IID91 + __ sbbl(r9, 1); // sbb r9d, 1 IID92 + __ shll(r20, 8); // shl r20d, 8 IID93 +#endif // _LP64 + __ shrl(rcx, 1); // shr ecx, 1 IID94 +#ifdef _LP64 + __ subl(r19, 16777216); // sub r19d, 16777216 IID95 + __ xorl(r16, 4096); // xor r16d, 4096 IID96 + __ movl(r24, 65536); // mov r24d, 65536 IID97 + __ testb(r20, 64); // test r20b, 64 IID98 + __ testl(r28, 16777216); // test r28d, 16777216 IID99 + __ subl_imm32(r29, 262144); // sub r29d, 262144 IID100 + __ cmovl(Assembler::Condition::overflow, r8, Address(r26, r28, (Address::ScaleFactor)1, +0x210f06d)); // cmovo r8d, dword ptr [r26+r28*2+0x210f06d] IID101 + __ cmovl(Assembler::Condition::noOverflow, rbx, Address(r18, rbx, (Address::ScaleFactor)0, -0x264fce2a)); // cmovno ebx, dword ptr [r18+rbx*1-0x264fce2a] IID102 + __ cmovl(Assembler::Condition::below, r29, Address(r17, r24, (Address::ScaleFactor)0, +0x46c06acb)); // cmovb r29d, dword ptr [r17+r24*1+0x46c06acb] IID103 + __ cmovl(Assembler::Condition::aboveEqual, r17, Address(r25, r11, (Address::ScaleFactor)3, -0x3b21f455)); // cmovae r17d, dword ptr [r25+r11*8-0x3b21f455] IID104 + __ cmovl(Assembler::Condition::zero, r23, Address(r20, r31, (Address::ScaleFactor)0, -0x5a03317b)); // cmovz r23d, dword ptr [r20+r31*1-0x5a03317b] IID105 + __ cmovl(Assembler::Condition::notZero, r31, Address(r31, r15, (Address::ScaleFactor)2, -0x53fc2e65)); // cmovnz r31d, dword ptr [r31+r15*4-0x53fc2e65] IID106 + __ cmovl(Assembler::Condition::belowEqual, r28, Address(rdx, rcx, (Address::ScaleFactor)3, -0x3bc9229f)); // cmovbe r28d, dword ptr [rdx+rcx*8-0x3bc9229f] IID107 + __ cmovl(Assembler::Condition::above, r31, Address(rdx, r19, (Address::ScaleFactor)3, +0x7bf1761c)); // cmova r31d, dword ptr [rdx+r19*8+0x7bf1761c] IID108 + __ cmovl(Assembler::Condition::negative, rdx, Address(r17, r18, (Address::ScaleFactor)0, -0x1da2fc03)); // cmovs edx, dword ptr [r17+r18*1-0x1da2fc03] IID109 + __ cmovl(Assembler::Condition::positive, r9, Address(r21, r23, (Address::ScaleFactor)2, -0x2799454a)); // cmovns r9d, dword ptr [r21+r23*4-0x2799454a] IID110 + __ cmovl(Assembler::Condition::parity, r27, Address(r13, -0x654c249c)); // cmovp r27d, dword ptr [r13-0x654c249c] IID111 + __ cmovl(Assembler::Condition::noParity, rdx, Address(r24, r10, (Address::ScaleFactor)3, +0x6c96beb2)); // cmovnp edx, dword ptr [r24+r10*8+0x6c96beb2] IID112 + __ cmovl(Assembler::Condition::less, r9, Address(rcx, r8, (Address::ScaleFactor)3, +0x573e1892)); // cmovl r9d, dword ptr [rcx+r8*8+0x573e1892] IID113 + __ cmovl(Assembler::Condition::greaterEqual, r31, Address(r26, r14, (Address::ScaleFactor)2, +0x717110b1)); // cmovge r31d, dword ptr [r26+r14*4+0x717110b1] IID114 + __ cmovl(Assembler::Condition::lessEqual, r24, Address(r19, r14, (Address::ScaleFactor)2, +0x119faad7)); // cmovle r24d, dword ptr [r19+r14*4+0x119faad7] IID115 + __ cmovl(Assembler::Condition::greater, r12, Address(r13, r12, (Address::ScaleFactor)0, +0xd537805)); // cmovg r12d, dword ptr [r13+r12*1+0xd537805] IID116 + __ setb(Assembler::Condition::overflow, r10); // seto r10b IID117 +#endif // _LP64 + __ setb(Assembler::Condition::noOverflow, rbx); // setno bl IID118 +#ifdef _LP64 + __ setb(Assembler::Condition::below, r13); // setb r13b IID119 + __ setb(Assembler::Condition::aboveEqual, r23); // setae r23b IID120 + __ setb(Assembler::Condition::zero, r24); // setz r24b IID121 + __ setb(Assembler::Condition::notZero, r15); // setnz r15b IID122 + __ setb(Assembler::Condition::belowEqual, r21); // setbe r21b IID123 + __ setb(Assembler::Condition::above, r17); // seta r17b IID124 + __ setb(Assembler::Condition::negative, r10); // sets r10b IID125 + __ setb(Assembler::Condition::positive, r24); // setns r24b IID126 + __ setb(Assembler::Condition::parity, r16); // setp r16b IID127 + __ setb(Assembler::Condition::noParity, r28); // setnp r28b IID128 + __ setb(Assembler::Condition::less, r11); // setl r11b IID129 + __ setb(Assembler::Condition::greaterEqual, r25); // setge r25b IID130 + __ setb(Assembler::Condition::lessEqual, r18); // setle r18b IID131 + __ setb(Assembler::Condition::greater, r14); // setg r14b IID132 + __ divl(r30); // div r30d IID133 + __ idivl(r23); // idiv r23d IID134 + __ imull(r28); // imul r28d IID135 + __ mull(r31); // mul r31d IID136 + __ negl(r27); // neg r27d IID137 + __ notl(r16); // not r16d IID138 +#endif // _LP64 + __ roll(rdx); // rol edx, cl IID139 +#ifdef _LP64 + __ rorl(r12); // ror r12d, cl IID140 + __ sarl(r14); // sar r14d, cl IID141 + __ sall(r19); // sal r19d, cl IID142 + __ shll(r10); // shl r10d, cl IID143 + __ shrl(r20); // shr r20d, cl IID144 +#endif // _LP64 + __ incrementl(rbx); // inc ebx IID145 +#ifdef _LP64 + __ decrementl(r14); // dec r14d IID146 + __ mull(Address(r12, -0x57a4fa5e)); // mul dword ptr [r12-0x57a4fa5e] IID147 + __ negl(Address(rbx, -0x3db4cfc7)); // neg dword ptr [rbx-0x3db4cfc7] IID148 + __ sarl(Address(r21, -0x7e70ad30)); // sar dword ptr [r21-0x7e70ad30], cl IID149 + __ sall(Address(r21, r28, (Address::ScaleFactor)3, -0x23456bc9)); // sal dword ptr [r21+r28*8-0x23456bc9], cl IID150 + __ shrl(Address(r11, r13, (Address::ScaleFactor)1, -0xe00fc44)); // shr dword ptr [r11+r13*2-0xe00fc44], cl IID151 + __ incrementl(Address(r19, -0x5e6ad56a)); // inc dword ptr [r19-0x5e6ad56a] IID152 + __ decrementl(Address(rcx, r20, (Address::ScaleFactor)0, -0x2530b9c4)); // dec dword ptr [rcx+r20*1-0x2530b9c4] IID153 + __ imull(r17, Address(r8, r24, (Address::ScaleFactor)1, +0x2efecf26), 1048576); // imul r17d, dword ptr [r8+r24*2+0x2efecf26], 1048576 IID154 + __ imull(r9, r8, 268435456); // imul r9d, r8d, 268435456 IID155 + __ shldl(r10, r15, 8); // shld r10d, r15d, 8 IID156 + __ shrdl(r29, r22, 2); // shrd r29d, r22d, 2 IID157 + __ movzbl(r14, Address(r19, -0x6c33584)); // movzx r14d, byte ptr [r19-0x6c33584] IID158 + __ movzwl(r25, Address(r12, r27, (Address::ScaleFactor)0, +0x2d05fa44)); // movzx r25d, word ptr [r12+r27*1+0x2d05fa44] IID159 + __ movsbl(r12, Address(r30, r15, (Address::ScaleFactor)0, +0x65bccac1)); // movsx r12d, byte ptr [r30+r15*1+0x65bccac1] IID160 + __ movswl(r26, Address(r10, r24, (Address::ScaleFactor)0, +0x1d707459)); // movsx r26d, word ptr [r10+r24*1+0x1d707459] IID161 + __ movzbl(r18, r8); // movzx r18d, r8b IID162 + __ movzwl(r31, r9); // movzx r31d, r9w IID163 + __ movsbl(r15, r22); // movsx r15d, r22b IID164 + __ movswl(r24, r24); // movsx r24d, r24w IID165 + __ cmpxchgb(r18, Address(r12, r28, (Address::ScaleFactor)1, -0x4855a65f)); // cmpxchg byte ptr [r12+r28*2-0x4855a65f], r18b IID166 + __ cmpxchgw(r28, Address(rdx, r14, (Address::ScaleFactor)3, +0x16f5a558)); // cmpxchg word ptr [rdx+r14*8+0x16f5a558], r28w IID167 + __ cmpxchgl(rdx, Address(r18, rdx, (Address::ScaleFactor)1, +0x50258d9c)); // cmpxchg dword ptr [r18+rdx*2+0x50258d9c], edx IID168 +#endif // _LP64 +#ifdef _LP64 + __ adcq(r9, rbx); // {load}adc r9, rbx IID169 + __ cmpq(r26, r24); // {load}cmp r26, r24 IID170 + __ imulq(r14, rdx); // {load}imul r14, rdx IID171 + __ popcntq(r25, r30); // {load}popcnt r25, r30 IID172 + __ sbbq(r24, r19); // {load}sbb r24, r19 IID173 + __ subq(r15, r11); // {load}sub r15, r11 IID174 + __ tzcntq(r18, r21); // {load}tzcnt r18, r21 IID175 + __ lzcntq(r15, r27); // {load}lzcnt r15, r27 IID176 + __ addq(r21, r20); // {load}add r21, r20 IID177 + __ andq(r11, r26); // {load}and r11, r26 IID178 + __ orq(r29, r15); // {load}or r29, r15 IID179 + __ xorq(r24, r21); // {load}xor r24, r21 IID180 + __ movq(r14, r13); // {load}mov r14, r13 IID181 + __ bsfq(r11, r22); // {load}bsf r11, r22 IID182 + __ bsrq(r14, r23); // {load}bsr r14, r23 IID183 + __ btq(r22, rcx); // {load}bt r22, rcx IID184 + __ xchgq(r25, r29); // {load}xchg r25, r29 IID185 + __ testq(r15, r8); // {load}test r15, r8 IID186 + __ addq(Address(r14, r10, (Address::ScaleFactor)3, -0x36e6fa02), r16); // add qword ptr [r14+r10*8-0x36e6fa02], r16 IID187 + __ andq(Address(rbx, r8, (Address::ScaleFactor)3, -0x279a21b8), r18); // and qword ptr [rbx+r8*8-0x279a21b8], r18 IID188 + __ cmpq(Address(r24, +0x62c3c9ef), r13); // cmp qword ptr [r24+0x62c3c9ef], r13 IID189 + __ orq(Address(r11, r22, (Address::ScaleFactor)2, +0x419fb378), r11); // or qword ptr [r11+r22*4+0x419fb378], r11 IID190 + __ xorq(Address(r25, r14, (Address::ScaleFactor)2, -0x32b449dd), r13); // xor qword ptr [r25+r14*4-0x32b449dd], r13 IID191 + __ subq(Address(r28, r31, (Address::ScaleFactor)3, +0x6ce1d361), r19); // sub qword ptr [r28+r31*8+0x6ce1d361], r19 IID192 + __ movq(Address(r25, r25, (Address::ScaleFactor)2, -0x3f5767c), r11); // mov qword ptr [r25+r25*4-0x3f5767c], r11 IID193 + __ xaddq(Address(r19, r17, (Address::ScaleFactor)3, +0x1febf06c), r20); // xadd qword ptr [r19+r17*8+0x1febf06c], r20 IID194 + __ andq(Address(r26, r17, (Address::ScaleFactor)1, -0x6b865f05), 65536); // and qword ptr [r26+r17*2-0x6b865f05], 65536 IID195 + __ addq(Address(r27, -0x6ec95d87), 65536); // add qword ptr [r27-0x6ec95d87], 65536 IID196 + __ cmpq(Address(rbx, r26, (Address::ScaleFactor)2, -0x1eabea4), 1048576); // cmp qword ptr [rbx+r26*4-0x1eabea4], 1048576 IID197 + __ sarq(Address(rbx, r19, (Address::ScaleFactor)0, +0x3c3c3de8), 8); // sar qword ptr [rbx+r19*1+0x3c3c3de8], 8 IID198 + __ salq(Address(r20, r23, (Address::ScaleFactor)1, +0x68519b6d), 8); // sal qword ptr [r20+r23*2+0x68519b6d], 8 IID199 + __ sbbq(Address(r31, r22, (Address::ScaleFactor)0, -0x7b3d1e85), 16); // sbb qword ptr [r31+r22*1-0x7b3d1e85], 16 IID200 + __ shrq(Address(r15, r18, (Address::ScaleFactor)3, +0x4d9d824), 4); // shr qword ptr [r15+r18*8+0x4d9d824], 4 IID201 + __ subq(Address(rdx, r29, (Address::ScaleFactor)2, +0x7e4aea85), 1); // sub qword ptr [rdx+r29*4+0x7e4aea85], 1 IID202 + __ xorq(Address(r23, r10, (Address::ScaleFactor)1, +0x2895c620), 16777216); // xor qword ptr [r23+r10*2+0x2895c620], 16777216 IID203 + __ orq(Address(r14, r13, (Address::ScaleFactor)0, -0x771b399b), 1); // or qword ptr [r14+r13*1-0x771b399b], 1 IID204 + __ movq(Address(r22, -0x63459b5a), 256); // mov qword ptr [r22-0x63459b5a], 256 IID205 + __ testq(Address(r13, -0xb9691c5), -1); // test qword ptr [r13-0xb9691c5], -1 IID206 + __ addq(r17, Address(r15, -0x51b64b0d)); // add r17, qword ptr [r15-0x51b64b0d] IID207 + __ andq(rcx, Address(r16, rcx, (Address::ScaleFactor)3, -0x1c8e4b54)); // and rcx, qword ptr [r16+rcx*8-0x1c8e4b54] IID208 + __ cmpq(r23, Address(r17, rcx, (Address::ScaleFactor)3, -0x44705560)); // cmp r23, qword ptr [r17+rcx*8-0x44705560] IID209 + __ lzcntq(r19, Address(r19, +0x487fe792)); // lzcnt r19, qword ptr [r19+0x487fe792] IID210 + __ orq(r11, Address(r17, -0x65de4329)); // or r11, qword ptr [r17-0x65de4329] IID211 + __ adcq(r29, Address(r9, -0x7092dc03)); // adc r29, qword ptr [r9-0x7092dc03] IID212 + __ imulq(r9, Address(r26, r26, (Address::ScaleFactor)3, -0x118287f7)); // imul r9, qword ptr [r26+r26*8-0x118287f7] IID213 + __ popcntq(r19, Address(r15, r19, (Address::ScaleFactor)1, -0x6e31ef95)); // popcnt r19, qword ptr [r15+r19*2-0x6e31ef95] IID214 + __ sbbq(r30, Address(r23, -0x46545c5e)); // sbb r30, qword ptr [r23-0x46545c5e] IID215 + __ subq(r23, Address(r31, r18, (Address::ScaleFactor)3, +0x663c37d8)); // sub r23, qword ptr [r31+r18*8+0x663c37d8] IID216 + __ tzcntq(r24, Address(r24, r25, (Address::ScaleFactor)3, -0x465a78f1)); // tzcnt r24, qword ptr [r24+r25*8-0x465a78f1] IID217 + __ xorq(r14, Address(r15, r19, (Address::ScaleFactor)1, +0x4196affa)); // xor r14, qword ptr [r15+r19*2+0x4196affa] IID218 + __ movq(rdx, Address(r25, r29, (Address::ScaleFactor)1, +0x115a6157)); // mov rdx, qword ptr [r25+r29*2+0x115a6157] IID219 + __ leaq(r19, Address(r28, r31, (Address::ScaleFactor)2, +0x6b82f933)); // lea r19, qword ptr [r28+r31*4+0x6b82f933] IID220 + __ cvttsd2siq(rcx, Address(r24, r21, (Address::ScaleFactor)3, -0x39dc99eb)); // cvttsd2si rcx, qword ptr [r24+r21*8-0x39dc99eb] IID221 + __ xchgq(r29, Address(r17, r24, (Address::ScaleFactor)3, +0x5902f01d)); // xchg r29, qword ptr [r17+r24*8+0x5902f01d] IID222 + __ testq(r12, Address(r24, r29, (Address::ScaleFactor)2, +0x8865bfc)); // test r12, qword ptr [r24+r29*4+0x8865bfc] IID223 + __ addq(r10, 16); // add r10, 16 IID224 + __ andq(r26, 256); // and r26, 256 IID225 + __ adcq(rcx, 1); // adc rcx, 1 IID226 + __ cmpq(r21, 65536); // cmp r21, 65536 IID227 + __ rclq(r28, 4); // rcl r28, 4 IID228 + __ rcrq(r28, 16); // rcr r28, 16 IID229 + __ rolq(r18, 1); // rol r18, 1 IID230 + __ rorq(r26, 2); // ror r26, 2 IID231 + __ sarq(r19, 2); // sar r19, 2 IID232 + __ salq(r14, 8); // sal r14, 8 IID233 + __ sbbq(r10, 65536); // sbb r10, 65536 IID234 + __ shlq(r30, 1); // shl r30, 1 IID235 + __ shrq(r15, 8); // shr r15, 8 IID236 + __ subq(r21, 1048576); // sub r21, 1048576 IID237 + __ xorq(rbx, 268435456); // xor rbx, 268435456 IID238 + __ movq(r19, 16); // mov r19, 16 IID239 + __ mov64(r19, 17179869184); // mov r19, 17179869184 IID240 + __ btq(r21, 1); // bt r21, 1 IID241 + __ testq(r15, -65536); // test r15, -65536 IID242 + __ orq_imm32(r21, 1073741824); // or r21, 1073741824 IID243 + __ subq_imm32(r19, 65536); // sub r19, 65536 IID244 + __ cmovq(Assembler::Condition::overflow, r15, Address(r29, -0x5c98219a)); // cmovo r15, qword ptr [r29-0x5c98219a] IID245 + __ cmovq(Assembler::Condition::noOverflow, rcx, Address(r21, +0x22cc581)); // cmovno rcx, qword ptr [r21+0x22cc581] IID246 + __ cmovq(Assembler::Condition::below, r15, Address(r29, r13, (Address::ScaleFactor)2, -0x5e968fb9)); // cmovb r15, qword ptr [r29+r13*4-0x5e968fb9] IID247 + __ cmovq(Assembler::Condition::aboveEqual, r26, Address(r24, +0x440c6894)); // cmovae r26, qword ptr [r24+0x440c6894] IID248 + __ cmovq(Assembler::Condition::zero, r17, Address(r23, r26, (Address::ScaleFactor)3, +0x23558b4e)); // cmovz r17, qword ptr [r23+r26*8+0x23558b4e] IID249 + __ cmovq(Assembler::Condition::notZero, r9, Address(r16, r29, (Address::ScaleFactor)3, -0x1289a3c9)); // cmovnz r9, qword ptr [r16+r29*8-0x1289a3c9] IID250 + __ cmovq(Assembler::Condition::belowEqual, r8, Address(r11, -0x49e134cc)); // cmovbe r8, qword ptr [r11-0x49e134cc] IID251 + __ cmovq(Assembler::Condition::above, r26, Address(r11, r20, (Address::ScaleFactor)1, -0x3ef9057a)); // cmova r26, qword ptr [r11+r20*2-0x3ef9057a] IID252 + __ cmovq(Assembler::Condition::negative, r11, Address(r26, r13, (Address::ScaleFactor)2, +0x4bd18f9f)); // cmovs r11, qword ptr [r26+r13*4+0x4bd18f9f] IID253 + __ cmovq(Assembler::Condition::positive, r8, Address(r9, r11, (Address::ScaleFactor)3, +0x4b42a528)); // cmovns r8, qword ptr [r9+r11*8+0x4b42a528] IID254 + __ cmovq(Assembler::Condition::parity, r12, Address(r19, r9, (Address::ScaleFactor)1, +0x68559a1c)); // cmovp r12, qword ptr [r19+r9*2+0x68559a1c] IID255 + __ cmovq(Assembler::Condition::noParity, r22, Address(r18, r17, (Address::ScaleFactor)1, +0x2c4d8e80)); // cmovnp r22, qword ptr [r18+r17*2+0x2c4d8e80] IID256 + __ cmovq(Assembler::Condition::less, r26, Address(r18, r30, (Address::ScaleFactor)0, -0x2ae8896e)); // cmovl r26, qword ptr [r18+r30*1-0x2ae8896e] IID257 + __ cmovq(Assembler::Condition::greaterEqual, r22, Address(r11, +0x4fefa622)); // cmovge r22, qword ptr [r11+0x4fefa622] IID258 + __ cmovq(Assembler::Condition::lessEqual, r28, Address(r18, r27, (Address::ScaleFactor)1, +0x6b7a8c34)); // cmovle r28, qword ptr [r18+r27*2+0x6b7a8c34] IID259 + __ cmovq(Assembler::Condition::greater, r20, Address(r23, r20, (Address::ScaleFactor)0, -0x12e725c5)); // cmovg r20, qword ptr [r23+r20*1-0x12e725c5] IID260 + __ call(r9); // call r9 IID261 + __ divq(r22); // div r22 IID262 + __ idivq(r29); // idiv r29 IID263 + __ imulq(rbx); // imul rbx IID264 + __ mulq(r27); // mul r27 IID265 + __ negq(rbx); // neg rbx IID266 + __ notq(r17); // not r17 IID267 + __ rolq(r25); // rol r25, cl IID268 + __ rorq(rbx); // ror rbx, cl IID269 + __ sarq(r17); // sar r17, cl IID270 + __ salq(r28); // sal r28, cl IID271 + __ shlq(r28); // shl r28, cl IID272 + __ shrq(r30); // shr r30, cl IID273 + __ incrementq(r27); // inc r27 IID274 + __ decrementq(rdx); // dec rdx IID275 + __ pushp(r27); // pushp r27 IID276 + __ popp(r10); // popp r10 IID277 + __ call(Address(r27, -0x22db8705)); // call qword ptr [r27-0x22db8705] IID278 + __ mulq(Address(r27, r21, (Address::ScaleFactor)0, -0x1f59ff9c)); // mul qword ptr [r27+r21*1-0x1f59ff9c] IID279 + __ negq(Address(r19, rcx, (Address::ScaleFactor)3, +0x7a47b812)); // neg qword ptr [r19+rcx*8+0x7a47b812] IID280 + __ sarq(Address(r18, r21, (Address::ScaleFactor)1, -0x48857a46)); // sar qword ptr [r18+r21*2-0x48857a46], cl IID281 + __ salq(Address(r24, -0x7a2bda2c)); // sal qword ptr [r24-0x7a2bda2c], cl IID282 + __ shrq(Address(r24, +0x1abd92f)); // shr qword ptr [r24+0x1abd92f], cl IID283 + __ incrementq(Address(r9, r9, (Address::ScaleFactor)3, +0x31a92520)); // inc qword ptr [r9+r9*8+0x31a92520] IID284 + __ decrementq(Address(r9, r8, (Address::ScaleFactor)0, +0x7f14b4bd)); // dec qword ptr [r9+r8*1+0x7f14b4bd] IID285 + __ imulq(r14, Address(r29, r15, (Address::ScaleFactor)1, +0x5281cf9c), 256); // imul r14, qword ptr [r29+r15*2+0x5281cf9c], 256 IID286 + __ imulq(r16, r28, 1048576); // imul r16, r28, 1048576 IID287 + __ shldq(r17, r24, 2); // shld r17, r24, 2 IID288 + __ shrdq(r16, r11, 2); // shrd r16, r11, 2 IID289 + __ pop2(r10, r11); // {load}pop2 r11, r10 IID290 + __ pop2p(r15, r24); // {load}pop2p r24, r15 IID291 + __ push2(r28, r11); // {load}push2 r11, r28 IID292 + __ push2p(r12, r31); // {load}push2p r31, r12 IID293 + __ movzbq(r24, Address(r22, r16, (Address::ScaleFactor)0, +0x511be837)); // movzx r24, byte ptr [r22+r16*1+0x511be837] IID294 + __ movzwq(r15, Address(r15, r26, (Address::ScaleFactor)2, -0x38794ee)); // movzx r15, word ptr [r15+r26*4-0x38794ee] IID295 + __ movsbq(r15, Address(r25, r16, (Address::ScaleFactor)3, -0x7a092741)); // movsx r15, byte ptr [r25+r16*8-0x7a092741] IID296 + __ movswq(rdx, Address(r28, r19, (Address::ScaleFactor)2, +0x79da6a)); // movsx rdx, word ptr [r28+r19*4+0x79da6a] IID297 + __ movzbq(r27, r9); // movzx r27, r9b IID298 + __ movzwq(r25, r21); // movzx r25, r21w IID299 + __ movsbq(r14, r12); // movsx r14, r12b IID300 + __ movswq(r23, r11); // movsx r23, r11w IID301 + __ cmpxchgq(r30, Address(r12, -0x65a974df)); // cmpxchg qword ptr [r12-0x65a974df], r30 IID302 +#endif // _LP64 + + static const uint8_t insns[] = + { +#ifdef _LP64 + 0xd5, 0x94, 0xa5, 0xf6, // IID0 +#endif // _LP64 + 0x0f, 0xad, 0xd9, // IID1 +#ifdef _LP64 + 0xd5, 0x54, 0x13, 0xc2, // IID2 + 0xd5, 0x14, 0x3b, 0xc3, // IID3 + 0xd5, 0xd4, 0xaf, 0xcb, // IID4 + 0xf3, 0xd5, 0xc1, 0xb8, 0xdf, // IID5 + 0xd5, 0x50, 0x1b, 0xeb, // IID6 + 0xd5, 0x51, 0x2b, 0xcd, // IID7 + 0xf3, 0xd5, 0xc0, 0xbc, 0xea, // IID8 + 0xf3, 0xd5, 0x90, 0xbd, 0xcf, // IID9 + 0x45, 0x03, 0xd3, // IID10 + 0xd5, 0x41, 0x23, 0xee, // IID11 + 0xd5, 0x15, 0x0b, 0xe6, // IID12 + 0xd5, 0x51, 0x33, 0xde, // IID13 + 0xd5, 0x45, 0x8b, 0xdb, // IID14 + 0x45, 0x0f, 0xbc, 0xd4, // IID15 + 0xd5, 0xc1, 0xbd, 0xc2, // IID16 + 0xd5, 0x51, 0x87, 0xc4, // IID17 + 0xd5, 0x54, 0x85, 0xc8, // IID18 + 0xd5, 0x11, 0x00, 0x8c, 0x53, 0x23, 0x47, 0x30, 0x6f, // IID19 + 0x66, 0xd5, 0x50, 0x01, 0x8c, 0x8b, 0x57, 0x4c, 0x24, 0x17, // IID20 + 0xd5, 0x70, 0x01, 0x9c, 0x47, 0x19, 0xf4, 0x8d, 0x13, // IID21 + 0x43, 0x11, 0x8c, 0xd8, 0x8d, 0x85, 0xb0, 0xe9, // IID22 + 0xd5, 0x60, 0x20, 0xb4, 0xca, 0x81, 0xf1, 0xf7, 0x4d, // IID23 + 0xd5, 0x41, 0x21, 0xbf, 0x97, 0xb8, 0x77, 0xbe, // IID24 + 0xd5, 0x34, 0x38, 0x84, 0x14, 0x78, 0x8a, 0x7d, 0xe4, // IID25 + 0x66, 0xd5, 0x65, 0x39, 0xbc, 0xf1, 0x70, 0xad, 0x4e, 0x56, // IID26 + 0xd5, 0x23, 0x39, 0x8c, 0x82, 0xec, 0xff, 0x08, 0x0f, // IID27 + 0xd5, 0x53, 0x08, 0x9c, 0x3b, 0xc7, 0xea, 0x18, 0x0f, // IID28 + 0xd5, 0x36, 0x09, 0xa4, 0xb8, 0x90, 0x27, 0x45, 0x3a, // IID29 + 0xd5, 0x16, 0x30, 0x94, 0x2c, 0xb7, 0xe6, 0xdd, 0x61, // IID30 + 0xd5, 0x11, 0x31, 0x9b, 0x9d, 0x6b, 0x56, 0x88, // IID31 + 0x47, 0x29, 0x94, 0x19, 0x45, 0xf1, 0x20, 0x4e, // IID32 + 0xd5, 0x34, 0x88, 0x94, 0x3f, 0x89, 0xe4, 0x0a, 0xfc, // IID33 + 0xd5, 0x75, 0x89, 0xb4, 0x37, 0x66, 0x54, 0xac, 0x0f, // IID34 + 0xd5, 0xc4, 0xc0, 0xbb, 0x6f, 0xa6, 0xfd, 0x8f, // IID35 + 0x66, 0xd5, 0xf6, 0xc1, 0xac, 0x51, 0xdf, 0xfd, 0xf3, 0xac, // IID36 + 0xd5, 0xe1, 0xc1, 0x8c, 0x29, 0x41, 0xc9, 0x8c, 0x84, // IID37 + 0xd5, 0x13, 0x81, 0x94, 0xa0, 0xe5, 0x07, 0x1b, 0x69, 0x00, 0x00, 0x01, 0x00, // IID38 + 0x43, 0x83, 0xa4, 0x0e, 0xa9, 0xa6, 0xa2, 0xee, 0x10, // IID39 + 0xd5, 0x10, 0x80, 0x85, 0x53, 0x7c, 0xc1, 0xe2, 0x40, // IID40 + 0x66, 0x41, 0x81, 0x84, 0x24, 0x9a, 0xcf, 0x7a, 0x3a, 0x00, 0x10, // IID41 + 0xd5, 0x13, 0x81, 0x84, 0x76, 0xea, 0x12, 0x8c, 0xdf, 0x00, 0x01, 0x00, 0x00, // IID42 + 0xd5, 0x31, 0x80, 0xbc, 0x14, 0xd5, 0x26, 0xd3, 0x6f, 0x10, // IID43 + 0x66, 0x43, 0x81, 0xbc, 0x74, 0x8f, 0x56, 0xe6, 0x2a, 0x00, 0x01, // IID44 + 0xd5, 0x33, 0x81, 0xbc, 0xf0, 0x54, 0x51, 0x46, 0xee, 0x00, 0x00, 0x10, 0x00, // IID45 + 0xd5, 0x32, 0xd1, 0xbc, 0xb6, 0x15, 0x91, 0xcb, 0x60, // IID46 + 0xd5, 0x13, 0xc1, 0xa4, 0x47, 0xb9, 0x8a, 0x6d, 0x23, 0x10, // IID47 + 0xd5, 0x12, 0x81, 0x9c, 0x65, 0xe8, 0x60, 0x64, 0x82, 0x00, 0x00, 0x00, 0x01, // IID48 + 0xd5, 0x31, 0xc1, 0xac, 0x0d, 0xea, 0x0d, 0xab, 0x83, 0x08, // IID49 + 0xd5, 0x23, 0x83, 0xac, 0x98, 0x3a, 0x1d, 0x6f, 0xee, 0x10, // IID50 + 0x81, 0xb2, 0x96, 0x33, 0xdd, 0x50, 0x00, 0x00, 0x10, 0x00, // IID51 + 0xd5, 0x10, 0x80, 0x8c, 0x24, 0xec, 0x09, 0x2e, 0x82, 0x40, // IID52 + 0xd5, 0x10, 0x83, 0x8a, 0x9f, 0x2a, 0x85, 0x6f, 0x10, // IID53 + 0xd5, 0x12, 0xc6, 0x84, 0x84, 0xaa, 0xe2, 0x36, 0x04, 0x01, // IID54 + 0x42, 0xc7, 0x84, 0x71, 0x84, 0xdf, 0x83, 0x08, 0x10, 0x00, 0x00, 0x00, // IID55 + 0x43, 0xf6, 0x84, 0x53, 0x65, 0xfc, 0x3d, 0xe0, 0x10, // IID56 + 0xd5, 0x11, 0xf7, 0x85, 0x03, 0xf0, 0xb9, 0x73, 0x00, 0x00, 0x00, 0x04, // IID57 + 0xd5, 0x11, 0x81, 0xbc, 0x8d, 0x92, 0xb0, 0xa2, 0x4c, 0x00, 0x00, 0x40, 0x00, // IID58 + 0xd5, 0x26, 0x03, 0x84, 0x82, 0x24, 0xdb, 0xea, 0xe1, // IID59 + 0xd5, 0x70, 0x23, 0x9c, 0x64, 0x92, 0x68, 0x28, 0x06, // IID60 + 0x45, 0x3a, 0x9d, 0x62, 0x40, 0x1f, 0xbd, // IID61 + 0xd5, 0x62, 0x3b, 0xa4, 0xf3, 0xcb, 0x88, 0xb6, 0xcf, // IID62 + 0xf3, 0x46, 0x0f, 0xbd, 0x84, 0x4a, 0x9e, 0xe9, 0xe2, 0x00, // IID63 + 0xd5, 0x37, 0x0b, 0x8c, 0x4d, 0x63, 0x9f, 0x16, 0x50, // IID64 + 0xd5, 0x71, 0x13, 0x8c, 0xef, 0x70, 0xd1, 0xef, 0x79, // IID65 + 0xd5, 0xc1, 0xaf, 0xb8, 0x8d, 0xe0, 0xad, 0xf5, // IID66 + 0xf3, 0xd5, 0xc5, 0xb8, 0xb2, 0x01, 0x29, 0x35, 0x44, // IID67 + 0xd5, 0x52, 0x1b, 0x84, 0x72, 0x76, 0xd8, 0x57, 0xf2, // IID68 + 0xd5, 0x50, 0x2b, 0x8e, 0xb3, 0xaa, 0x63, 0x2d, // IID69 + 0xf3, 0xd5, 0xd2, 0xbc, 0xbc, 0x1d, 0x97, 0x8b, 0x43, 0xe7, // IID70 + 0xd5, 0x14, 0x32, 0x8c, 0x13, 0x13, 0xf8, 0x9d, 0xa0, // IID71 + 0x66, 0xd5, 0x16, 0x33, 0x9c, 0x95, 0xd5, 0x60, 0x38, 0x9c, // IID72 + 0xd5, 0x55, 0x33, 0xac, 0xcf, 0x0f, 0x3c, 0xd9, 0x34, // IID73 + 0xd5, 0x61, 0x8a, 0x8c, 0x90, 0x29, 0xc5, 0x00, 0xc7, // IID74 + 0xd5, 0x56, 0x8b, 0xbc, 0x9c, 0xf4, 0xb8, 0xdc, 0xe2, // IID75 + 0xd5, 0x46, 0x8d, 0xbc, 0xa3, 0xeb, 0xbd, 0xb5, 0xc4, // IID76 + 0xd5, 0x73, 0x86, 0xa4, 0x06, 0x44, 0x7d, 0xb1, 0xa3, // IID77 + 0x66, 0xd5, 0x25, 0x87, 0xac, 0xea, 0x03, 0x4a, 0xbd, 0x19, // IID78 + 0xd5, 0x52, 0x87, 0xbc, 0xa8, 0x2a, 0x6c, 0xfd, 0x95, // IID79 + 0x45, 0x85, 0xa9, 0x61, 0xff, 0xa6, 0x34, // IID80 + 0xd5, 0x10, 0x80, 0xc7, 0x04, // IID81 + 0xd5, 0x11, 0x81, 0xc4, 0x00, 0x00, 0x01, 0x00, // IID82 +#endif // _LP64 + 0x81, 0xe2, 0x00, 0x00, 0x01, 0x00, // IID83 +#ifdef _LP64 + 0xd5, 0x11, 0x81, 0xd3, 0x00, 0x00, 0x10, 0x00, // IID84 + 0x41, 0x80, 0xfd, 0x04, // IID85 + 0xd5, 0x11, 0x81, 0xfd, 0x00, 0x00, 0x00, 0x10, // IID86 + 0xd5, 0x10, 0xc1, 0xd4, 0x10, // IID87 + 0xd5, 0x11, 0xc1, 0xc1, 0x02, // IID88 +#endif // _LP64 + 0xc1, 0xca, 0x04, // IID89 + 0xd1, 0xf9, // IID90 +#ifdef _LP64 + 0xd5, 0x10, 0xc1, 0xe3, 0x10, // IID91 + 0x41, 0x83, 0xd9, 0x01, // IID92 + 0xd5, 0x10, 0xc1, 0xe4, 0x08, // IID93 +#endif // _LP64 + 0xd1, 0xe9, // IID94 +#ifdef _LP64 + 0xd5, 0x10, 0x81, 0xeb, 0x00, 0x00, 0x00, 0x01, // IID95 + 0xd5, 0x10, 0x81, 0xf0, 0x00, 0x10, 0x00, 0x00, // IID96 + 0xd5, 0x11, 0xb8, 0x00, 0x00, 0x01, 0x00, // IID97 + 0xd5, 0x10, 0xf6, 0xc4, 0x40, // IID98 + 0xd5, 0x11, 0xf7, 0xc4, 0x00, 0x00, 0x00, 0x01, // IID99 + 0xd5, 0x11, 0x81, 0xed, 0x00, 0x00, 0x04, 0x00, // IID100 + 0xd5, 0xb7, 0x40, 0x84, 0x62, 0x6d, 0xf0, 0x10, 0x02, // IID101 + 0xd5, 0x90, 0x41, 0x9c, 0x1a, 0xd6, 0x31, 0xb0, 0xd9, // IID102 + 0xd5, 0xf6, 0x42, 0xac, 0x01, 0xcb, 0x6a, 0xc0, 0x46, // IID103 + 0xd5, 0xd3, 0x43, 0x8c, 0xd9, 0xab, 0x0b, 0xde, 0xc4, // IID104 + 0xd5, 0xf2, 0x44, 0xbc, 0x3c, 0x85, 0xce, 0xfc, 0xa5, // IID105 + 0xd5, 0xd7, 0x45, 0xbc, 0xbf, 0x9b, 0xd1, 0x03, 0xac, // IID106 + 0xd5, 0xc4, 0x46, 0xa4, 0xca, 0x61, 0xdd, 0x36, 0xc4, // IID107 + 0xd5, 0xe4, 0x47, 0xbc, 0xda, 0x1c, 0x76, 0xf1, 0x7b, // IID108 + 0xd5, 0xb0, 0x48, 0x94, 0x11, 0xfd, 0x03, 0x5d, 0xe2, // IID109 + 0xd5, 0xb4, 0x49, 0x8c, 0xbd, 0xb6, 0xba, 0x66, 0xd8, // IID110 + 0xd5, 0xc5, 0x4a, 0x9d, 0x64, 0xdb, 0xb3, 0x9a, // IID111 + 0xd5, 0x93, 0x4b, 0x94, 0xd0, 0xb2, 0xbe, 0x96, 0x6c, // IID112 + 0x46, 0x0f, 0x4c, 0x8c, 0xc1, 0x92, 0x18, 0x3e, 0x57, // IID113 + 0xd5, 0xd7, 0x4d, 0xbc, 0xb2, 0xb1, 0x10, 0x71, 0x71, // IID114 + 0xd5, 0xd6, 0x4e, 0x84, 0xb3, 0xd7, 0xaa, 0x9f, 0x11, // IID115 + 0x47, 0x0f, 0x4f, 0xa4, 0x25, 0x05, 0x78, 0x53, 0x0d, // IID116 + 0x41, 0x0f, 0x90, 0xc2, // IID117 +#endif // _LP64 + 0x0f, 0x91, 0xc3, // IID118 +#ifdef _LP64 + 0x41, 0x0f, 0x92, 0xc5, // IID119 + 0xd5, 0x90, 0x93, 0xc7, // IID120 + 0xd5, 0x91, 0x94, 0xc0, // IID121 + 0x41, 0x0f, 0x95, 0xc7, // IID122 + 0xd5, 0x90, 0x96, 0xc5, // IID123 + 0xd5, 0x90, 0x97, 0xc1, // IID124 + 0x41, 0x0f, 0x98, 0xc2, // IID125 + 0xd5, 0x91, 0x99, 0xc0, // IID126 + 0xd5, 0x90, 0x9a, 0xc0, // IID127 + 0xd5, 0x91, 0x9b, 0xc4, // IID128 + 0x41, 0x0f, 0x9c, 0xc3, // IID129 + 0xd5, 0x91, 0x9d, 0xc1, // IID130 + 0xd5, 0x90, 0x9e, 0xc2, // IID131 + 0x41, 0x0f, 0x9f, 0xc6, // IID132 + 0xd5, 0x11, 0xf7, 0xf6, // IID133 + 0xd5, 0x10, 0xf7, 0xff, // IID134 + 0xd5, 0x11, 0xf7, 0xec, // IID135 + 0xd5, 0x11, 0xf7, 0xe7, // IID136 + 0xd5, 0x11, 0xf7, 0xdb, // IID137 + 0xd5, 0x10, 0xf7, 0xd0, // IID138 +#endif // _LP64 + 0xd3, 0xc2, // IID139 +#ifdef _LP64 + 0x41, 0xd3, 0xcc, // IID140 + 0x41, 0xd3, 0xfe, // IID141 + 0xd5, 0x10, 0xd3, 0xe3, // IID142 + 0x41, 0xd3, 0xe2, // IID143 + 0xd5, 0x10, 0xd3, 0xec, // IID144 +#endif // _LP64 + 0xff, 0xc3, // IID145 +#ifdef _LP64 + 0x41, 0xff, 0xce, // IID146 + 0x41, 0xf7, 0xa4, 0x24, 0xa2, 0x05, 0x5b, 0xa8, // IID147 + 0xf7, 0x9b, 0x39, 0x30, 0x4b, 0xc2, // IID148 + 0xd5, 0x10, 0xd3, 0xbd, 0xd0, 0x52, 0x8f, 0x81, // IID149 + 0xd5, 0x32, 0xd3, 0xa4, 0xe5, 0x37, 0x94, 0xba, 0xdc, // IID150 + 0x43, 0xd3, 0xac, 0x6b, 0xbc, 0x03, 0xff, 0xf1, // IID151 + 0xd5, 0x10, 0xff, 0x83, 0x96, 0x2a, 0x95, 0xa1, // IID152 + 0xd5, 0x20, 0xff, 0x8c, 0x21, 0x3c, 0x46, 0xcf, 0xda, // IID153 + 0xd5, 0x63, 0x69, 0x8c, 0x40, 0x26, 0xcf, 0xfe, 0x2e, 0x00, 0x00, 0x10, 0x00, // IID154 + 0x45, 0x69, 0xc8, 0x00, 0x00, 0x00, 0x10, // IID155 + 0x45, 0x0f, 0xa4, 0xfa, 0x08, // IID156 + 0xd5, 0xd1, 0xac, 0xf5, 0x02, // IID157 + 0xd5, 0x94, 0xb6, 0xb3, 0x7c, 0xca, 0x3c, 0xf9, // IID158 + 0xd5, 0xe7, 0xb7, 0x8c, 0x1c, 0x44, 0xfa, 0x05, 0x2d, // IID159 + 0xd5, 0x97, 0xbe, 0xa4, 0x3e, 0xc1, 0xca, 0xbc, 0x65, // IID160 + 0xd5, 0xe7, 0xbf, 0x94, 0x02, 0x59, 0x74, 0x70, 0x1d, // IID161 + 0xd5, 0xc1, 0xb6, 0xd0, // IID162 + 0xd5, 0xc5, 0xb7, 0xf9, // IID163 + 0xd5, 0x94, 0xbe, 0xfe, // IID164 + 0xd5, 0xd5, 0xbf, 0xc0, // IID165 + 0xd5, 0xe3, 0xb0, 0x94, 0x64, 0xa1, 0x59, 0xaa, 0xb7, // IID166 + 0x66, 0xd5, 0xc6, 0xb1, 0xa4, 0xf2, 0x58, 0xa5, 0xf5, 0x16, // IID167 + 0xd5, 0x90, 0xb1, 0x94, 0x52, 0x9c, 0x8d, 0x25, 0x50, // IID168 + 0x4c, 0x13, 0xcb, // IID169 + 0xd5, 0x5d, 0x3b, 0xd0, // IID170 + 0x4c, 0x0f, 0xaf, 0xf2, // IID171 + 0xf3, 0xd5, 0xdd, 0xb8, 0xce, // IID172 + 0xd5, 0x5c, 0x1b, 0xc3, // IID173 + 0x4d, 0x2b, 0xfb, // IID174 + 0xf3, 0xd5, 0xd8, 0xbc, 0xd5, // IID175 + 0xf3, 0xd5, 0x9d, 0xbd, 0xfb, // IID176 + 0xd5, 0x58, 0x03, 0xec, // IID177 + 0xd5, 0x1d, 0x23, 0xda, // IID178 + 0xd5, 0x4d, 0x0b, 0xef, // IID179 + 0xd5, 0x5c, 0x33, 0xc5, // IID180 + 0x4d, 0x8b, 0xf5, // IID181 + 0xd5, 0x9c, 0xbc, 0xde, // IID182 + 0xd5, 0x9c, 0xbd, 0xf7, // IID183 + 0xd5, 0x98, 0xa3, 0xce, // IID184 + 0xd5, 0x5d, 0x87, 0xcd, // IID185 + 0x4d, 0x85, 0xf8, // IID186 + 0xd5, 0x4b, 0x01, 0x84, 0xd6, 0xfe, 0x05, 0x19, 0xc9, // IID187 + 0xd5, 0x4a, 0x21, 0x94, 0xc3, 0x48, 0xde, 0x65, 0xd8, // IID188 + 0xd5, 0x1d, 0x39, 0xa8, 0xef, 0xc9, 0xc3, 0x62, // IID189 + 0xd5, 0x2d, 0x09, 0x9c, 0xb3, 0x78, 0xb3, 0x9f, 0x41, // IID190 + 0xd5, 0x1f, 0x31, 0xac, 0xb1, 0x23, 0xb6, 0x4b, 0xcd, // IID191 + 0xd5, 0x7b, 0x29, 0x9c, 0xfc, 0x61, 0xd3, 0xe1, 0x6c, // IID192 + 0xd5, 0x3f, 0x89, 0x9c, 0x89, 0x84, 0x89, 0x0a, 0xfc, // IID193 + 0xd5, 0xf8, 0xc1, 0xa4, 0xcb, 0x6c, 0xf0, 0xeb, 0x1f, // IID194 + 0xd5, 0x39, 0x81, 0xa4, 0x4a, 0xfb, 0xa0, 0x79, 0x94, 0x00, 0x00, 0x01, 0x00, // IID195 + 0xd5, 0x19, 0x81, 0x83, 0x79, 0xa2, 0x36, 0x91, 0x00, 0x00, 0x01, 0x00, // IID196 + 0xd5, 0x2a, 0x81, 0xbc, 0x93, 0x5c, 0x41, 0x15, 0xfe, 0x00, 0x00, 0x10, 0x00, // IID197 + 0xd5, 0x28, 0xc1, 0xbc, 0x1b, 0xe8, 0x3d, 0x3c, 0x3c, 0x08, // IID198 + 0xd5, 0x38, 0xc1, 0xa4, 0x7c, 0x6d, 0x9b, 0x51, 0x68, 0x08, // IID199 + 0xd5, 0x39, 0x83, 0x9c, 0x37, 0x7b, 0xe1, 0xc2, 0x84, 0x10, // IID200 + 0xd5, 0x29, 0xc1, 0xac, 0xd7, 0x24, 0xd8, 0xd9, 0x04, 0x04, // IID201 + 0xd5, 0x2a, 0x83, 0xac, 0xaa, 0x85, 0xea, 0x4a, 0x7e, 0x01, // IID202 + 0xd5, 0x1a, 0x81, 0xb4, 0x57, 0x20, 0xc6, 0x95, 0x28, 0x00, 0x00, 0x00, 0x01, // IID203 + 0x4b, 0x83, 0x8c, 0x2e, 0x65, 0xc6, 0xe4, 0x88, 0x01, // IID204 + 0xd5, 0x18, 0xc7, 0x86, 0xa6, 0x64, 0xba, 0x9c, 0x00, 0x01, 0x00, 0x00, // IID205 + 0x49, 0xf7, 0x85, 0x3b, 0x6e, 0x69, 0xf4, 0xff, 0xff, 0xff, 0xff, // IID206 + 0xd5, 0x49, 0x03, 0x8f, 0xf3, 0xb4, 0x49, 0xae, // IID207 + 0xd5, 0x18, 0x23, 0x8c, 0xc8, 0xac, 0xb4, 0x71, 0xe3, // IID208 + 0xd5, 0x58, 0x3b, 0xbc, 0xc9, 0xa0, 0xaa, 0x8f, 0xbb, // IID209 + 0xf3, 0xd5, 0xd8, 0xbd, 0x9b, 0x92, 0xe7, 0x7f, 0x48, // IID210 + 0xd5, 0x1c, 0x0b, 0x99, 0xd7, 0xbc, 0x21, 0x9a, // IID211 + 0xd5, 0x4d, 0x13, 0xa9, 0xfd, 0x23, 0x6d, 0x8f, // IID212 + 0xd5, 0xbf, 0xaf, 0x8c, 0xd2, 0x09, 0x78, 0x7d, 0xee, // IID213 + 0xf3, 0xd5, 0xe9, 0xb8, 0x9c, 0x5f, 0x6b, 0x10, 0xce, 0x91, // IID214 + 0xd5, 0x5c, 0x1b, 0xb7, 0xa2, 0xa3, 0xab, 0xb9, // IID215 + 0xd5, 0x79, 0x2b, 0xbc, 0xd7, 0xd8, 0x37, 0x3c, 0x66, // IID216 + 0xf3, 0xd5, 0xff, 0xbc, 0x84, 0xc8, 0x0f, 0x87, 0xa5, 0xb9, // IID217 + 0xd5, 0x2d, 0x33, 0xb4, 0x5f, 0xfa, 0xaf, 0x96, 0x41, // IID218 + 0xd5, 0x3b, 0x8b, 0x94, 0x69, 0x57, 0x61, 0x5a, 0x11, // IID219 + 0xd5, 0x7b, 0x8d, 0x9c, 0xbc, 0x33, 0xf9, 0x82, 0x6b, // IID220 + 0xf2, 0xd5, 0xb9, 0x2c, 0x8c, 0xe8, 0x15, 0x66, 0x23, 0xc6, // IID221 + 0xd5, 0x7e, 0x87, 0xac, 0xc1, 0x1d, 0xf0, 0x02, 0x59, // IID222 + 0xd5, 0x3f, 0x85, 0xa4, 0xa8, 0xfc, 0x5b, 0x86, 0x08, // IID223 + 0x49, 0x83, 0xc2, 0x10, // IID224 + 0xd5, 0x19, 0x81, 0xe2, 0x00, 0x01, 0x00, 0x00, // IID225 + 0x48, 0x83, 0xd1, 0x01, // IID226 + 0xd5, 0x18, 0x81, 0xfd, 0x00, 0x00, 0x01, 0x00, // IID227 + 0xd5, 0x19, 0xc1, 0xd4, 0x04, // IID228 + 0xd5, 0x19, 0xc1, 0xdc, 0x10, // IID229 + 0xd5, 0x18, 0xd1, 0xc2, // IID230 + 0xd5, 0x19, 0xc1, 0xca, 0x02, // IID231 + 0xd5, 0x18, 0xc1, 0xfb, 0x02, // IID232 + 0x49, 0xc1, 0xe6, 0x08, // IID233 + 0x49, 0x81, 0xda, 0x00, 0x00, 0x01, 0x00, // IID234 + 0xd5, 0x19, 0xd1, 0xe6, // IID235 + 0x49, 0xc1, 0xef, 0x08, // IID236 + 0xd5, 0x18, 0x81, 0xed, 0x00, 0x00, 0x10, 0x00, // IID237 + 0x48, 0x81, 0xf3, 0x00, 0x00, 0x00, 0x10, // IID238 + 0xd5, 0x18, 0xc7, 0xc3, 0x10, 0x00, 0x00, 0x00, // IID239 + 0xd5, 0x18, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, // IID240 + 0xd5, 0x98, 0xba, 0xe5, 0x01, // IID241 + 0x49, 0xf7, 0xc7, 0x00, 0x00, 0xff, 0xff, // IID242 + 0xd5, 0x18, 0x81, 0xcd, 0x00, 0x00, 0x00, 0x40, // IID243 + 0xd5, 0x18, 0x81, 0xeb, 0x00, 0x00, 0x01, 0x00, // IID244 + 0xd5, 0x9d, 0x40, 0xbd, 0x66, 0xde, 0x67, 0xa3, // IID245 + 0xd5, 0x98, 0x41, 0x8d, 0x81, 0xc5, 0x2c, 0x02, // IID246 + 0xd5, 0x9f, 0x42, 0xbc, 0xad, 0x47, 0x70, 0x69, 0xa1, // IID247 + 0xd5, 0xdd, 0x43, 0x90, 0x94, 0x68, 0x0c, 0x44, // IID248 + 0xd5, 0xfa, 0x44, 0x8c, 0xd7, 0x4e, 0x8b, 0x55, 0x23, // IID249 + 0xd5, 0xbe, 0x45, 0x8c, 0xe8, 0x37, 0x5c, 0x76, 0xed, // IID250 + 0x4d, 0x0f, 0x46, 0x83, 0x34, 0xcb, 0x1e, 0xb6, // IID251 + 0xd5, 0xed, 0x47, 0x94, 0x63, 0x86, 0xfa, 0x06, 0xc1, // IID252 + 0xd5, 0x9f, 0x48, 0x9c, 0xaa, 0x9f, 0x8f, 0xd1, 0x4b, // IID253 + 0x4f, 0x0f, 0x49, 0x84, 0xd9, 0x28, 0xa5, 0x42, 0x4b, // IID254 + 0xd5, 0x9e, 0x4a, 0xa4, 0x4b, 0x1c, 0x9a, 0x55, 0x68, // IID255 + 0xd5, 0xf8, 0x4b, 0xb4, 0x4a, 0x80, 0x8e, 0x4d, 0x2c, // IID256 + 0xd5, 0xfe, 0x4c, 0x94, 0x32, 0x92, 0x76, 0x17, 0xd5, // IID257 + 0xd5, 0xc9, 0x4d, 0xb3, 0x22, 0xa6, 0xef, 0x4f, // IID258 + 0xd5, 0xfe, 0x4e, 0xa4, 0x5a, 0x34, 0x8c, 0x7a, 0x6b, // IID259 + 0xd5, 0xf8, 0x4f, 0xa4, 0x27, 0x3b, 0xda, 0x18, 0xed, // IID260 + 0x41, 0xff, 0xd1, // IID261 + 0xd5, 0x18, 0xf7, 0xf6, // IID262 + 0xd5, 0x19, 0xf7, 0xfd, // IID263 + 0x48, 0xf7, 0xeb, // IID264 + 0xd5, 0x19, 0xf7, 0xe3, // IID265 + 0x48, 0xf7, 0xdb, // IID266 + 0xd5, 0x18, 0xf7, 0xd1, // IID267 + 0xd5, 0x19, 0xd3, 0xc1, // IID268 + 0x48, 0xd3, 0xcb, // IID269 + 0xd5, 0x18, 0xd3, 0xf9, // IID270 + 0xd5, 0x19, 0xd3, 0xe4, // IID271 + 0xd5, 0x19, 0xd3, 0xe4, // IID272 + 0xd5, 0x19, 0xd3, 0xee, // IID273 + 0xd5, 0x19, 0xff, 0xc3, // IID274 + 0x48, 0xff, 0xca, // IID275 + 0xd5, 0x19, 0x53, // IID276 + 0xd5, 0x09, 0x5a, // IID277 + 0xd5, 0x11, 0xff, 0x93, 0xfb, 0x78, 0x24, 0xdd, // IID278 + 0xd5, 0x39, 0xf7, 0xa4, 0x2b, 0x64, 0x00, 0xa6, 0xe0, // IID279 + 0xd5, 0x18, 0xf7, 0x9c, 0xcb, 0x12, 0xb8, 0x47, 0x7a, // IID280 + 0xd5, 0x38, 0xd3, 0xbc, 0x6a, 0xba, 0x85, 0x7a, 0xb7, // IID281 + 0xd5, 0x19, 0xd3, 0xa0, 0xd4, 0x25, 0xd4, 0x85, // IID282 + 0xd5, 0x19, 0xd3, 0xa8, 0x2f, 0xd9, 0xab, 0x01, // IID283 + 0x4b, 0xff, 0x84, 0xc9, 0x20, 0x25, 0xa9, 0x31, // IID284 + 0x4b, 0xff, 0x8c, 0x01, 0xbd, 0xb4, 0x14, 0x7f, // IID285 + 0xd5, 0x1f, 0x69, 0xb4, 0x7d, 0x9c, 0xcf, 0x81, 0x52, 0x00, 0x01, 0x00, 0x00, // IID286 + 0xd5, 0x59, 0x69, 0xc4, 0x00, 0x00, 0x10, 0x00, // IID287 + 0xd5, 0xdc, 0xa4, 0xc1, 0x02, // IID288 + 0xd5, 0x9c, 0xac, 0xd8, 0x02, // IID289 + 0x62, 0xd4, 0x24, 0x18, 0x8f, 0xc2, // IID290 + 0x62, 0xd4, 0xbc, 0x10, 0x8f, 0xc7, // IID291 + 0x62, 0xdc, 0x24, 0x18, 0xff, 0xf4, // IID292 + 0x62, 0xd4, 0x84, 0x10, 0xff, 0xf4, // IID293 + 0xd5, 0xfc, 0xb6, 0x84, 0x06, 0x37, 0xe8, 0x1b, 0x51, // IID294 + 0xd5, 0xaf, 0xb7, 0xbc, 0x97, 0x12, 0x6b, 0x78, 0xfc, // IID295 + 0xd5, 0xbd, 0xbe, 0xbc, 0xc1, 0xbf, 0xd8, 0xf6, 0x85, // IID296 + 0xd5, 0xb9, 0xbf, 0x94, 0x9c, 0x6a, 0xda, 0x79, 0x00, // IID297 + 0xd5, 0xcd, 0xb6, 0xd9, // IID298 + 0xd5, 0xdc, 0xb7, 0xcd, // IID299 + 0x4d, 0x0f, 0xbe, 0xf4, // IID300 + 0xd5, 0xc9, 0xbf, 0xfb, // IID301 + 0xd5, 0xcd, 0xb1, 0xb4, 0x24, 0x21, 0x8b, 0x56, 0x9a, // IID302 +#endif // _LP64 + }; + + static const unsigned int insns_lens[] = + { +#ifdef _LP64 + 4, // IID0 +#endif // _LP64 + 3, // IID1 +#ifdef _LP64 + 4, // IID2 + 4, // IID3 + 4, // IID4 + 5, // IID5 + 4, // IID6 + 4, // IID7 + 5, // IID8 + 5, // IID9 + 3, // IID10 + 4, // IID11 + 4, // IID12 + 4, // IID13 + 4, // IID14 + 4, // IID15 + 4, // IID16 + 4, // IID17 + 4, // IID18 + 9, // IID19 + 10, // IID20 + 9, // IID21 + 8, // IID22 + 9, // IID23 + 8, // IID24 + 9, // IID25 + 10, // IID26 + 9, // IID27 + 9, // IID28 + 9, // IID29 + 9, // IID30 + 8, // IID31 + 8, // IID32 + 9, // IID33 + 9, // IID34 + 8, // IID35 + 10, // IID36 + 9, // IID37 + 13, // IID38 + 9, // IID39 + 9, // IID40 + 11, // IID41 + 13, // IID42 + 10, // IID43 + 11, // IID44 + 13, // IID45 + 9, // IID46 + 10, // IID47 + 13, // IID48 + 10, // IID49 + 10, // IID50 + 10, // IID51 + 10, // IID52 + 9, // IID53 + 10, // IID54 + 12, // IID55 + 9, // IID56 + 12, // IID57 + 13, // IID58 + 9, // IID59 + 9, // IID60 + 7, // IID61 + 9, // IID62 + 10, // IID63 + 9, // IID64 + 9, // IID65 + 8, // IID66 + 9, // IID67 + 9, // IID68 + 8, // IID69 + 10, // IID70 + 9, // IID71 + 10, // IID72 + 9, // IID73 + 9, // IID74 + 9, // IID75 + 9, // IID76 + 9, // IID77 + 10, // IID78 + 9, // IID79 + 7, // IID80 + 5, // IID81 + 8, // IID82 +#endif // _LP64 + 6, // IID83 +#ifdef _LP64 + 8, // IID84 + 4, // IID85 + 8, // IID86 + 5, // IID87 + 5, // IID88 +#endif // _LP64 + 3, // IID89 + 2, // IID90 +#ifdef _LP64 + 5, // IID91 + 4, // IID92 + 5, // IID93 +#endif // _LP64 + 2, // IID94 +#ifdef _LP64 + 8, // IID95 + 8, // IID96 + 7, // IID97 + 5, // IID98 + 8, // IID99 + 8, // IID100 + 9, // IID101 + 9, // IID102 + 9, // IID103 + 9, // IID104 + 9, // IID105 + 9, // IID106 + 9, // IID107 + 9, // IID108 + 9, // IID109 + 9, // IID110 + 8, // IID111 + 9, // IID112 + 9, // IID113 + 9, // IID114 + 9, // IID115 + 9, // IID116 + 4, // IID117 +#endif // _LP64 + 3, // IID118 +#ifdef _LP64 + 4, // IID119 + 4, // IID120 + 4, // IID121 + 4, // IID122 + 4, // IID123 + 4, // IID124 + 4, // IID125 + 4, // IID126 + 4, // IID127 + 4, // IID128 + 4, // IID129 + 4, // IID130 + 4, // IID131 + 4, // IID132 + 4, // IID133 + 4, // IID134 + 4, // IID135 + 4, // IID136 + 4, // IID137 + 4, // IID138 +#endif // _LP64 + 2, // IID139 +#ifdef _LP64 + 3, // IID140 + 3, // IID141 + 4, // IID142 + 3, // IID143 + 4, // IID144 +#endif // _LP64 + 2, // IID145 +#ifdef _LP64 + 3, // IID146 + 8, // IID147 + 6, // IID148 + 8, // IID149 + 9, // IID150 + 8, // IID151 + 8, // IID152 + 9, // IID153 + 13, // IID154 + 7, // IID155 + 5, // IID156 + 5, // IID157 + 8, // IID158 + 9, // IID159 + 9, // IID160 + 9, // IID161 + 4, // IID162 + 4, // IID163 + 4, // IID164 + 4, // IID165 + 9, // IID166 + 10, // IID167 + 9, // IID168 + 3, // IID169 + 4, // IID170 + 4, // IID171 + 5, // IID172 + 4, // IID173 + 3, // IID174 + 5, // IID175 + 5, // IID176 + 4, // IID177 + 4, // IID178 + 4, // IID179 + 4, // IID180 + 3, // IID181 + 4, // IID182 + 4, // IID183 + 4, // IID184 + 4, // IID185 + 3, // IID186 + 9, // IID187 + 9, // IID188 + 8, // IID189 + 9, // IID190 + 9, // IID191 + 9, // IID192 + 9, // IID193 + 9, // IID194 + 13, // IID195 + 12, // IID196 + 13, // IID197 + 10, // IID198 + 10, // IID199 + 10, // IID200 + 10, // IID201 + 10, // IID202 + 13, // IID203 + 9, // IID204 + 12, // IID205 + 11, // IID206 + 8, // IID207 + 9, // IID208 + 9, // IID209 + 9, // IID210 + 8, // IID211 + 8, // IID212 + 9, // IID213 + 10, // IID214 + 8, // IID215 + 9, // IID216 + 10, // IID217 + 9, // IID218 + 9, // IID219 + 9, // IID220 + 10, // IID221 + 9, // IID222 + 9, // IID223 + 4, // IID224 + 8, // IID225 + 4, // IID226 + 8, // IID227 + 5, // IID228 + 5, // IID229 + 4, // IID230 + 5, // IID231 + 5, // IID232 + 4, // IID233 + 7, // IID234 + 4, // IID235 + 4, // IID236 + 8, // IID237 + 7, // IID238 + 8, // IID239 + 11, // IID240 + 5, // IID241 + 7, // IID242 + 8, // IID243 + 8, // IID244 + 8, // IID245 + 8, // IID246 + 9, // IID247 + 8, // IID248 + 9, // IID249 + 9, // IID250 + 8, // IID251 + 9, // IID252 + 9, // IID253 + 9, // IID254 + 9, // IID255 + 9, // IID256 + 9, // IID257 + 8, // IID258 + 9, // IID259 + 9, // IID260 + 3, // IID261 + 4, // IID262 + 4, // IID263 + 3, // IID264 + 4, // IID265 + 3, // IID266 + 4, // IID267 + 4, // IID268 + 3, // IID269 + 4, // IID270 + 4, // IID271 + 4, // IID272 + 4, // IID273 + 4, // IID274 + 3, // IID275 + 3, // IID276 + 3, // IID277 + 8, // IID278 + 9, // IID279 + 9, // IID280 + 9, // IID281 + 8, // IID282 + 8, // IID283 + 8, // IID284 + 8, // IID285 + 13, // IID286 + 8, // IID287 + 5, // IID288 + 5, // IID289 + 6, // IID290 + 6, // IID291 + 6, // IID292 + 6, // IID293 + 9, // IID294 + 9, // IID295 + 9, // IID296 + 9, // IID297 + 4, // IID298 + 4, // IID299 + 4, // IID300 + 4, // IID301 + 9, // IID302 +#endif // _LP64 + }; + + static const char* insns_strs[] = + { +#ifdef _LP64 + "__ shldl(r22, r14);", // IID0 +#endif // _LP64 + "__ shrdl(rcx, rbx);", // IID1 +#ifdef _LP64 + "__ adcl(r24, r18);", // IID2 + "__ cmpl(r8, r19);", // IID3 + "__ imull(r25, r19);", // IID4 + "__ popcntl(r19, r15);", // IID5 + "__ sbbl(r21, r19);", // IID6 + "__ subl(r17, r29);", // IID7 + "__ tzcntl(r21, rdx);", // IID8 + "__ lzcntl(rcx, r23);", // IID9 + "__ addl(r10, r11);", // IID10 + "__ andl(r21, r14);", // IID11 + "__ orl(r12, r30);", // IID12 + "__ xorl(r19, r30);", // IID13 + "__ movl(r27, r11);", // IID14 + "__ bsfl(r10, r12);", // IID15 + "__ bsrl(r16, r10);", // IID16 + "__ xchgl(r16, r28);", // IID17 + "__ testl(r25, r16);", // IID18 + "__ addb(Address(r27, rdx, (Address::ScaleFactor)1, +0x6f304723), rcx);", // IID19 + "__ addw(Address(r19, rcx, (Address::ScaleFactor)2, +0x17244c57), r17);", // IID20 + "__ addl(Address(r23, r16, (Address::ScaleFactor)1, +0x138df419), r19);", // IID21 + "__ adcl(Address(r8, r11, (Address::ScaleFactor)3, -0x164f7a73), rcx);", // IID22 + "__ andb(Address(rdx, r17, (Address::ScaleFactor)3, +0x4df7f181), r22);", // IID23 + "__ andl(Address(r15, -0x41884769), r23);", // IID24 + "__ cmpb(Address(r20, r18, (Address::ScaleFactor)0, -0x1b827588), r8);", // IID25 + "__ cmpw(Address(r9, r22, (Address::ScaleFactor)3, +0x564ead70), r31);", // IID26 + "__ cmpl(Address(r10, r24, (Address::ScaleFactor)2, +0xf08ffec), rcx);", // IID27 + "__ orb(Address(r27, r15, (Address::ScaleFactor)0, +0xf18eac7), r19);", // IID28 + "__ orl(Address(r16, r31, (Address::ScaleFactor)2, +0x3a452790), r12);", // IID29 + "__ xorb(Address(r20, r13, (Address::ScaleFactor)0, +0x61dde6b7), r10);", // IID30 + "__ xorl(Address(r27, -0x77a99463), rbx);", // IID31 + "__ subl(Address(r9, r11, (Address::ScaleFactor)0, +0x4e20f145), r10);", // IID32 + "__ movb(Address(r23, r23, (Address::ScaleFactor)0, -0x3f51b77), r10);", // IID33 + "__ movl(Address(r31, r22, (Address::ScaleFactor)0, +0xfac5466), r30);", // IID34 + "__ xaddb(Address(rbx, -0x70025991), r31);", // IID35 + "__ xaddw(Address(r17, r26, (Address::ScaleFactor)1, -0x530c0221), r29);", // IID36 + "__ xaddl(Address(r9, r21, (Address::ScaleFactor)0, -0x7b7336bf), r17);", // IID37 + "__ adcl(Address(r24, r12, (Address::ScaleFactor)2, +0x691b07e5), 65536);", // IID38 + "__ andl(Address(r14, r9, (Address::ScaleFactor)0, -0x115d5957), 16);", // IID39 + "__ addb(Address(r21, -0x1d3e83ad), 64);", // IID40 + "__ addw(Address(r12, +0x3a7acf9a), 4096);", // IID41 + "__ addl(Address(r30, r14, (Address::ScaleFactor)1, -0x2073ed16), 256);", // IID42 + "__ cmpb(Address(r28, r18, (Address::ScaleFactor)0, +0x6fd326d5), 16);", // IID43 + "__ cmpw(Address(r12, r14, (Address::ScaleFactor)1, +0x2ae6568f), 256);", // IID44 + "__ cmpl(Address(r24, r30, (Address::ScaleFactor)3, -0x11b9aeac), 1048576);", // IID45 + "__ sarl(Address(r22, r30, (Address::ScaleFactor)2, +0x60cb9115), 1);", // IID46 + "__ sall(Address(r31, r8, (Address::ScaleFactor)1, +0x236d8ab9), 16);", // IID47 + "__ sbbl(Address(r21, r12, (Address::ScaleFactor)1, -0x7d9b9f18), 16777216);", // IID48 + "__ shrl(Address(r29, r17, (Address::ScaleFactor)0, -0x7c54f216), 8);", // IID49 + "__ subl(Address(r8, r27, (Address::ScaleFactor)2, -0x1190e2c6), 16);", // IID50 + "__ xorl(Address(rdx, +0x50dd3396), 1048576);", // IID51 + "__ orb(Address(r20, -0x7dd1f614), 64);", // IID52 + "__ orl(Address(r18, +0x6f852a9f), 16);", // IID53 + "__ movb(Address(r20, r8, (Address::ScaleFactor)2, +0x436e2aa), 1);", // IID54 + "__ movl(Address(rcx, r14, (Address::ScaleFactor)1, +0x883df84), 16);", // IID55 + "__ testb(Address(r11, r10, (Address::ScaleFactor)1, -0x1fc2039b), 16);", // IID56 + "__ testl(Address(r29, +0x73b9f003), 67108864);", // IID57 + "__ cmpl_imm32(Address(r29, rcx, (Address::ScaleFactor)2, +0x4ca2b092), 4194304);", // IID58 + "__ addl(r8, Address(rdx, r24, (Address::ScaleFactor)2, -0x1e1524dc));", // IID59 + "__ andl(r19, Address(r20, r20, (Address::ScaleFactor)1, +0x6286892));", // IID60 + "__ cmpb(r11, Address(r13, -0x42e0bf9e));", // IID61 + "__ cmpl(r20, Address(rbx, r30, (Address::ScaleFactor)3, -0x30497735));", // IID62 + "__ lzcntl(r8, Address(rdx, r9, (Address::ScaleFactor)1, +0xe2e99e));", // IID63 + "__ orl(r9, Address(r29, r25, (Address::ScaleFactor)1, +0x50169f63));", // IID64 + "__ adcl(r17, Address(r31, r21, (Address::ScaleFactor)3, +0x79efd170));", // IID65 + "__ imull(r23, Address(r8, -0xa521f73));", // IID66 + "__ popcntl(r30, Address(r10, +0x44352901));", // IID67 + "__ sbbl(r16, Address(r18, r14, (Address::ScaleFactor)1, -0xda8278a));", // IID68 + "__ subl(r17, Address(r22, +0x2d63aab3));", // IID69 + "__ tzcntl(r23, Address(r21, r11, (Address::ScaleFactor)0, -0x18bc7469));", // IID70 + "__ xorb(r9, Address(r19, rdx, (Address::ScaleFactor)0, -0x5f6207ed));", // IID71 + "__ xorw(r11, Address(r21, r10, (Address::ScaleFactor)2, -0x63c79f2b));", // IID72 + "__ xorl(r29, Address(r31, rcx, (Address::ScaleFactor)3, +0x34d93c0f));", // IID73 + "__ movb(r17, Address(r8, r18, (Address::ScaleFactor)2, -0x38ff3ad7));", // IID74 + "__ movl(r31, Address(r20, r11, (Address::ScaleFactor)2, -0x1d23470c));", // IID75 + "__ leal(r31, Address(rbx, r12, (Address::ScaleFactor)2, -0x3b4a4215));", // IID76 + "__ xchgb(r20, Address(r30, r24, (Address::ScaleFactor)0, -0x5c4e82bc));", // IID77 + "__ xchgw(r13, Address(r10, r21, (Address::ScaleFactor)3, +0x19bd4a03));", // IID78 + "__ xchgl(r23, Address(r16, r13, (Address::ScaleFactor)2, -0x6a0293d6));", // IID79 + "__ testl(r13, Address(r9, +0x34a6ff61));", // IID80 + "__ addb(r23, 4);", // IID81 + "__ addl(r28, 65536);", // IID82 +#endif // _LP64 + "__ andl(rdx, 65536);", // IID83 +#ifdef _LP64 + "__ adcl(r27, 1048576);", // IID84 + "__ cmpb(r13, 4);", // IID85 + "__ cmpl(r29, 268435456);", // IID86 + "__ rcll(r20, 16);", // IID87 + "__ roll(r25, 2);", // IID88 +#endif // _LP64 + "__ rorl(rdx, 4);", // IID89 + "__ sarl(rcx, 1);", // IID90 +#ifdef _LP64 + "__ sall(r19, 16);", // IID91 + "__ sbbl(r9, 1);", // IID92 + "__ shll(r20, 8);", // IID93 +#endif // _LP64 + "__ shrl(rcx, 1);", // IID94 +#ifdef _LP64 + "__ subl(r19, 16777216);", // IID95 + "__ xorl(r16, 4096);", // IID96 + "__ movl(r24, 65536);", // IID97 + "__ testb(r20, 64);", // IID98 + "__ testl(r28, 16777216);", // IID99 + "__ subl_imm32(r29, 262144);", // IID100 + "__ cmovl(Assembler::Condition::overflow, r8, Address(r26, r28, (Address::ScaleFactor)1, +0x210f06d));", // IID101 + "__ cmovl(Assembler::Condition::noOverflow, rbx, Address(r18, rbx, (Address::ScaleFactor)0, -0x264fce2a));", // IID102 + "__ cmovl(Assembler::Condition::below, r29, Address(r17, r24, (Address::ScaleFactor)0, +0x46c06acb));", // IID103 + "__ cmovl(Assembler::Condition::aboveEqual, r17, Address(r25, r11, (Address::ScaleFactor)3, -0x3b21f455));", // IID104 + "__ cmovl(Assembler::Condition::zero, r23, Address(r20, r31, (Address::ScaleFactor)0, -0x5a03317b));", // IID105 + "__ cmovl(Assembler::Condition::notZero, r31, Address(r31, r15, (Address::ScaleFactor)2, -0x53fc2e65));", // IID106 + "__ cmovl(Assembler::Condition::belowEqual, r28, Address(rdx, rcx, (Address::ScaleFactor)3, -0x3bc9229f));", // IID107 + "__ cmovl(Assembler::Condition::above, r31, Address(rdx, r19, (Address::ScaleFactor)3, +0x7bf1761c));", // IID108 + "__ cmovl(Assembler::Condition::negative, rdx, Address(r17, r18, (Address::ScaleFactor)0, -0x1da2fc03));", // IID109 + "__ cmovl(Assembler::Condition::positive, r9, Address(r21, r23, (Address::ScaleFactor)2, -0x2799454a));", // IID110 + "__ cmovl(Assembler::Condition::parity, r27, Address(r13, -0x654c249c));", // IID111 + "__ cmovl(Assembler::Condition::noParity, rdx, Address(r24, r10, (Address::ScaleFactor)3, +0x6c96beb2));", // IID112 + "__ cmovl(Assembler::Condition::less, r9, Address(rcx, r8, (Address::ScaleFactor)3, +0x573e1892));", // IID113 + "__ cmovl(Assembler::Condition::greaterEqual, r31, Address(r26, r14, (Address::ScaleFactor)2, +0x717110b1));", // IID114 + "__ cmovl(Assembler::Condition::lessEqual, r24, Address(r19, r14, (Address::ScaleFactor)2, +0x119faad7));", // IID115 + "__ cmovl(Assembler::Condition::greater, r12, Address(r13, r12, (Address::ScaleFactor)0, +0xd537805));", // IID116 + "__ setb(Assembler::Condition::overflow, r10);", // IID117 +#endif // _LP64 + "__ setb(Assembler::Condition::noOverflow, rbx);", // IID118 +#ifdef _LP64 + "__ setb(Assembler::Condition::below, r13);", // IID119 + "__ setb(Assembler::Condition::aboveEqual, r23);", // IID120 + "__ setb(Assembler::Condition::zero, r24);", // IID121 + "__ setb(Assembler::Condition::notZero, r15);", // IID122 + "__ setb(Assembler::Condition::belowEqual, r21);", // IID123 + "__ setb(Assembler::Condition::above, r17);", // IID124 + "__ setb(Assembler::Condition::negative, r10);", // IID125 + "__ setb(Assembler::Condition::positive, r24);", // IID126 + "__ setb(Assembler::Condition::parity, r16);", // IID127 + "__ setb(Assembler::Condition::noParity, r28);", // IID128 + "__ setb(Assembler::Condition::less, r11);", // IID129 + "__ setb(Assembler::Condition::greaterEqual, r25);", // IID130 + "__ setb(Assembler::Condition::lessEqual, r18);", // IID131 + "__ setb(Assembler::Condition::greater, r14);", // IID132 + "__ divl(r30);", // IID133 + "__ idivl(r23);", // IID134 + "__ imull(r28);", // IID135 + "__ mull(r31);", // IID136 + "__ negl(r27);", // IID137 + "__ notl(r16);", // IID138 +#endif // _LP64 + "__ roll(rdx);", // IID139 +#ifdef _LP64 + "__ rorl(r12);", // IID140 + "__ sarl(r14);", // IID141 + "__ sall(r19);", // IID142 + "__ shll(r10);", // IID143 + "__ shrl(r20);", // IID144 +#endif // _LP64 + "__ incrementl(rbx);", // IID145 +#ifdef _LP64 + "__ decrementl(r14);", // IID146 + "__ mull(Address(r12, -0x57a4fa5e));", // IID147 + "__ negl(Address(rbx, -0x3db4cfc7));", // IID148 + "__ sarl(Address(r21, -0x7e70ad30));", // IID149 + "__ sall(Address(r21, r28, (Address::ScaleFactor)3, -0x23456bc9));", // IID150 + "__ shrl(Address(r11, r13, (Address::ScaleFactor)1, -0xe00fc44));", // IID151 + "__ incrementl(Address(r19, -0x5e6ad56a));", // IID152 + "__ decrementl(Address(rcx, r20, (Address::ScaleFactor)0, -0x2530b9c4));", // IID153 + "__ imull(r17, Address(r8, r24, (Address::ScaleFactor)1, +0x2efecf26), 1048576);", // IID154 + "__ imull(r9, r8, 268435456);", // IID155 + "__ shldl(r10, r15, 8);", // IID156 + "__ shrdl(r29, r22, 2);", // IID157 + "__ movzbl(r14, Address(r19, -0x6c33584));", // IID158 + "__ movzwl(r25, Address(r12, r27, (Address::ScaleFactor)0, +0x2d05fa44));", // IID159 + "__ movsbl(r12, Address(r30, r15, (Address::ScaleFactor)0, +0x65bccac1));", // IID160 + "__ movswl(r26, Address(r10, r24, (Address::ScaleFactor)0, +0x1d707459));", // IID161 + "__ movzbl(r18, r8);", // IID162 + "__ movzwl(r31, r9);", // IID163 + "__ movsbl(r15, r22);", // IID164 + "__ movswl(r24, r24);", // IID165 + "__ cmpxchgb(r18, Address(r12, r28, (Address::ScaleFactor)1, -0x4855a65f));", // IID166 + "__ cmpxchgw(r28, Address(rdx, r14, (Address::ScaleFactor)3, +0x16f5a558));", // IID167 + "__ cmpxchgl(rdx, Address(r18, rdx, (Address::ScaleFactor)1, +0x50258d9c));", // IID168 + "__ adcq(r9, rbx);", // IID169 + "__ cmpq(r26, r24);", // IID170 + "__ imulq(r14, rdx);", // IID171 + "__ popcntq(r25, r30);", // IID172 + "__ sbbq(r24, r19);", // IID173 + "__ subq(r15, r11);", // IID174 + "__ tzcntq(r18, r21);", // IID175 + "__ lzcntq(r15, r27);", // IID176 + "__ addq(r21, r20);", // IID177 + "__ andq(r11, r26);", // IID178 + "__ orq(r29, r15);", // IID179 + "__ xorq(r24, r21);", // IID180 + "__ movq(r14, r13);", // IID181 + "__ bsfq(r11, r22);", // IID182 + "__ bsrq(r14, r23);", // IID183 + "__ btq(r22, rcx);", // IID184 + "__ xchgq(r25, r29);", // IID185 + "__ testq(r15, r8);", // IID186 + "__ addq(Address(r14, r10, (Address::ScaleFactor)3, -0x36e6fa02), r16);", // IID187 + "__ andq(Address(rbx, r8, (Address::ScaleFactor)3, -0x279a21b8), r18);", // IID188 + "__ cmpq(Address(r24, +0x62c3c9ef), r13);", // IID189 + "__ orq(Address(r11, r22, (Address::ScaleFactor)2, +0x419fb378), r11);", // IID190 + "__ xorq(Address(r25, r14, (Address::ScaleFactor)2, -0x32b449dd), r13);", // IID191 + "__ subq(Address(r28, r31, (Address::ScaleFactor)3, +0x6ce1d361), r19);", // IID192 + "__ movq(Address(r25, r25, (Address::ScaleFactor)2, -0x3f5767c), r11);", // IID193 + "__ xaddq(Address(r19, r17, (Address::ScaleFactor)3, +0x1febf06c), r20);", // IID194 + "__ andq(Address(r26, r17, (Address::ScaleFactor)1, -0x6b865f05), 65536);", // IID195 + "__ addq(Address(r27, -0x6ec95d87), 65536);", // IID196 + "__ cmpq(Address(rbx, r26, (Address::ScaleFactor)2, -0x1eabea4), 1048576);", // IID197 + "__ sarq(Address(rbx, r19, (Address::ScaleFactor)0, +0x3c3c3de8), 8);", // IID198 + "__ salq(Address(r20, r23, (Address::ScaleFactor)1, +0x68519b6d), 8);", // IID199 + "__ sbbq(Address(r31, r22, (Address::ScaleFactor)0, -0x7b3d1e85), 16);", // IID200 + "__ shrq(Address(r15, r18, (Address::ScaleFactor)3, +0x4d9d824), 4);", // IID201 + "__ subq(Address(rdx, r29, (Address::ScaleFactor)2, +0x7e4aea85), 1);", // IID202 + "__ xorq(Address(r23, r10, (Address::ScaleFactor)1, +0x2895c620), 16777216);", // IID203 + "__ orq(Address(r14, r13, (Address::ScaleFactor)0, -0x771b399b), 1);", // IID204 + "__ movq(Address(r22, -0x63459b5a), 256);", // IID205 + "__ testq(Address(r13, -0xb9691c5), -1);", // IID206 + "__ addq(r17, Address(r15, -0x51b64b0d));", // IID207 + "__ andq(rcx, Address(r16, rcx, (Address::ScaleFactor)3, -0x1c8e4b54));", // IID208 + "__ cmpq(r23, Address(r17, rcx, (Address::ScaleFactor)3, -0x44705560));", // IID209 + "__ lzcntq(r19, Address(r19, +0x487fe792));", // IID210 + "__ orq(r11, Address(r17, -0x65de4329));", // IID211 + "__ adcq(r29, Address(r9, -0x7092dc03));", // IID212 + "__ imulq(r9, Address(r26, r26, (Address::ScaleFactor)3, -0x118287f7));", // IID213 + "__ popcntq(r19, Address(r15, r19, (Address::ScaleFactor)1, -0x6e31ef95));", // IID214 + "__ sbbq(r30, Address(r23, -0x46545c5e));", // IID215 + "__ subq(r23, Address(r31, r18, (Address::ScaleFactor)3, +0x663c37d8));", // IID216 + "__ tzcntq(r24, Address(r24, r25, (Address::ScaleFactor)3, -0x465a78f1));", // IID217 + "__ xorq(r14, Address(r15, r19, (Address::ScaleFactor)1, +0x4196affa));", // IID218 + "__ movq(rdx, Address(r25, r29, (Address::ScaleFactor)1, +0x115a6157));", // IID219 + "__ leaq(r19, Address(r28, r31, (Address::ScaleFactor)2, +0x6b82f933));", // IID220 + "__ cvttsd2siq(rcx, Address(r24, r21, (Address::ScaleFactor)3, -0x39dc99eb));", // IID221 + "__ xchgq(r29, Address(r17, r24, (Address::ScaleFactor)3, +0x5902f01d));", // IID222 + "__ testq(r12, Address(r24, r29, (Address::ScaleFactor)2, +0x8865bfc));", // IID223 + "__ addq(r10, 16);", // IID224 + "__ andq(r26, 256);", // IID225 + "__ adcq(rcx, 1);", // IID226 + "__ cmpq(r21, 65536);", // IID227 + "__ rclq(r28, 4);", // IID228 + "__ rcrq(r28, 16);", // IID229 + "__ rolq(r18, 1);", // IID230 + "__ rorq(r26, 2);", // IID231 + "__ sarq(r19, 2);", // IID232 + "__ salq(r14, 8);", // IID233 + "__ sbbq(r10, 65536);", // IID234 + "__ shlq(r30, 1);", // IID235 + "__ shrq(r15, 8);", // IID236 + "__ subq(r21, 1048576);", // IID237 + "__ xorq(rbx, 268435456);", // IID238 + "__ movq(r19, 16);", // IID239 + "__ mov64(r19, 17179869184);", // IID240 + "__ btq(r21, 1);", // IID241 + "__ testq(r15, -65536);", // IID242 + "__ orq_imm32(r21, 1073741824);", // IID243 + "__ subq_imm32(r19, 65536);", // IID244 + "__ cmovq(Assembler::Condition::overflow, r15, Address(r29, -0x5c98219a));", // IID245 + "__ cmovq(Assembler::Condition::noOverflow, rcx, Address(r21, +0x22cc581));", // IID246 + "__ cmovq(Assembler::Condition::below, r15, Address(r29, r13, (Address::ScaleFactor)2, -0x5e968fb9));", // IID247 + "__ cmovq(Assembler::Condition::aboveEqual, r26, Address(r24, +0x440c6894));", // IID248 + "__ cmovq(Assembler::Condition::zero, r17, Address(r23, r26, (Address::ScaleFactor)3, +0x23558b4e));", // IID249 + "__ cmovq(Assembler::Condition::notZero, r9, Address(r16, r29, (Address::ScaleFactor)3, -0x1289a3c9));", // IID250 + "__ cmovq(Assembler::Condition::belowEqual, r8, Address(r11, -0x49e134cc));", // IID251 + "__ cmovq(Assembler::Condition::above, r26, Address(r11, r20, (Address::ScaleFactor)1, -0x3ef9057a));", // IID252 + "__ cmovq(Assembler::Condition::negative, r11, Address(r26, r13, (Address::ScaleFactor)2, +0x4bd18f9f));", // IID253 + "__ cmovq(Assembler::Condition::positive, r8, Address(r9, r11, (Address::ScaleFactor)3, +0x4b42a528));", // IID254 + "__ cmovq(Assembler::Condition::parity, r12, Address(r19, r9, (Address::ScaleFactor)1, +0x68559a1c));", // IID255 + "__ cmovq(Assembler::Condition::noParity, r22, Address(r18, r17, (Address::ScaleFactor)1, +0x2c4d8e80));", // IID256 + "__ cmovq(Assembler::Condition::less, r26, Address(r18, r30, (Address::ScaleFactor)0, -0x2ae8896e));", // IID257 + "__ cmovq(Assembler::Condition::greaterEqual, r22, Address(r11, +0x4fefa622));", // IID258 + "__ cmovq(Assembler::Condition::lessEqual, r28, Address(r18, r27, (Address::ScaleFactor)1, +0x6b7a8c34));", // IID259 + "__ cmovq(Assembler::Condition::greater, r20, Address(r23, r20, (Address::ScaleFactor)0, -0x12e725c5));", // IID260 + "__ call(r9);", // IID261 + "__ divq(r22);", // IID262 + "__ idivq(r29);", // IID263 + "__ imulq(rbx);", // IID264 + "__ mulq(r27);", // IID265 + "__ negq(rbx);", // IID266 + "__ notq(r17);", // IID267 + "__ rolq(r25);", // IID268 + "__ rorq(rbx);", // IID269 + "__ sarq(r17);", // IID270 + "__ salq(r28);", // IID271 + "__ shlq(r28);", // IID272 + "__ shrq(r30);", // IID273 + "__ incrementq(r27);", // IID274 + "__ decrementq(rdx);", // IID275 + "__ pushp(r27);", // IID276 + "__ popp(r10);", // IID277 + "__ call(Address(r27, -0x22db8705));", // IID278 + "__ mulq(Address(r27, r21, (Address::ScaleFactor)0, -0x1f59ff9c));", // IID279 + "__ negq(Address(r19, rcx, (Address::ScaleFactor)3, +0x7a47b812));", // IID280 + "__ sarq(Address(r18, r21, (Address::ScaleFactor)1, -0x48857a46));", // IID281 + "__ salq(Address(r24, -0x7a2bda2c));", // IID282 + "__ shrq(Address(r24, +0x1abd92f));", // IID283 + "__ incrementq(Address(r9, r9, (Address::ScaleFactor)3, +0x31a92520));", // IID284 + "__ decrementq(Address(r9, r8, (Address::ScaleFactor)0, +0x7f14b4bd));", // IID285 + "__ imulq(r14, Address(r29, r15, (Address::ScaleFactor)1, +0x5281cf9c), 256);", // IID286 + "__ imulq(r16, r28, 1048576);", // IID287 + "__ shldq(r17, r24, 2);", // IID288 + "__ shrdq(r16, r11, 2);", // IID289 + "__ pop2(r10, r11);", // IID290 + "__ pop2p(r15, r24);", // IID291 + "__ push2(r28, r11);", // IID292 + "__ push2p(r12, r31);", // IID293 + "__ movzbq(r24, Address(r22, r16, (Address::ScaleFactor)0, +0x511be837));", // IID294 + "__ movzwq(r15, Address(r15, r26, (Address::ScaleFactor)2, -0x38794ee));", // IID295 + "__ movsbq(r15, Address(r25, r16, (Address::ScaleFactor)3, -0x7a092741));", // IID296 + "__ movswq(rdx, Address(r28, r19, (Address::ScaleFactor)2, +0x79da6a));", // IID297 + "__ movzbq(r27, r9);", // IID298 + "__ movzwq(r25, r21);", // IID299 + "__ movsbq(r14, r12);", // IID300 + "__ movswq(r23, r11);", // IID301 + "__ cmpxchgq(r30, Address(r12, -0x65a974df));", // IID302 +#endif // _LP64 + }; +// END Generated code -- do not edit diff --git a/test/hotspot/gtest/x86/test_assemblerx86.cpp b/test/hotspot/gtest/x86/test_assemblerx86.cpp new file mode 100644 index 0000000000000..30ecd87793c80 --- /dev/null +++ b/test/hotspot/gtest/x86/test_assemblerx86.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" + +#if defined(X86) && !defined(ZERO) + +#include "utilities/vmassert_uninstall.hpp" +#include +#include "utilities/vmassert_reinstall.hpp" + +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "asm/macroAssembler.hpp" +#include "memory/resourceArea.hpp" + +#include "unittest.hpp" + +#define __ _masm. + +static void asm_check(const uint8_t *insns, const uint8_t *insns1, const unsigned int *insns_lens, const char *insns_strs[], size_t len) { + ResourceMark rm; + size_t cur_idx = 0; + for (size_t i = 0; i < len; i++) { + size_t insn_len = insns_lens[i]; + const char *insn = insns_strs[i]; + std::string insn_str(insn); + std::string insns_name = insn_str.substr(3, insn_str.find('(') - 3); + + if (std::memcmp(&insns[cur_idx], &insns1[cur_idx], insn_len) != 0) { + stringStream ss; + ss.print("%s\n", insn); + ss.print("Ours: "); + for (size_t j = 0; j < insn_len; j++) { + ss.print("%02x ", (uint8_t)insns[cur_idx + j]); + } + ss.print_cr(""); + ss.print("Theirs: "); + for (size_t j = 0; j < insn_len; j++) { + ss.print("%02x ", (uint8_t)insns1[cur_idx + j]); + } + ADD_FAILURE() << ss.as_string(); + } + cur_idx += insn_len; + } +} + +TEST_VM(AssemblerX86, validate) { + FlagSetting flag_change_apx(UseAPX, true); + VM_Version::set_bmi_cpuFeatures(); + VM_Version::set_evex_cpuFeatures(); + VM_Version::set_avx_cpuFeatures(); + VM_Version::set_apx_cpuFeatures(); + BufferBlob* b = BufferBlob::create("x64Test", 500000); + CodeBuffer code(b); + MacroAssembler _masm(&code); + address entry = __ pc(); + + // To build asmtest.out.h, ensure you have binutils version 2.34 or higher, then run: + // python3 x86-asmtest.py | expand > asmtest.out.h to generate tests with random inputs + // python3 x86-asmtest.py --full | expand > asmtest.out.h to generate tests with all possible inputs +#include "asmtest.out.h" + + asm_check((const uint8_t *)entry, (const uint8_t *)insns, insns_lens, insns_strs, sizeof(insns_lens) / sizeof(insns_lens[0])); + BufferBlob::free(b); +} + +#endif // X86 \ No newline at end of file diff --git a/test/hotspot/gtest/x86/x86-asmtest.py b/test/hotspot/gtest/x86/x86-asmtest.py new file mode 100644 index 0000000000000..c09fa80138d39 --- /dev/null +++ b/test/hotspot/gtest/x86/x86-asmtest.py @@ -0,0 +1,934 @@ +# 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 os +import sys +import platform +import random +import re +import subprocess + +OBJDUMP = "objdump" +X86_AS = "as" +X86_OBJCOPY = "objcopy" + +cond_to_suffix = { + 'overflow': 'o', + 'noOverflow': 'no', + 'below': 'b', + 'aboveEqual': 'ae', + 'zero': 'z', + 'notZero': 'nz', + 'belowEqual': 'be', + 'above': 'a', + 'negative': 's', + 'positive': 'ns', + 'parity': 'p', + 'noParity': 'np', + 'less': 'l', + 'greaterEqual': 'ge', + 'lessEqual': 'le', + 'greater': 'g', +} + +shift_rot_ops = {'sarl', 'sarq', 'sall', 'salq', 'shll', 'shlq', 'shrl', 'shrq', 'shrdl', 'shrdq', 'shldl', 'shldq', 'rcrq', 'rorl', 'rorq', 'roll', 'rolq', 'rcll', 'rclq'} + +registers_mapping = { + # skip rax, rsi, rdi, rsp, rbp as they have special encodings + # 'rax': {64: 'rax', 32: 'eax', 16: 'ax', 8: 'al'}, + 'rcx': {64: 'rcx', 32: 'ecx', 16: 'cx', 8: 'cl'}, + 'rdx': {64: 'rdx', 32: 'edx', 16: 'dx', 8: 'dl'}, + 'rbx': {64: 'rbx', 32: 'ebx', 16: 'bx', 8: 'bl'}, + # 'rsp': {64: 'rsp', 32: 'esp', 16: 'sp', 8: 'spl'}, + # 'rbp': {64: 'rbp', 32: 'ebp', 16: 'bp', 8: 'bpl'}, + # 'rsi': {64: 'rsi', 32: 'esi', 16: 'si', 8: 'sil'}, + # 'rdi': {64: 'rdi', 32: 'edi', 16: 'di', 8: 'dil'}, + 'r8': {64: 'r8', 32: 'r8d', 16: 'r8w', 8: 'r8b'}, + 'r9': {64: 'r9', 32: 'r9d', 16: 'r9w', 8: 'r9b'}, + 'r10': {64: 'r10', 32: 'r10d', 16: 'r10w', 8: 'r10b'}, + 'r11': {64: 'r11', 32: 'r11d', 16: 'r11w', 8: 'r11b'}, + 'r12': {64: 'r12', 32: 'r12d', 16: 'r12w', 8: 'r12b'}, + 'r13': {64: 'r13', 32: 'r13d', 16: 'r13w', 8: 'r13b'}, + 'r14': {64: 'r14', 32: 'r14d', 16: 'r14w', 8: 'r14b'}, + 'r15': {64: 'r15', 32: 'r15d', 16: 'r15w', 8: 'r15b'}, + 'r16': {64: 'r16', 32: 'r16d', 16: 'r16w', 8: 'r16b'}, + 'r17': {64: 'r17', 32: 'r17d', 16: 'r17w', 8: 'r17b'}, + 'r18': {64: 'r18', 32: 'r18d', 16: 'r18w', 8: 'r18b'}, + 'r19': {64: 'r19', 32: 'r19d', 16: 'r19w', 8: 'r19b'}, + 'r20': {64: 'r20', 32: 'r20d', 16: 'r20w', 8: 'r20b'}, + 'r21': {64: 'r21', 32: 'r21d', 16: 'r21w', 8: 'r21b'}, + 'r22': {64: 'r22', 32: 'r22d', 16: 'r22w', 8: 'r22b'}, + 'r23': {64: 'r23', 32: 'r23d', 16: 'r23w', 8: 'r23b'}, + 'r24': {64: 'r24', 32: 'r24d', 16: 'r24w', 8: 'r24b'}, + 'r25': {64: 'r25', 32: 'r25d', 16: 'r25w', 8: 'r25b'}, + 'r26': {64: 'r26', 32: 'r26d', 16: 'r26w', 8: 'r26b'}, + 'r27': {64: 'r27', 32: 'r27d', 16: 'r27w', 8: 'r27b'}, + 'r28': {64: 'r28', 32: 'r28d', 16: 'r28w', 8: 'r28b'}, + 'r29': {64: 'r29', 32: 'r29d', 16: 'r29w', 8: 'r29b'}, + 'r30': {64: 'r30', 32: 'r30d', 16: 'r30w', 8: 'r30b'}, + 'r31': {64: 'r31', 32: 'r31d', 16: 'r31w', 8: 'r31b'}, +} + +class Operand(object): + def generate(self): + return self + +class Register(Operand): + def generate(self, reg, width): + self.reg = reg + self.areg = registers_mapping.get(reg, {}).get(width, reg) + return self + + def cstr(self): + return self.reg + + def astr(self): + return self.areg + +class Immediate(Operand): + def generate(self, value): + self._value = value + return self + + def cstr(self): + return str(self._value) + + def astr(self): + return str(self._value) + +class Address(Operand): + width_to_ptr = { + 8: "byte ptr", + 16: "word ptr", + 32: "dword ptr", + 64: "qword ptr" + } + + def generate(self, base, index, width): + self.base = Register().generate(base, 64) + self.index = Register().generate(index, 64) + self._width = width + self._scale_factor = random.choice([-1, 0, 1, 2, 3]) + self._disp = random.randint(-2**31, 2**31 - 1) + return self + + def cstr(self): + disp_str = "{0:+#x}".format(self._disp) + if self._scale_factor == -1: + return f"Address({self.base.cstr()}, {disp_str})" + else: + return f"Address({self.base.cstr()}, {self.index.cstr()}, (Address::ScaleFactor){self._scale_factor}, {disp_str})" + + def astr(self): + ptr_str = self.width_to_ptr.get(self._width, "qword ptr") + disp_str = "{0:+#x}".format(self._disp) + if self._scale_factor == -1: + return f"{ptr_str} [{self.base.cstr() + disp_str}]" + else: + return f"{ptr_str} [{self.base.cstr()}+{self.index.cstr()}*{2 ** self._scale_factor}{disp_str}]" + +class Instruction(object): + def __init__(self, name, aname): + self._name = name + self._aname = aname + + def generate_operands(self, *operands): + self.operands = [operand for operand in operands] + + def cstr(self): + return f'__ {self._name}(' + ', '.join([op.cstr() for op in self.operands]) + ');' + + def astr(self): + # JDK assembler uses 'cl' for shift instructions with one operand by default + cl_str = (', cl' if self._name in shift_rot_ops and len(self.operands) == 1 else '') + return f'{self._aname} ' + ', '.join([op.astr() for op in self.operands]) + cl_str + +class RegInstruction(Instruction): + def __init__(self, name, aname, width, reg): + super().__init__(name, aname) + self.reg = Register().generate(reg, width) + self.generate_operands(self.reg) + +class MemInstruction(Instruction): + def __init__(self, name, aname, width, mem_base, mem_idx): + super().__init__(name, aname) + self.mem = Address().generate(mem_base, mem_idx, width) + self.generate_operands(self.mem) + +class TwoRegInstruction(Instruction): + def __init__(self, name, aname, width, reg1, reg2): + super().__init__(name, aname) + self.reg1 = Register().generate(reg1, width) + self.reg2 = Register().generate(reg2, width) + self.generate_operands(self.reg1, self.reg2) + + def astr(self): + return f'{{load}}' + super().astr() + +class MemRegInstruction(Instruction): + def __init__(self, name, aname, width, reg, mem_base, mem_idx): + super().__init__(name, aname) + self.mem = Address().generate(mem_base, mem_idx, width) + self.reg = Register().generate(reg, width) + self.generate_operands(self.mem, self.reg) + +class RegMemInstruction(Instruction): + def __init__(self, name, aname, width, reg, mem_base, mem_idx): + super().__init__(name, aname) + self.reg = Register().generate(reg, width) + self.mem = Address().generate(mem_base, mem_idx, width) + self.generate_operands(self.reg, self.mem) + +class RegImmInstruction(Instruction): + def __init__(self, name, aname, width, reg, imm): + super().__init__(name, aname) + self.reg = Register().generate(reg, width) + self.imm = Immediate().generate(imm) + self.generate_operands(self.reg, self.imm) + +class MemImmInstruction(Instruction): + def __init__(self, name, aname, width, imm, mem_base, mem_idx): + super().__init__(name, aname) + self.mem = Address().generate(mem_base, mem_idx, width) + self.imm = Immediate().generate(imm) + self.generate_operands(self.mem, self.imm) + +class RegRegImmInstruction(Instruction): + def __init__(self, name, aname, width, reg1, reg2, imm): + super().__init__(name, aname) + self.reg1 = Register().generate(reg1, width) + self.reg2 = Register().generate(reg2, width) + self.imm = Immediate().generate(imm) + self.generate_operands(self.reg1, self.reg2, self.imm) + +class RegMemImmInstruction(Instruction): + def __init__(self, name, aname, width, reg, imm, mem_base, mem_idx): + super().__init__(name, aname) + self.reg = Register().generate(reg, width) + self.mem = Address().generate(mem_base, mem_idx, width) + self.imm = Immediate().generate(imm) + self.generate_operands(self.reg, self.mem, self.imm) + +class Pop2Instruction(TwoRegInstruction): + def __init__(self, name, aname, width, reg1, reg2): + super().__init__(name, aname, width, reg1, reg2) + + def cstr(self): + # reverse to match the order in OpenJDK + return f'__ {self._name}(' + ', '.join([reg.cstr() for reg in reversed(self.operands)]) + ');' + +class Push2Instruction(TwoRegInstruction): + def __init__(self, name, aname, width, reg1, reg2): + super().__init__(name, aname, width, reg1, reg2) + + def cstr(self): + # reverse to match the order in OpenJDK + return f'__ {self._name}(' + ', '.join([reg.cstr() for reg in reversed(self.operands)]) + ');' + +class CmpxchgInstruction(MemRegInstruction): + def __init__(self, name, aname, width, reg, mem_base, mem_idx): + super().__init__(name, aname, width, reg, mem_base, mem_idx) + + def cstr(self): + # reverse to match the order in OpenJDK + return f'__ {self._name}(' + ', '.join([reg.cstr() for reg in reversed(self.operands)]) + ');' + +class CondRegMemInstruction(RegMemInstruction): + def __init__(self, name, aname, width, cond, reg, mem_base, mem_idx): + super().__init__(name, aname, width, reg, mem_base, mem_idx) + self.cond = cond + + def cstr(self): + return f'__ {self._name}(' + 'Assembler::Condition::' + self.cond + ', ' + ', '.join([self.reg.cstr(), self.mem.cstr()]) + ');' + + def astr(self): + return f'{self._aname}' + cond_to_suffix[self.cond] + ' ' + ', '.join([self.reg.astr(), self.mem.astr()]) + +class CondRegInstruction(RegInstruction): + def __init__(self, name, aname, width, cond, reg): + super().__init__(name, aname, width, reg) + self.cond = cond + + def cstr(self): + return f'__ {self._name}b(' + 'Assembler::Condition::' + self.cond + ', ' + self.reg.cstr() + ');' + + def astr(self): + return f'{self._aname}' + cond_to_suffix[self.cond] + ' ' + self.reg.astr() + +class MoveRegMemInstruction(Instruction): + def __init__(self, name, aname, width, mem_width, reg, mem_base, mem_idx): + super().__init__(name, aname) + self.reg = Register().generate(reg, width) + self.mem = Address().generate(mem_base, mem_idx, mem_width) + self.generate_operands(self.reg, self.mem) + +class MoveRegRegInstruction(Instruction): + def __init__(self, name, aname, width, reg_width, reg1, reg2): + super().__init__(name, aname) + self.reg1 = Register().generate(reg1, width) + self.reg2 = Register().generate(reg2, reg_width) + self.generate_operands(self.reg1, self.reg2) + +test_regs = list(registers_mapping.keys()) + +immediates32 = [2 ** i for i in range(0, 32, 4)] +immediates16 = [2 ** i for i in range(0, 16, 2)] +immediates8 = [2 ** i for i in range(0, 8, 2)] +immediates5 = [2 ** i for i in range(0, 5, 1)] +immediate_values_8_to_16_bit = [2 ** i for i in range(8, 16, 2)] +immediate_values_16_to_32_bit = [2 ** i for i in range(16, 32, 2)] +immediate_values_32_to_64_bit = [2 ** i for i in range(32, 64, 2)] +negative_immediates32 = [-2 ** i for i in range(0, 32, 4)] + +immediate_map = { + 8: immediates8, + 16: immediates16, + 32: immediates32, + 64: immediates32 +} + +def is_64_reg(reg): + return reg in {'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', 'r16', 'r17', 'r18', 'r19', 'r20', 'r21', 'r22', 'r23', 'r24', 'r25', 'r26', 'r27', 'r28', 'r29', 'r30', 'r31'} + +def print_instruction(instr, lp64_flag, print_lp64_flag): + cstr = instr.cstr() + astr = instr.astr() + print(" %-75s // %s IID%s" % (cstr, astr, len(ifdef_flags))) + ifdef_flags.append(lp64_flag or not print_lp64_flag) + insns_strs.append(cstr) + outfile.write(f" {astr}\n") + +def handle_lp64_flag(lp64_flag, print_lp64_flag, *regs): + for reg in regs: + if is_64_reg(reg): + if not lp64_flag and print_lp64_flag: + print("#ifdef _LP64") + return True + if lp64_flag and print_lp64_flag: + print("#endif // _LP64") + return False + return lp64_flag + +def get_immediate_list(op_name, width): + # special cases + word_imm_ops = {'addw', 'cmpw'} + dword_imm_ops = {'subl_imm32', 'subq_imm32', 'orq_imm32', 'cmpl_imm32', 'testl'} + qword_imm_ops = {'mov64'} + neg_imm_ops = {'testq'} + bt_ops = {'btq'} + + if op_name in shift_rot_ops: + return immediates5 + elif op_name in bt_ops: + return immediate_map[8] + elif op_name in word_imm_ops: + return immediate_values_8_to_16_bit + elif op_name in dword_imm_ops: + return immediate_values_16_to_32_bit + elif op_name in qword_imm_ops: + return immediate_values_32_to_64_bit + elif op_name in neg_imm_ops: + return negative_immediates32 + else: + return immediate_map[width] + +lp64_flag = False +def generate(RegOp, ops, print_lp64_flag=True, full_set=False): + global lp64_flag + for op in ops: + op_name = op[0] + width = op[2] + + if RegOp in [RegInstruction, CondRegInstruction]: + if full_set: + for i in range(len(test_regs)): + test_reg = test_regs[i] + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg) + instr = RegOp(*op, reg=test_reg) + print_instruction(instr, lp64_flag, print_lp64_flag) + else: + test_reg = random.choice(test_regs) + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg) + instr = RegOp(*op, reg=test_reg) + print_instruction(instr, lp64_flag, print_lp64_flag) + + elif RegOp in [TwoRegInstruction, MoveRegRegInstruction]: + if full_set: + for i in range(len(test_regs)): + test_reg1 = test_regs[i] + test_reg2 = test_regs[(i + 1) % len(test_regs)] + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg1, test_reg2) + instr = RegOp(*op, reg1=test_reg1, reg2=test_reg2) + print_instruction(instr, lp64_flag, print_lp64_flag) + else: + test_reg1 = random.choice(test_regs) + test_reg2 = random.choice(test_regs) + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg1, test_reg2) + instr = RegOp(*op, reg1=test_reg1, reg2=test_reg2) + print_instruction(instr, lp64_flag, print_lp64_flag) + + elif RegOp in [MemRegInstruction, RegMemInstruction, MoveRegMemInstruction, CmpxchgInstruction, CondRegMemInstruction]: + if full_set: + for i in range(len(test_regs)): + test_reg = test_regs[i] + test_mem_base = test_regs[(i + 1) % len(test_regs)] + test_mem_idx = test_regs[(i + 2) % len(test_regs)] + if test_mem_idx == 'rsp': + continue + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg, test_mem_base, test_mem_idx) + instr = RegOp(*op, reg=test_reg, mem_base=test_mem_base, mem_idx=test_mem_idx) + print_instruction(instr, lp64_flag, print_lp64_flag) + else: + filtered_regs = [reg for reg in test_regs if reg != 'rsp'] + test_reg = random.choice(test_regs) + test_mem_base = random.choice(test_regs) + test_mem_idx = random.choice(filtered_regs) + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg, test_mem_base, test_mem_idx) + instr = RegOp(*op, reg=test_reg, mem_base=test_mem_base, mem_idx=test_mem_idx) + print_instruction(instr, lp64_flag, print_lp64_flag) + + elif RegOp in [RegImmInstruction]: + if full_set: + imm_list = get_immediate_list(op_name, width) + for i in range(len(test_regs)): + test_reg = test_regs[i] + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg) + for imm in imm_list: + instr = RegOp(*op, reg=test_reg, imm=imm) + print_instruction(instr, lp64_flag, print_lp64_flag) + else: + test_reg = random.choice(test_regs) + imm = random.choice(get_immediate_list(op_name, width)) + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg) + instr = RegOp(*op, reg=test_reg, imm=imm) + print_instruction(instr, lp64_flag, print_lp64_flag) + + elif RegOp in [MemImmInstruction]: + if full_set: + imm_list = get_immediate_list(op_name, width) + for imm in imm_list: + for i in range(len(test_regs)): + test_mem_base = test_regs[i] + test_mem_idx = test_regs[(i + 1) % len(test_regs)] + if test_mem_idx == 'rsp': + continue + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_mem_base, test_mem_idx) + instr = RegOp(*op, imm=imm, mem_base=test_mem_base, mem_idx=test_mem_idx) + print_instruction(instr, lp64_flag, print_lp64_flag) + + else: + filtered_regs = [reg for reg in test_regs if reg != 'rsp'] + imm = random.choice(get_immediate_list(op_name, width)) + test_mem_base = random.choice(test_regs) + test_mem_idx = random.choice(filtered_regs) + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_mem_base, test_mem_idx) + instr = RegOp(*op, imm=imm, mem_base=test_mem_base, mem_idx=test_mem_idx) + print_instruction(instr, lp64_flag, print_lp64_flag) + + elif RegOp in [MemInstruction]: + if full_set: + for i in range(len(test_regs)): + test_mem_base = test_regs[i] + test_mem_idx = test_regs[(i + 1) % len(test_regs)] + if test_mem_idx == 'rsp': + continue + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_mem_base, test_mem_idx) + instr = RegOp(*op, mem_base=test_mem_base, mem_idx=test_mem_idx) + print_instruction(instr, lp64_flag, print_lp64_flag) + else: + filtered_regs = [reg for reg in test_regs if reg != 'rsp'] + test_mem_base = random.choice(test_regs) + test_mem_idx = random.choice(filtered_regs) + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_mem_base, test_mem_idx) + instr = RegOp(*op, mem_base=test_mem_base, mem_idx=test_mem_idx) + print_instruction(instr, lp64_flag, print_lp64_flag) + + elif RegOp in [RegRegImmInstruction]: + if full_set: + imm_list = get_immediate_list(op_name, width) + for i in range(len(test_regs)): + test_reg1 = test_regs[i] + test_reg2 = test_regs[(i + 1) % len(test_regs)] + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg1, test_reg2) + for imm in imm_list: + instr = RegOp(*op, reg1=test_reg1, reg2=test_reg2, imm=imm) + print_instruction(instr, lp64_flag, print_lp64_flag) + else: + imm = random.choice(get_immediate_list(op_name, width)) + test_reg1 = random.choice(test_regs) + test_reg2 = random.choice(test_regs) + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg1, test_reg2) + instr = RegOp(*op, reg1=test_reg1, reg2=test_reg2, imm=imm) + print_instruction(instr, lp64_flag, print_lp64_flag) + + elif RegOp in [RegMemImmInstruction]: + if full_set: + imm_list = get_immediate_list(op_name, width) + for i in range(len(test_regs)): + test_reg = test_regs[i] + test_mem_base = test_regs[(i + 1) % len(test_regs)] + test_mem_idx = test_regs[(i + 2) % len(test_regs)] + if test_mem_idx == 'rsp': + continue + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg, test_mem_base, test_mem_idx) + for imm in imm_list: + instr = RegOp(*op, reg=test_reg, mem_base=test_mem_base, mem_idx=test_mem_idx, imm=imm) + print_instruction(instr, lp64_flag, print_lp64_flag) + else: + imm = random.choice(get_immediate_list(op_name, width)) + filtered_regs = [reg for reg in test_regs if reg != 'rsp'] + test_reg = random.choice(test_regs) + test_mem_base = random.choice(test_regs) + test_mem_idx = random.choice(filtered_regs) + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg, test_mem_base, test_mem_idx) + instr = RegOp(*op, reg=test_reg, imm=imm, mem_base=test_mem_base, mem_idx=test_mem_idx) + print_instruction(instr, lp64_flag, print_lp64_flag) + + elif RegOp in [Push2Instruction, Pop2Instruction]: + if full_set: + for i in range(len(test_regs)): + test_reg1 = test_regs[i] + test_reg2 = test_regs[(i + 1) % len(test_regs)] + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg1, test_reg2) + if test_reg1 == 'rsp' or test_reg2 == 'rsp': + continue + instr = RegOp(*op, reg1=test_reg1, reg2=test_reg2) + print_instruction(instr, lp64_flag, print_lp64_flag) + else: + filtered_regs = [reg for reg in test_regs if reg != 'rsp'] + test_reg1, test_reg2 = random.sample(filtered_regs, 2) + lp64_flag = handle_lp64_flag(lp64_flag, print_lp64_flag, test_reg1, test_reg2) + instr = RegOp(*op, reg1=test_reg1, reg2=test_reg2) + print_instruction(instr, lp64_flag, print_lp64_flag) + + else: + raise ValueError(f"Unsupported instruction type: {RegOp}") + +def print_with_ifdef(ifdef_flags, items, item_formatter, width): + under_defined = False + iid = 0 + for idx, item in enumerate(items): + if ifdef_flags[idx]: + if not under_defined: + print("#ifdef _LP64") + under_defined = True + else: + if under_defined: + print("#endif // _LP64") + under_defined = False + print(" %-*s // IID%s" % (width, item_formatter(item) + ",", iid)) + iid += 1 + if under_defined: + print("#endif // _LP64") + +instruction_set = { + TwoRegInstruction: [ + ('shldl', 'shld', 32), + ('shrdl', 'shrd', 32), + ('adcl', 'adc', 32), + ('cmpl', 'cmp', 32), + ('imull', 'imul', 32), + ('popcntl', 'popcnt', 32), + ('sbbl', 'sbb', 32), + ('subl', 'sub', 32), + ('tzcntl', 'tzcnt', 32), + ('lzcntl', 'lzcnt', 32), + ('addl', 'add', 32), + ('andl', 'and', 32), + ('orl', 'or', 32), + ('xorl', 'xor', 32), + ('movl', 'mov', 32), + ('bsfl', 'bsf', 32), + ('bsrl', 'bsr', 32), + ('xchgl', 'xchg', 32), + ('testl', 'test', 32), + ], + MemRegInstruction: [ + ('addb', 'add', 8), + ('addw', 'add', 16), + ('addl', 'add', 32), + ('adcl', 'adc', 32), + ('andb', 'and', 8), + ('andl', 'and', 32), + ('cmpb', 'cmp', 8), + ('cmpw', 'cmp', 16), + ('cmpl', 'cmp', 32), + ('orb', 'or', 8), + ('orl', 'or', 32), + ('xorb', 'xor', 8), + ('xorl', 'xor', 32), + ('subl', 'sub', 32), + ('movb', 'mov', 8), + ('movl', 'mov', 32), + ('xaddb', 'xadd', 8), + ('xaddw', 'xadd', 16), + ('xaddl', 'xadd', 32), + ], + MemImmInstruction: [ + ('adcl', 'adc', 32), + ('andl', 'and', 32), + ('addb', 'add', 8), + ('addw', 'add', 16), + ('addl', 'add', 32), + ('cmpb', 'cmp', 8), + ('cmpw', 'cmp', 16), + ('cmpl', 'cmp', 32), + ('sarl', 'sar', 32), + ('sall', 'sal', 32), + ('sbbl', 'sbb', 32), + ('shrl', 'shr', 32), + ('subl', 'sub', 32), + ('xorl', 'xor', 32), + ('orb', 'or', 8), + ('orl', 'or', 32), + ('movb', 'mov', 8), + ('movl', 'mov', 32), + ('testb', 'test', 8), + ('testl', 'test', 32), + ('cmpl_imm32', 'cmp', 32), + ], + RegMemInstruction: [ + ('addl', 'add', 32), + ('andl', 'and', 32), + ('cmpb', 'cmp', 8), + ('cmpl', 'cmp', 32), + ('lzcntl', 'lzcnt', 32), + ('orl', 'or', 32), + ('adcl', 'adc', 32), + ('imull', 'imul', 32), + ('popcntl', 'popcnt', 32), + ('sbbl', 'sbb', 32), + ('subl', 'sub', 32), + ('tzcntl', 'tzcnt', 32), + ('xorb', 'xor', 8), + ('xorw', 'xor', 16), + ('xorl', 'xor', 32), + ('movb', 'mov', 8), + ('movl', 'mov', 32), + ('leal', 'lea', 32), + ('xchgb', 'xchg', 8), + ('xchgw', 'xchg', 16), + ('xchgl', 'xchg', 32), + ('testl', 'test', 32), + ], + RegImmInstruction: [ + ('addb', 'add', 8), + ('addl', 'add', 32), + ('andl', 'and', 32), + ('adcl', 'adc', 32), + ('cmpb', 'cmp', 8), + ('cmpl', 'cmp', 32), + ('rcll', 'rcl', 32), + ('roll', 'rol', 32), + ('rorl', 'ror', 32), + ('sarl', 'sar', 32), + ('sall', 'sal', 32), + ('sbbl', 'sbb', 32), + ('shll', 'shl', 32), + ('shrl', 'shr', 32), + ('subl', 'sub', 32), + ('xorl', 'xor', 32), + ('movl', 'mov', 32), + ('testb', 'test', 8), + ('testl', 'test', 32), + ('subl_imm32', 'sub', 32), + ], + CondRegMemInstruction: [ + ('cmovl', 'cmov', 32, key) for key in cond_to_suffix.keys() + ], + CondRegInstruction: [ + ('set', 'set', 8, key) for key in cond_to_suffix.keys() + ], + RegInstruction: [ + ('divl', 'div', 32), + ('idivl', 'idiv', 32), + ('imull', 'imul', 32), + ('mull', 'mul', 32), + ('negl', 'neg', 32), + ('notl', 'not', 32), + ('roll', 'rol', 32), + ('rorl', 'ror', 32), + ('sarl', 'sar', 32), + ('sall', 'sal', 32), + ('shll', 'shl', 32), + ('shrl', 'shr', 32), + ('incrementl', 'inc', 32), + ('decrementl', 'dec', 32), + ], + MemInstruction: [ + ('mull', 'mul', 32), + ('negl', 'neg', 32), + ('sarl', 'sar', 32), + ('sall', 'sal', 32), + ('shrl', 'shr', 32), + ('incrementl', 'inc', 32), + ('decrementl', 'dec', 32), + ], + RegMemImmInstruction: [ + ('imull', 'imul', 32), + ], + RegRegImmInstruction: [ + ('imull', 'imul', 32), + ('shldl', 'shld', 32), + ('shrdl', 'shrd', 32), + ], + MoveRegMemInstruction: [ + ('movzbl', 'movzx', 32, 8), + ('movzwl', 'movzx', 32, 16), + ('movsbl', 'movsx', 32, 8), + ('movswl', 'movsx', 32, 16), + ], + MoveRegRegInstruction: [ + ('movzbl', 'movzx', 32, 8), + ('movzwl', 'movzx', 32, 16), + ('movsbl', 'movsx', 32, 8), + ('movswl', 'movsx', 32, 16), + ], + CmpxchgInstruction: [ + ('cmpxchgb', 'cmpxchg', 8), + ('cmpxchgw', 'cmpxchg', 16), + ('cmpxchgl', 'cmpxchg', 32), + ], +} + +instruction_set64 = { + TwoRegInstruction: [ + ('adcq', 'adc', 64), + ('cmpq', 'cmp', 64), + ('imulq', 'imul', 64), + ('popcntq', 'popcnt', 64), + ('sbbq', 'sbb', 64), + ('subq', 'sub', 64), + ('tzcntq', 'tzcnt', 64), + ('lzcntq', 'lzcnt', 64), + ('addq', 'add', 64), + ('andq', 'and', 64), + ('orq', 'or', 64), + ('xorq', 'xor', 64), + ('movq', 'mov', 64), + ('bsfq', 'bsf', 64), + ('bsrq', 'bsr', 64), + ('btq', 'bt', 64), + ('xchgq', 'xchg', 64), + ('testq', 'test', 64), + ], + MemRegInstruction: [ + ('addq', 'add', 64), + ('andq', 'and', 64), + ('cmpq', 'cmp', 64), + ('orq', 'or', 64), + ('xorq', 'xor', 64), + ('subq', 'sub', 64), + ('movq', 'mov', 64), + ('xaddq', 'xadd', 64), + ], + MemImmInstruction: [ + ('andq', 'and', 64), + ('addq', 'add', 64), + ('cmpq', 'cmp', 64), + ('sarq', 'sar', 64), + ('salq', 'sal', 64), + ('sbbq', 'sbb', 64), + ('shrq', 'shr', 64), + ('subq', 'sub', 64), + ('xorq', 'xor', 64), + ('orq', 'or', 64), + ('movq', 'mov', 64), + ('testq', 'test', 64), + ], + RegMemInstruction: [ + ('addq', 'add', 64), + ('andq', 'and', 64), + ('cmpq', 'cmp', 64), + ('lzcntq', 'lzcnt', 64), + ('orq', 'or', 64), + ('adcq', 'adc', 64), + ('imulq', 'imul', 64), + ('popcntq', 'popcnt', 64), + ('sbbq', 'sbb', 64), + ('subq', 'sub', 64), + ('tzcntq', 'tzcnt', 64), + ('xorq', 'xor', 64), + ('movq', 'mov', 64), + ('leaq', 'lea', 64), + ('cvttsd2siq', 'cvttsd2si', 64), + ('xchgq', 'xchg', 64), + ('testq', 'test', 64), + ], + RegImmInstruction: [ + ('addq', 'add', 64), + ('andq', 'and', 64), + ('adcq', 'adc', 64), + ('cmpq', 'cmp', 64), + ('rclq', 'rcl', 64), + ('rcrq', 'rcr', 64), + ('rolq', 'rol', 64), + ('rorq', 'ror', 64), + ('sarq', 'sar', 64), + ('salq', 'sal', 64), + ('sbbq', 'sbb', 64), + ('shlq', 'shl', 64), + ('shrq', 'shr', 64), + ('subq', 'sub', 64), + ('xorq', 'xor', 64), + ('movq', 'mov', 64), + ('mov64', 'mov', 64), + ('btq', 'bt', 64), + ('testq', 'test', 64), + ('orq_imm32', 'or', 64), + ('subq_imm32', 'sub', 64) + ], + CondRegMemInstruction: [ + ('cmovq', 'cmov', 64, key) for key in cond_to_suffix.keys() + ], + RegInstruction: [ + ('call', 'call', 64), + ('divq', 'div', 64), + ('idivq', 'idiv', 64), + ('imulq', 'imul', 64), + ('mulq', 'mul', 64), + ('negq', 'neg', 64), + ('notq', 'not', 64), + ('rolq', 'rol', 64), + ('rorq', 'ror', 64), + ('sarq', 'sar', 64), + ('salq', 'sal', 64), + ('shlq', 'shl', 64), + ('shrq', 'shr', 64), + ('incrementq', 'inc', 64), + ('decrementq', 'dec', 64), + ('pushp', 'pushp', 64), + ('popp', 'popp', 64) + ], + MemInstruction: [ + ('call', 'call', 64), + ('mulq', 'mul', 64), + ('negq', 'neg', 64), + ('sarq', 'sar', 64), + ('salq', 'sal', 64), + ('shrq', 'shr', 64), + ('incrementq', 'inc', 64), + ('decrementq', 'dec', 64) + ], + RegMemImmInstruction: [ + ('imulq', 'imul', 64) + ], + RegRegImmInstruction: [ + ('imulq', 'imul', 64), + ('shldq', 'shld', 64), + ('shrdq', 'shrd', 64) + ], + Pop2Instruction: [ + ('pop2', 'pop2', 64), + ('pop2p', 'pop2p', 64) + ], + Push2Instruction: [ + ('push2', 'push2', 64), + ('push2p', 'push2p', 64) + ], + MoveRegMemInstruction: [ + ('movzbq', 'movzx', 64, 8), + ('movzwq', 'movzx', 64, 16), + ('movsbq', 'movsx', 64, 8), + ('movswq', 'movsx', 64, 16), + ], + MoveRegRegInstruction: [ + ('movzbq', 'movzx', 64, 8), + ('movzwq', 'movzx', 64, 16), + ('movsbq', 'movsx', 64, 8), + ('movswq', 'movsx', 64, 16), + ], + CmpxchgInstruction: [ + ('cmpxchgq', 'cmpxchg', 64), + ], +} + +if __name__ == "__main__": + if platform.system() != "Linux": + print("This script only works on Linux") + exit(1) + + full_set = '--full' in sys.argv + + ifdef_flags = [] + insns_strs = [] + + print("// BEGIN Generated code -- do not edit") + print("// Generated by x86-asmtest.py") + + outfile = open("x86ops.s", "w") + outfile.write(".intel_syntax noprefix\n") + + for RegOp, ops in instruction_set.items(): + generate(RegOp, ops, True, full_set) + + if lp64_flag: + lp64_flag = False + print("#endif // _LP64") + + print("#ifdef _LP64") + for RegOp, ops in instruction_set64.items(): + generate(RegOp, ops, False, full_set) + print("#endif // _LP64") + + outfile.close() + + subprocess.check_call([X86_AS, "x86ops.s", "-o", "x86ops.o",]) + subprocess.check_call([X86_OBJCOPY, "-O", "binary", "-j", ".text", "x86ops.o", "x86ops.bin"]) + + infile = open("x86ops.bin", "rb") + bytes = bytearray(infile.read()) + infile.close() + + disassembly_text = subprocess.check_output([OBJDUMP, "-M", "intel", "-d", "x86ops.o", "--insn-width=16"], text=True) + lines = disassembly_text.split("\n") + instruction_regex = re.compile(r'^\s*([0-9a-f]+):\s*([0-9a-f\s]+?)(?:\s{2,})') + instructions = [] + + for i, line in enumerate(lines): + match = instruction_regex.match(line) + if match: + offset = int(match.group(1), 16) + insns = match.group(2).split() + binary_code = ", ".join([f"0x{insn}" for insn in insns]) + length = len(insns) + instructions.append((length, binary_code)) + + print() + print(" static const uint8_t insns[] =") + print(" {") + print_with_ifdef(ifdef_flags, instructions, lambda x: f"{x[1]}", 80) + print(" };") + print() + print(" static const unsigned int insns_lens[] =") + print(" {") + print_with_ifdef(ifdef_flags, instructions, lambda x: f"{x[0]}", 5) + print(" };") + print() + print(" static const char* insns_strs[] =") + print(" {") + print_with_ifdef(ifdef_flags, insns_strs, lambda x: f"\"{x}\"", 85) + print(" };") + + print("// END Generated code -- do not edit") + + for f in ["x86ops.s", "x86ops.o", "x86ops.bin"]: + os.remove(f) \ No newline at end of file diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index cb6bb2b4cca58..6df68c1ed622a 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -39,9 +39,11 @@ serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.j serviceability/sa/ClhsdbInspect.java 8283578 windows-x64 -vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java 8308367 windows-x64 -vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manySame_a/TestDescription.java 8308367 windows-x64 -vmTestbase/vm/mlvm/indy/func/jvmti/redefineClassInTarget/TestDescription.java 8308367 windows-x64 +vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java 8308367 generic-all +vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manySame_a/TestDescription.java 8308367 generic-all +vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2none_b/TestDescription.java 8308367 generic-all +vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_none2indy_b/TestDescription.java 8308367 generic-all +vmTestbase/vm/mlvm/indy/func/jvmti/redefineClassInTarget/TestDescription.java 8308367 generic-all vmTestbase/nsk/jdi/StepRequest/addClassFilter_rt/filter_rt001/TestDescription.java 8043571 generic-all vmTestbase/nsk/jdi/StepRequest/addClassFilter_rt/filter_rt003/TestDescription.java 8043571 generic-all @@ -53,5 +55,3 @@ vmTestbase/nsk/stress/thread/thread006.java 8321476 linux-all compiler/cha/TypeProfileFinalMethod.java 8341039 generic-all gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64 - -runtime/condy/escapeAnalysis/TestEscapeCondy.java 8339694 generic-all diff --git a/test/hotspot/jtreg/ProblemList-generational-zgc.txt b/test/hotspot/jtreg/ProblemList-generational-zgc.txt deleted file mode 100644 index 801328ec4aec5..0000000000000 --- a/test/hotspot/jtreg/ProblemList-generational-zgc.txt +++ /dev/null @@ -1,118 +0,0 @@ -# -# 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 -# 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. -# - -############################################################################# -# -# List of quarantined tests for testing with Generational ZGC. -# -############################################################################# - -# Quiet all SA tests - -resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java 8307393 generic-all -serviceability/sa/CDSJMapClstats.java 8307393 generic-all -serviceability/sa/ClhsdbAttach.java 8307393 generic-all -serviceability/sa/ClhsdbAttachDifferentJVMs.java 8307393 generic-all -serviceability/sa/ClhsdbCDSCore.java 8307393 generic-all -serviceability/sa/ClhsdbCDSJstackPrintAll.java 8307393 generic-all -serviceability/sa/ClhsdbClasses.java 8307393 generic-all -serviceability/sa/ClhsdbDumpclass.java 8307393 generic-all -serviceability/sa/ClhsdbDumpheap.java 8307393 generic-all -serviceability/sa/ClhsdbField.java 8307393 generic-all -serviceability/sa/ClhsdbFindPC.java#apa 8307393 generic-all -serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8307393 generic-all -serviceability/sa/ClhsdbFindPC.java#no-xcomp-process 8307393 generic-all -serviceability/sa/ClhsdbFindPC.java#xcomp-core 8307393 generic-all -serviceability/sa/ClhsdbFindPC.java#xcomp-process 8307393 generic-all -serviceability/sa/ClhsdbFlags.java 8307393 generic-all -serviceability/sa/ClhsdbHistory.java 8307393 generic-all -serviceability/sa/ClhsdbInspect.java 8307393 generic-all -serviceability/sa/ClhsdbJdis.java 8307393 generic-all -serviceability/sa/ClhsdbJhisto.java 8307393 generic-all -serviceability/sa/ClhsdbJstack.java#id0 8307393 generic-all -serviceability/sa/ClhsdbJstack.java#id1 8307393 generic-all -serviceability/sa/ClhsdbJstackWithConcurrentLock.java 8307393 generic-all -serviceability/sa/ClhsdbJstackXcompStress.java 8307393 generic-all -serviceability/sa/ClhsdbLauncher.java 8307393 generic-all -serviceability/sa/ClhsdbLongConstant.java 8307393 generic-all -serviceability/sa/ClhsdbPmap.java 8307393 generic-all -serviceability/sa/ClhsdbPmap.java#core 8307393 generic-all -serviceability/sa/ClhsdbPmap.java#process 8307393 generic-all -serviceability/sa/ClhsdbPrintAll.java 8307393 generic-all -serviceability/sa/ClhsdbPrintAs.java 8307393 generic-all -serviceability/sa/ClhsdbPrintStatics.java 8307393 generic-all -serviceability/sa/ClhsdbPstack.java#core 8307393 generic-all -serviceability/sa/ClhsdbPstack.java#process 8307393 generic-all -serviceability/sa/ClhsdbScanOops.java 8307393 generic-all -serviceability/sa/ClhsdbSource.java 8307393 generic-all -serviceability/sa/ClhsdbSymbol.java 8307393 generic-all -serviceability/sa/ClhsdbThread.java 8307393 generic-all -serviceability/sa/ClhsdbThreadContext.java 8307393 generic-all -serviceability/sa/ClhsdbVmStructsDump.java 8307393 generic-all -serviceability/sa/ClhsdbWhere.java 8307393 generic-all -serviceability/sa/DeadlockDetectionTest.java 8307393 generic-all -serviceability/sa/JhsdbThreadInfoTest.java 8307393 generic-all -serviceability/sa/LingeredAppSysProps.java 8307393 generic-all -serviceability/sa/LingeredAppWithDefaultMethods.java 8307393 generic-all -serviceability/sa/LingeredAppWithEnum.java 8307393 generic-all -serviceability/sa/LingeredAppWithInterface.java 8307393 generic-all -serviceability/sa/LingeredAppWithInvokeDynamic.java 8307393 generic-all -serviceability/sa/LingeredAppWithLock.java 8307393 generic-all -serviceability/sa/LingeredAppWithNativeMethod.java 8307393 generic-all -serviceability/sa/LingeredAppWithRecComputation.java 8307393 generic-all -serviceability/sa/TestClassDump.java 8307393 generic-all -serviceability/sa/TestClhsdbJstackLock.java 8307393 generic-all -serviceability/sa/TestCpoolForInvokeDynamic.java 8307393 generic-all -serviceability/sa/TestDefaultMethods.java 8307393 generic-all -serviceability/sa/TestG1HeapRegion.java 8307393 generic-all -serviceability/sa/TestHeapDumpForInvokeDynamic.java 8307393 generic-all -serviceability/sa/TestInstanceKlassSize.java 8307393 generic-all -serviceability/sa/TestInstanceKlassSizeForInterface.java 8307393 generic-all -serviceability/sa/TestIntConstant.java 8307393 generic-all -serviceability/sa/TestJhsdbJstackLineNumbers.java 8307393 generic-all -serviceability/sa/TestJhsdbJstackLock.java 8307393 generic-all -serviceability/sa/TestJhsdbJstackMixed.java 8307393 generic-all -serviceability/sa/TestJhsdbJstackUpcall.java 8307393 generic-all -serviceability/sa/TestJmapCore.java 8307393 generic-all -serviceability/sa/TestJmapCoreMetaspace.java 8307393 generic-all -serviceability/sa/TestObjectAlignment.java 8307393 generic-all -serviceability/sa/TestObjectMonitorIterate.java 8307393 generic-all -serviceability/sa/TestPrintMdo.java 8307393 generic-all -serviceability/sa/TestRevPtrsForInvokeDynamic.java 8307393 generic-all -serviceability/sa/TestSysProps.java 8307393 generic-all -serviceability/sa/TestType.java 8307393 generic-all -serviceability/sa/TestUniverse.java 8307393 generic-all -serviceability/sa/UniqueVtableTest.java 8307393 generic-all -serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java 8307393 generic-all -serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java 8307393 generic-all -serviceability/sa/sadebugd/ClhsdbAttachToDebugServer.java 8307393 generic-all -serviceability/sa/sadebugd/ClhsdbTestConnectArgument.java 8307393 generic-all -serviceability/sa/ClhsdbTestAllocationMerge.java 8307393 generic-all -serviceability/sa/sadebugd/DebugdConnectTest.java 8307393 generic-all -serviceability/sa/sadebugd/DebugdUtils.java 8307393 generic-all -serviceability/sa/sadebugd/DisableRegistryTest.java 8307393 generic-all -serviceability/sa/sadebugd/PmapOnDebugdTest.java 8307393 generic-all -serviceability/sa/sadebugd/RunCommandOnServerTest.java 8307393 generic-all -serviceability/sa/sadebugd/SADebugDTest.java 8307393 generic-all - -vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 1afe56c99f8af..7b2978ba4916a 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -27,22 +27,92 @@ # ############################################################################# -resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java 8276539 generic-all -serviceability/sa/CDSJMapClstats.java 8276539 generic-all -serviceability/sa/ClhsdbJhisto.java 8276539 generic-all -serviceability/sa/ClhsdbJstackWithConcurrentLock.java 8276539 generic-all -serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java 8276539 generic-all +# Quiet all SA tests -serviceability/sa/ClhsdbFindPC.java#xcomp-core 8284045 generic-all -serviceability/sa/TestJmapCore.java 8268283,8270202 generic-all -serviceability/sa/TestJmapCoreMetaspace.java 8268636 generic-all - -serviceability/sa/TestJhsdbJstackMixed.java 8248912 generic-all -serviceability/sa/ClhsdbPstack.java#process 8248912 generic-all -serviceability/sa/ClhsdbPstack.java#core 8248912 generic-all - -serviceability/sa/TestSysProps.java 8302055 generic-all - -serviceability/sa/TestHeapDumpForInvokeDynamic.java 8315646 generic-all +resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java 8307393 generic-all +serviceability/sa/CDSJMapClstats.java 8307393 generic-all +serviceability/sa/ClhsdbAttach.java 8307393 generic-all +serviceability/sa/ClhsdbAttachDifferentJVMs.java 8307393 generic-all +serviceability/sa/ClhsdbCDSCore.java 8307393 generic-all +serviceability/sa/ClhsdbCDSJstackPrintAll.java 8307393 generic-all +serviceability/sa/ClhsdbClasses.java 8307393 generic-all +serviceability/sa/ClhsdbDumpclass.java 8307393 generic-all +serviceability/sa/ClhsdbDumpheap.java 8307393 generic-all +serviceability/sa/ClhsdbField.java 8307393 generic-all +serviceability/sa/ClhsdbFindPC.java#apa 8307393 generic-all +serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8307393 generic-all +serviceability/sa/ClhsdbFindPC.java#no-xcomp-process 8307393 generic-all +serviceability/sa/ClhsdbFindPC.java#xcomp-core 8307393 generic-all +serviceability/sa/ClhsdbFindPC.java#xcomp-process 8307393 generic-all +serviceability/sa/ClhsdbFlags.java 8307393 generic-all +serviceability/sa/ClhsdbHistory.java 8307393 generic-all +serviceability/sa/ClhsdbInspect.java 8307393 generic-all +serviceability/sa/ClhsdbJdis.java 8307393 generic-all +serviceability/sa/ClhsdbJhisto.java 8307393 generic-all +serviceability/sa/ClhsdbJstack.java#id0 8307393 generic-all +serviceability/sa/ClhsdbJstack.java#id1 8307393 generic-all +serviceability/sa/ClhsdbJstackWithConcurrentLock.java 8307393 generic-all +serviceability/sa/ClhsdbJstackXcompStress.java 8307393 generic-all +serviceability/sa/ClhsdbLauncher.java 8307393 generic-all +serviceability/sa/ClhsdbLongConstant.java 8307393 generic-all +serviceability/sa/ClhsdbPmap.java 8307393 generic-all +serviceability/sa/ClhsdbPmap.java#core 8307393 generic-all +serviceability/sa/ClhsdbPmap.java#process 8307393 generic-all +serviceability/sa/ClhsdbPrintAll.java 8307393 generic-all +serviceability/sa/ClhsdbPrintAs.java 8307393 generic-all +serviceability/sa/ClhsdbPrintStatics.java 8307393 generic-all +serviceability/sa/ClhsdbPstack.java#core 8307393 generic-all +serviceability/sa/ClhsdbPstack.java#process 8307393 generic-all +serviceability/sa/ClhsdbScanOops.java 8307393 generic-all +serviceability/sa/ClhsdbSource.java 8307393 generic-all +serviceability/sa/ClhsdbSymbol.java 8307393 generic-all +serviceability/sa/ClhsdbThread.java 8307393 generic-all +serviceability/sa/ClhsdbThreadContext.java 8307393 generic-all +serviceability/sa/ClhsdbVmStructsDump.java 8307393 generic-all +serviceability/sa/ClhsdbWhere.java 8307393 generic-all +serviceability/sa/DeadlockDetectionTest.java 8307393 generic-all +serviceability/sa/JhsdbThreadInfoTest.java 8307393 generic-all +serviceability/sa/LingeredAppSysProps.java 8307393 generic-all +serviceability/sa/LingeredAppWithDefaultMethods.java 8307393 generic-all +serviceability/sa/LingeredAppWithEnum.java 8307393 generic-all +serviceability/sa/LingeredAppWithInterface.java 8307393 generic-all +serviceability/sa/LingeredAppWithInvokeDynamic.java 8307393 generic-all +serviceability/sa/LingeredAppWithLock.java 8307393 generic-all +serviceability/sa/LingeredAppWithNativeMethod.java 8307393 generic-all +serviceability/sa/LingeredAppWithRecComputation.java 8307393 generic-all +serviceability/sa/TestClassDump.java 8307393 generic-all +serviceability/sa/TestClhsdbJstackLock.java 8307393 generic-all +serviceability/sa/TestCpoolForInvokeDynamic.java 8307393 generic-all +serviceability/sa/TestDefaultMethods.java 8307393 generic-all +serviceability/sa/TestG1HeapRegion.java 8307393 generic-all +serviceability/sa/TestHeapDumpForInvokeDynamic.java 8307393 generic-all +serviceability/sa/TestInstanceKlassSize.java 8307393 generic-all +serviceability/sa/TestInstanceKlassSizeForInterface.java 8307393 generic-all +serviceability/sa/TestIntConstant.java 8307393 generic-all +serviceability/sa/TestJhsdbJstackLineNumbers.java 8307393 generic-all +serviceability/sa/TestJhsdbJstackLock.java 8307393 generic-all +serviceability/sa/TestJhsdbJstackMixed.java 8307393 generic-all +serviceability/sa/TestJhsdbJstackUpcall.java 8307393 generic-all +serviceability/sa/TestJmapCore.java 8307393 generic-all +serviceability/sa/TestJmapCoreMetaspace.java 8307393 generic-all +serviceability/sa/TestObjectAlignment.java 8307393 generic-all +serviceability/sa/TestObjectMonitorIterate.java 8307393 generic-all +serviceability/sa/TestPrintMdo.java 8307393 generic-all +serviceability/sa/TestRevPtrsForInvokeDynamic.java 8307393 generic-all +serviceability/sa/TestSysProps.java 8307393 generic-all +serviceability/sa/TestType.java 8307393 generic-all +serviceability/sa/TestUniverse.java 8307393 generic-all +serviceability/sa/UniqueVtableTest.java 8307393 generic-all +serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java 8307393 generic-all +serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java 8307393 generic-all +serviceability/sa/sadebugd/ClhsdbAttachToDebugServer.java 8307393 generic-all +serviceability/sa/sadebugd/ClhsdbTestConnectArgument.java 8307393 generic-all +serviceability/sa/ClhsdbTestAllocationMerge.java 8307393 generic-all +serviceability/sa/sadebugd/DebugdConnectTest.java 8307393 generic-all +serviceability/sa/sadebugd/DebugdUtils.java 8307393 generic-all +serviceability/sa/sadebugd/DisableRegistryTest.java 8307393 generic-all +serviceability/sa/sadebugd/PmapOnDebugdTest.java 8307393 generic-all +serviceability/sa/sadebugd/RunCommandOnServerTest.java 8307393 generic-all +serviceability/sa/sadebugd/SADebugDTest.java 8307393 generic-all vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 0e75009ac8a1a..ce9e97e1715fd 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -53,15 +53,13 @@ compiler/loopopts/TestUnreachableInnerLoop.java 8288981 linux-s390x compiler/c2/Test8004741.java 8235801 generic-all compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all -compiler/c2/irTests/TestIfMinMax.java 8339220 linux-s390x compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all compiler/codecache/CheckLargePages.java 8332654 linux-x64 compiler/vectorapi/reshape/TestVectorReinterpret.java 8320897 aix-ppc64,linux-ppc64le compiler/vectorapi/VectorLogicalOpIdentityTest.java 8302459 linux-x64,windows-x64 -compiler/vectorapi/VectorRebracket128Test.java#ZSinglegen 8330538 generic-all -compiler/vectorapi/VectorRebracket128Test.java#ZGenerational 8330538 generic-all +compiler/vectorapi/VectorRebracket128Test.java#Z 8330538 generic-all compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java 8331704 linux-riscv64 @@ -95,8 +93,7 @@ gc/TestAlwaysPreTouchBehavior.java#ParallelCollector 8334513 generic-all gc/TestAlwaysPreTouchBehavior.java#SerialCollector 8334513 generic-all gc/TestAlwaysPreTouchBehavior.java#Shenandoah 8334513 generic-all gc/TestAlwaysPreTouchBehavior.java#G1 8334513 generic-all -gc/TestAlwaysPreTouchBehavior.java#ZGenerational 8334513 generic-all -gc/TestAlwaysPreTouchBehavior.java#ZSinglegen 8334513 generic-all +gc/TestAlwaysPreTouchBehavior.java#Z 8334513 generic-all gc/TestAlwaysPreTouchBehavior.java#Epsilon 8334513 generic-all gc/stress/gclocker/TestExcessGCLockerCollections.java 8229120 generic-all @@ -106,6 +103,7 @@ gc/stress/gclocker/TestExcessGCLockerCollections.java 8229120 generic-all runtime/jni/terminatedThread/TestTerminatedThread.java 8317789 aix-ppc64 runtime/handshake/HandshakeSuspendExitTest.java 8294313 generic-all +runtime/Monitor/SyncOnValueBasedClassTest.java 8340995 linux-s390x runtime/os/TestTracePageSizes.java#no-options 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#explicit-large-page-size 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#compiler-options 8267460 linux-aarch64 @@ -122,6 +120,7 @@ applications/jcstress/copy.java 8229852 linux-all containers/docker/TestJcmd.java 8278102 linux-all containers/docker/TestMemoryAwareness.java 8303470 linux-all containers/docker/TestJFREvents.java 8327723 linux-x64 +containers/docker/TestJcmdWithSideCar.java 8341518 linux-x64 ############################################################################# diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 5ed0227068cf6..21c5aebaa716c 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -61,8 +61,6 @@ requires.properties= \ vm.gc.Shenandoah \ vm.gc.Epsilon \ vm.gc.Z \ - vm.gc.ZGenerational \ - vm.gc.ZSinglegen \ vm.jvmci \ vm.jvmci.enabled \ vm.emulatedClient \ @@ -86,7 +84,7 @@ requires.properties= \ vm.compiler2.enabled \ vm.musl \ vm.flagless \ - docker.support \ + container.support \ systemd.support \ jdk.containerized diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 4ab4ba68692c1..f54dc79fcfc8f 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -438,6 +438,8 @@ hotspot_appcds_dynamic = \ -runtime/cds/appcds/complexURI \ -runtime/cds/appcds/customLoader \ -runtime/cds/appcds/dynamicArchive \ + -runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java \ + -runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java \ -runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java \ -runtime/cds/appcds/javaldr/ArrayTest.java \ -runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java \ @@ -454,6 +456,7 @@ hotspot_appcds_dynamic = \ -runtime/cds/appcds/BadBSM.java \ -runtime/cds/appcds/DumpClassList.java \ -runtime/cds/appcds/DumpClassListWithLF.java \ + -runtime/cds/appcds/DumpRuntimeClassesTest.java \ -runtime/cds/appcds/DumpingWithNoCoops.java \ -runtime/cds/appcds/ExtraSymbols.java \ -runtime/cds/appcds/LambdaContainsOldInf.java \ diff --git a/test/hotspot/jtreg/compiler/arguments/TestManyParameters.java b/test/hotspot/jtreg/compiler/arguments/TestManyParameters.java new file mode 100644 index 0000000000000..4828a0feabc40 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arguments/TestManyParameters.java @@ -0,0 +1,47 @@ +/* + * 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 + * @requires os.simpleArch == "x64" + * @bug 8342156 + * @summary Check that C2's restriction on number of method arguments is not too + * restrictive on x64. + * + * @run main/othervm -Xcomp + * -XX:CompileCommand=compileonly,compiler.arguments.TestManyParameters::test + * -XX:+UnlockDiagnosticVMOptions + * -XX:+AbortVMOnCompilationFailure + * compiler.arguments.TestManyParameters + */ + +package compiler.arguments; + +public class TestManyParameters { + + public static void main(String[] args) { + test(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54); + } + + static void test(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11, int i12, int i13, int i14, int i15, int i16, int i17, int i18, int i19, int i20, int i21, int i22, int i23, int i24, int i25, int i26, int i27, int i28, int i29, int i30, int i31, int i32, int i33, int i34, int i35, int i36, int i37, int i38, int i39, int i40, int i41, int i42, int i43, int i44, int i45, int i46, int i47, int i48, int i49, int i50, int i51, int i52, int i53, int i54) {} +} diff --git a/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java b/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java index 6597b2186f266..0a403a784506f 100644 --- a/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java +++ b/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java @@ -25,6 +25,7 @@ * @test * @library /test/lib / * @requires vm.flagless + * @requires ! vm.opt.final.UnlockExperimentalVMOptions * @requires vm.compMode != "Xint" * @run driver compiler.blackhole.BlackholeExperimentalUnlockTest */ diff --git a/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java b/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java new file mode 100644 index 0000000000000..6a7179d0ce45f --- /dev/null +++ b/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java @@ -0,0 +1,145 @@ +/* + * 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.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; + +/** + * @test + * @bug 8340313 + * @summary Test that concurrent patching of oop immediates is thread-safe in C1. + * @run main/othervm/timeout=480 -Xcomp -XX:CompileCommand=compileonly,TestConcurrentPatching::* -XX:TieredStopAtLevel=1 TestConcurrentPatching + */ + +class MyClass { } + +class Holder { + public static final MyClass OBJ1 = null; + public static final MyClass OBJ2 = null; + public static final MyClass OBJ3 = null; + public static final MyClass OBJ4 = null; + public static final MyClass OBJ5 = null; + public static final MyClass OBJ6 = null; + public static final MyClass OBJ7 = null; + public static final MyClass OBJ8 = null; + public static final MyClass OBJ9 = null; + public static final MyClass OBJ10 = null; + public static final MyClass OBJ11 = null; + public static final MyClass OBJ12 = null; + public static final MyClass OBJ13 = null; + public static final MyClass OBJ14 = null; + public static final MyClass OBJ15 = null; + public static final MyClass OBJ16 = null; + public static final MyClass OBJ17 = null; + public static final MyClass OBJ18 = null; + public static final MyClass OBJ19 = null; + public static final MyClass OBJ20 = null; +} + +public class TestConcurrentPatching { + // Increase to 100_000 for a good chance of reproducing the issue with a single run + static final int ITERATIONS = 1000; + + static Object field; + + // 'Holder' class is unloaded on first execution and therefore field + // accesses require patching when the method is C1 compiled (with -Xcomp). + public static void test() { + field = Holder.OBJ1; + field = Holder.OBJ2; + field = Holder.OBJ3; + field = Holder.OBJ4; + field = Holder.OBJ5; + field = Holder.OBJ6; + field = Holder.OBJ7; + field = Holder.OBJ8; + field = Holder.OBJ9; + field = Holder.OBJ10; + field = Holder.OBJ11; + field = Holder.OBJ12; + field = Holder.OBJ13; + field = Holder.OBJ14; + field = Holder.OBJ15; + field = Holder.OBJ16; + field = Holder.OBJ17; + field = Holder.OBJ18; + field = Holder.OBJ19; + field = Holder.OBJ20; + } + + // Appendix of invokedynamic call sites is unloaded on first execution and + // therefore requires patching when the method is C1 compiled (with -Xcomp). + public static void testIndy() throws Throwable { + field = (Runnable) () -> { }; + field = (Runnable) () -> { }; + field = (Runnable) () -> { }; + field = (Runnable) () -> { }; + field = (Runnable) () -> { }; + field = (Runnable) () -> { }; + field = (Runnable) () -> { }; + field = (Runnable) () -> { }; + field = (Runnable) () -> { }; + field = (Runnable) () -> { }; + } + + // Run 'test' by multiple threads to trigger concurrent patching of field accesses + static void runWithThreads(Method method) { + ArrayList threads = new ArrayList<>(); + for (int threadIdx = 0; threadIdx < 10; threadIdx++) { + threads.add(new Thread(() -> { + try { + method.invoke(null); + } catch (Exception e) { + throw new IllegalStateException(e); + } + })); + } + threads.forEach(Thread::start); + threads.forEach(t -> { + try { + t.join(); + } catch (Throwable e) { + throw new IllegalStateException(e); + } + }); + } + + public static void main(String[] args) throws Exception { + Class thisClass = TestConcurrentPatching.class; + ClassLoader defaultLoader = thisClass.getClassLoader(); + URL classesDir = thisClass.getProtectionDomain().getCodeSource().getLocation(); + + // Load the test class multiple times with a separate class loader to make sure + // that the 'Holder' class is unloaded for each compilation of method 'test' + // and that the appendix of the invokedynamic call site is unloaded for each + // compilation of method 'testIndy'. + for (int i = 0; i < ITERATIONS; ++i) { + URLClassLoader myLoader = URLClassLoader.newInstance(new URL[] {classesDir}, defaultLoader.getParent()); + Class testClass = Class.forName(thisClass.getCanonicalName(), true, myLoader); + runWithThreads(testClass.getDeclaredMethod("test")); + runWithThreads(testClass.getDeclaredMethod("testIndy")); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c1/TestOSRLotsOfLocals.java b/test/hotspot/jtreg/compiler/c1/TestOSRLotsOfLocals.java new file mode 100644 index 0000000000000..c6e111fabad55 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c1/TestOSRLotsOfLocals.java @@ -0,0 +1,102 @@ +/* + * 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 + * @summary Test that OSR correctly handles method with large number of locals + * @bug 8335662 + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * + * @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 + * compiler.c1.TestOSRLotsOfLocals + */ +package compiler.c1; + +import java.lang.reflect.Method; + +import jdk.test.whitebox.WhiteBox; + +import static compiler.whitebox.CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE; + +public class TestOSRLotsOfLocals { + + private static WhiteBox wb = WhiteBox.getWhiteBox(); + + public static void main(String... args) throws Exception { + Method method = TestOSRLotsOfLocals.class.getDeclaredMethod("lotsOfLocals"); + + wb.enqueueMethodForCompilation(method, COMP_LEVEL_SIMPLE, 0); + while (wb.isMethodQueuedForCompilation(method)) { + Thread.onSpinWait(); + } + } + + private static synchronized void lotsOfLocals() { + boolean b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, b33, b34, b35, b36, b37, b38, b39, b40, b41, b42, b43, b44, b45, b46, b47, b48, b49, b50, b51, b52, b53, b54, b55, b56, b57, b58, b59, b60, b61, b62, b63, b64, b65, b66, b67, b68, b69, b70, b71, b72, b73, b74, b75, b76, b77, b78, b79, b80, b81, b82, b83, b84, b85, b86, b87, b88, b89, b90, b91, b92, b93, b94, b95, b96, b97, b98, b99, + b100, b101, b102, b103, b104, b105, b106, b107, b108, b109, b110, b111, b112, b113, b114, b115, b116, b117, b118, b119, b120, b121, b122, b123, b124, b125, b126, b127, b128, b129, b130, b131, b132, b133, b134, b135, b136, b137, b138, b139, b140, b141, b142, b143, b144, b145, b146, b147, b148, b149, b150, b151, b152, b153, b154, b155, b156, b157, b158, b159, b160, b161, b162, b163, b164, b165, b166, b167, b168, b169, b170, b171, b172, b173, b174, b175, b176, b177, b178, b179, b180, b181, b182, b183, b184, b185, b186, b187, b188, b189, b190, b191, b192, b193, b194, b195, b196, b197, b198, b199, + b200, b201, b202, b203, b204, b205, b206, b207, b208, b209, b210, b211, b212, b213, b214, b215, b216, b217, b218, b219, b220, b221, b222, b223, b224, b225, b226, b227, b228, b229, b230, b231, b232, b233, b234, b235, b236, b237, b238, b239, b240, b241, b242, b243, b244, b245, b246, b247, b248, b249, b250, b251, b252, b253, b254, b255, b256, b257, b258, b259, b260, b261, b262, b263, b264, b265, b266, b267, b268, b269, b270, b271, b272, b273, b274, b275, b276, b277, b278, b279, b280, b281, b282, b283, b284, b285, b286, b287, b288, b289, b290, b291, b292, b293, b294, b295, b296, b297, b298, b299, + b300, b301, b302, b303, b304, b305, b306, b307, b308, b309, b310, b311, b312, b313, b314, b315, b316, b317, b318, b319, b320, b321, b322, b323, b324, b325, b326, b327, b328, b329, b330, b331, b332, b333, b334, b335, b336, b337, b338, b339, b340, b341, b342, b343, b344, b345, b346, b347, b348, b349, b350, b351, b352, b353, b354, b355, b356, b357, b358, b359, b360, b361, b362, b363, b364, b365, b366, b367, b368, b369, b370, b371, b372, b373, b374, b375, b376, b377, b378, b379, b380, b381, b382, b383, b384, b385, b386, b387, b388, b389, b390, b391, b392, b393, b394, b395, b396, b397, b398, b399, + b400, b401, b402, b403, b404, b405, b406, b407, b408, b409, b410, b411, b412, b413, b414, b415, b416, b417, b418, b419, b420, b421, b422, b423, b424, b425, b426, b427, b428, b429, b430, b431, b432, b433, b434, b435, b436, b437, b438, b439, b440, b441, b442, b443, b444, b445, b446, b447, b448, b449, b450, b451, b452, b453, b454, b455, b456, b457, b458, b459, b460, b461, b462, b463, b464, b465, b466, b467, b468, b469, b470, b471, b472, b473, b474, b475, b476, b477, b478, b479, b480, b481, b482, b483, b484, b485, b486, b487, b488, b489, b490, b491, b492, b493, b494, b495, b496, b497, b498, b499, + b500, b501, b502, b503, b504, b505, b506, b507, b508, b509, b510, b511, b512, b513, b514, b515, b516, b517, b518, b519, b520, b521, b522, b523, b524, b525, b526, b527, b528, b529, b530, b531, b532, b533, b534, b535, b536, b537, b538, b539, b540, b541, b542, b543, b544, b545, b546, b547, b548, b549, b550, b551, b552, b553, b554, b555, b556, b557, b558, b559, b560, b561, b562, b563, b564, b565, b566, b567, b568, b569, b570, b571, b572, b573, b574, b575, b576, b577, b578, b579, b580, b581, b582, b583, b584, b585, b586, b587, b588, b589, b590, b591, b592, b593, b594, b595, b596, b597, b598, b599, + b600, b601, b602, b603, b604, b605, b606, b607, b608, b609, b610, b611, b612, b613, b614, b615, b616, b617, b618, b619, b620, b621, b622, b623, b624, b625, b626, b627, b628, b629, b630, b631, b632, b633, b634, b635, b636, b637, b638, b639, b640, b641, b642, b643, b644, b645, b646, b647, b648, b649, b650, b651, b652, b653, b654, b655, b656, b657, b658, b659, b660, b661, b662, b663, b664, b665, b666, b667, b668, b669, b670, b671, b672, b673, b674, b675, b676, b677, b678, b679, b680, b681, b682, b683, b684, b685, b686, b687, b688, b689, b690, b691, b692, b693, b694, b695, b696, b697, b698, b699, + b700, b701, b702, b703, b704, b705, b706, b707, b708, b709, b710, b711, b712, b713, b714, b715, b716, b717, b718, b719, b720, b721, b722, b723, b724, b725, b726, b727, b728, b729, b730, b731, b732, b733, b734, b735, b736, b737, b738, b739, b740, b741, b742, b743, b744, b745, b746, b747, b748, b749, b750, b751, b752, b753, b754, b755, b756, b757, b758, b759, b760, b761, b762, b763, b764, b765, b766, b767, b768, b769, b770, b771, b772, b773, b774, b775, b776, b777, b778, b779, b780, b781, b782, b783, b784, b785, b786, b787, b788, b789, b790, b791, b792, b793, b794, b795, b796, b797, b798, b799, + b800, b801, b802, b803, b804, b805, b806, b807, b808, b809, b810, b811, b812, b813, b814, b815, b816, b817, b818, b819, b820, b821, b822, b823, b824, b825, b826, b827, b828, b829, b830, b831, b832, b833, b834, b835, b836, b837, b838, b839, b840, b841, b842, b843, b844, b845, b846, b847, b848, b849, b850, b851, b852, b853, b854, b855, b856, b857, b858, b859, b860, b861, b862, b863, b864, b865, b866, b867, b868, b869, b870, b871, b872, b873, b874, b875, b876, b877, b878, b879, b880, b881, b882, b883, b884, b885, b886, b887, b888, b889, b890, b891, b892, b893, b894, b895, b896, b897, b898, b899, + b900, b901, b902, b903, b904, b905, b906, b907, b908, b909, b910, b911, b912, b913, b914, b915, b916, b917, b918, b919, b920, b921, b922, b923, b924, b925, b926, b927, b928, b929, b930, b931, b932, b933, b934, b935, b936, b937, b938, b939, b940, b941, b942, b943, b944, b945, b946, b947, b948, b949, b950, b951, b952, b953, b954, b955, b956, b957, b958, b959, b960, b961, b962, b963, b964, b965, b966, b967, b968, b969, b970, b971, b972, b973, b974, b975, b976, b977, b978, b979, b980, b981, b982, b983, b984, b985, b986, b987, b988, b989, b990, b991, b992, b993, b994, b995, b996, b997, b998, b999, + b1000, b1001, b1002, b1003, b1004, b1005, b1006, b1007, b1008, b1009, b1010, b1011, b1012, b1013, b1014, b1015, b1016, b1017, b1018, b1019, b1020, b1021, b1022, b1023, b1024, b1025, b1026, b1027, b1028, b1029, b1030, b1031, b1032, b1033, b1034, b1035, b1036, b1037, b1038, b1039, b1040, b1041, b1042, b1043, b1044, b1045, b1046, b1047, b1048, b1049, b1050, b1051, b1052, b1053, b1054, b1055, b1056, b1057, b1058, b1059, b1060, b1061, b1062, b1063, b1064, b1065, b1066, b1067, b1068, b1069, b1070, b1071, b1072, b1073, b1074, b1075, b1076, b1077, b1078, b1079, b1080, b1081, b1082, b1083, b1084, b1085, b1086, b1087, b1088, b1089, b1090, b1091, b1092, b1093, b1094, b1095, b1096, b1097, b1098, b1099, + b1100, b1101, b1102, b1103, b1104, b1105, b1106, b1107, b1108, b1109, b1110, b1111, b1112, b1113, b1114, b1115, b1116, b1117, b1118, b1119, b1120, b1121, b1122, b1123, b1124, b1125, b1126, b1127, b1128, b1129, b1130, b1131, b1132, b1133, b1134, b1135, b1136, b1137, b1138, b1139, b1140, b1141, b1142, b1143, b1144, b1145, b1146, b1147, b1148, b1149, b1150, b1151, b1152, b1153, b1154, b1155, b1156, b1157, b1158, b1159, b1160, b1161, b1162, b1163, b1164, b1165, b1166, b1167, b1168, b1169, b1170, b1171, b1172, b1173, b1174, b1175, b1176, b1177, b1178, b1179, b1180, b1181, b1182, b1183, b1184, b1185, b1186, b1187, b1188, b1189, b1190, b1191, b1192, b1193, b1194, b1195, b1196, b1197, b1198, b1199, + b1200, b1201, b1202, b1203, b1204, b1205, b1206, b1207, b1208, b1209, b1210, b1211, b1212, b1213, b1214, b1215, b1216, b1217, b1218, b1219, b1220, b1221, b1222, b1223, b1224, b1225, b1226, b1227, b1228, b1229, b1230, b1231, b1232, b1233, b1234, b1235, b1236, b1237, b1238, b1239, b1240, b1241, b1242, b1243, b1244, b1245, b1246, b1247, b1248, b1249, b1250, b1251, b1252, b1253, b1254, b1255, b1256, b1257, b1258, b1259, b1260, b1261, b1262, b1263, b1264, b1265, b1266, b1267, b1268, b1269, b1270, b1271, b1272, b1273, b1274, b1275, b1276, b1277, b1278, b1279, b1280, b1281, b1282, b1283, b1284, b1285, b1286, b1287, b1288, b1289, b1290, b1291, b1292, b1293, b1294, b1295, b1296, b1297, b1298, b1299, + b1300, b1301, b1302, b1303, b1304, b1305, b1306, b1307, b1308, b1309, b1310, b1311, b1312, b1313, b1314, b1315, b1316, b1317, b1318, b1319, b1320, b1321, b1322, b1323, b1324, b1325, b1326, b1327, b1328, b1329, b1330, b1331, b1332, b1333, b1334, b1335, b1336, b1337, b1338, b1339, b1340, b1341, b1342, b1343, b1344, b1345, b1346, b1347, b1348, b1349, b1350, b1351, b1352, b1353, b1354, b1355, b1356, b1357, b1358, b1359, b1360, b1361, b1362, b1363, b1364, b1365, b1366, b1367, b1368, b1369, b1370, b1371, b1372, b1373, b1374, b1375, b1376, b1377, b1378, b1379, b1380, b1381, b1382, b1383, b1384, b1385, b1386, b1387, b1388, b1389, b1390, b1391, b1392, b1393, b1394, b1395, b1396, b1397, b1398, b1399, + b1400, b1401, b1402, b1403, b1404, b1405, b1406, b1407, b1408, b1409, b1410, b1411, b1412, b1413, b1414, b1415, b1416, b1417, b1418, b1419, b1420, b1421, b1422, b1423, b1424, b1425, b1426, b1427, b1428, b1429, b1430, b1431, b1432, b1433, b1434, b1435, b1436, b1437, b1438, b1439, b1440, b1441, b1442, b1443, b1444, b1445, b1446, b1447, b1448, b1449, b1450, b1451, b1452, b1453, b1454, b1455, b1456, b1457, b1458, b1459, b1460, b1461, b1462, b1463, b1464, b1465, b1466, b1467, b1468, b1469, b1470, b1471, b1472, b1473, b1474, b1475, b1476, b1477, b1478, b1479, b1480, b1481, b1482, b1483, b1484, b1485, b1486, b1487, b1488, b1489, b1490, b1491, b1492, b1493, b1494, b1495, b1496, b1497, b1498, b1499, + b1500, b1501, b1502, b1503, b1504, b1505, b1506, b1507, b1508, b1509, b1510, b1511, b1512, b1513, b1514, b1515, b1516, b1517, b1518, b1519, b1520, b1521, b1522, b1523, b1524, b1525, b1526, b1527, b1528, b1529, b1530, b1531, b1532, b1533, b1534, b1535, b1536, b1537, b1538, b1539, b1540, b1541, b1542, b1543, b1544, b1545, b1546, b1547, b1548, b1549, b1550, b1551, b1552, b1553, b1554, b1555, b1556, b1557, b1558, b1559, b1560, b1561, b1562, b1563, b1564, b1565, b1566, b1567, b1568, b1569, b1570, b1571, b1572, b1573, b1574, b1575, b1576, b1577, b1578, b1579, b1580, b1581, b1582, b1583, b1584, b1585, b1586, b1587, b1588, b1589, b1590, b1591, b1592, b1593, b1594, b1595, b1596, b1597, b1598, b1599, + b1600, b1601, b1602, b1603, b1604, b1605, b1606, b1607, b1608, b1609, b1610, b1611, b1612, b1613, b1614, b1615, b1616, b1617, b1618, b1619, b1620, b1621, b1622, b1623, b1624, b1625, b1626, b1627, b1628, b1629, b1630, b1631, b1632, b1633, b1634, b1635, b1636, b1637, b1638, b1639, b1640, b1641, b1642, b1643, b1644, b1645, b1646, b1647, b1648, b1649, b1650, b1651, b1652, b1653, b1654, b1655, b1656, b1657, b1658, b1659, b1660, b1661, b1662, b1663, b1664, b1665, b1666, b1667, b1668, b1669, b1670, b1671, b1672, b1673, b1674, b1675, b1676, b1677, b1678, b1679, b1680, b1681, b1682, b1683, b1684, b1685, b1686, b1687, b1688, b1689, b1690, b1691, b1692, b1693, b1694, b1695, b1696, b1697, b1698, b1699, + b1700, b1701, b1702, b1703, b1704, b1705, b1706, b1707, b1708, b1709, b1710, b1711, b1712, b1713, b1714, b1715, b1716, b1717, b1718, b1719, b1720, b1721, b1722, b1723, b1724, b1725, b1726, b1727, b1728, b1729, b1730, b1731, b1732, b1733, b1734, b1735, b1736, b1737, b1738, b1739, b1740, b1741, b1742, b1743, b1744, b1745, b1746, b1747, b1748, b1749, b1750, b1751, b1752, b1753, b1754, b1755, b1756, b1757, b1758, b1759, b1760, b1761, b1762, b1763, b1764, b1765, b1766, b1767, b1768, b1769, b1770, b1771, b1772, b1773, b1774, b1775, b1776, b1777, b1778, b1779, b1780, b1781, b1782, b1783, b1784, b1785, b1786, b1787, b1788, b1789, b1790, b1791, b1792, b1793, b1794, b1795, b1796, b1797, b1798, b1799, + b1800, b1801, b1802, b1803, b1804, b1805, b1806, b1807, b1808, b1809, b1810, b1811, b1812, b1813, b1814, b1815, b1816, b1817, b1818, b1819, b1820, b1821, b1822, b1823, b1824, b1825, b1826, b1827, b1828, b1829, b1830, b1831, b1832, b1833, b1834, b1835, b1836, b1837, b1838, b1839, b1840, b1841, b1842, b1843, b1844, b1845, b1846, b1847, b1848, b1849, b1850, b1851, b1852, b1853, b1854, b1855, b1856, b1857, b1858, b1859, b1860, b1861, b1862, b1863, b1864, b1865, b1866, b1867, b1868, b1869, b1870, b1871, b1872, b1873, b1874, b1875, b1876, b1877, b1878, b1879, b1880, b1881, b1882, b1883, b1884, b1885, b1886, b1887, b1888, b1889, b1890, b1891, b1892, b1893, b1894, b1895, b1896, b1897, b1898, b1899, + b1900, b1901, b1902, b1903, b1904, b1905, b1906, b1907, b1908, b1909, b1910, b1911, b1912, b1913, b1914, b1915, b1916, b1917, b1918, b1919, b1920, b1921, b1922, b1923, b1924, b1925, b1926, b1927, b1928, b1929, b1930, b1931, b1932, b1933, b1934, b1935, b1936, b1937, b1938, b1939, b1940, b1941, b1942, b1943, b1944, b1945, b1946, b1947, b1948, b1949, b1950, b1951, b1952, b1953, b1954, b1955, b1956, b1957, b1958, b1959, b1960, b1961, b1962, b1963, b1964, b1965, b1966, b1967, b1968, b1969, b1970, b1971, b1972, b1973, b1974, b1975, b1976, b1977, b1978, b1979, b1980, b1981, b1982, b1983, b1984, b1985, b1986, b1987, b1988, b1989, b1990, b1991, b1992, b1993, b1994, b1995, b1996, b1997, b1998, b1999, + b2000, b2001, b2002, b2003, b2004, b2005, b2006, b2007, b2008, b2009, b2010, b2011, b2012, b2013, b2014, b2015, b2016, b2017, b2018, b2019, b2020, b2021, b2022, b2023, b2024, b2025, b2026, b2027, b2028, b2029, b2030, b2031, b2032, b2033, b2034, b2035, b2036, b2037, b2038, b2039, b2040, b2041, b2042, b2043, b2044, b2045, b2046, b2047, b2048, b2049, b2050, b2051, b2052, b2053, b2054, b2055, b2056, b2057, b2058, b2059, b2060, b2061, b2062, b2063, b2064, b2065, b2066, b2067, b2068, b2069, b2070, b2071, b2072, b2073, b2074, b2075, b2076, b2077, b2078, b2079, b2080, b2081, b2082, b2083, b2084, b2085, b2086, b2087, b2088, b2089, b2090, b2091, b2092, b2093, b2094, b2095, b2096, b2097, b2098, b2099, + b2100, b2101, b2102, b2103, b2104, b2105, b2106, b2107, b2108, b2109, b2110, b2111, b2112, b2113, b2114, b2115, b2116, b2117, b2118, b2119, b2120, b2121, b2122, b2123, b2124, b2125, b2126, b2127, b2128, b2129, b2130, b2131, b2132, b2133, b2134, b2135, b2136, b2137, b2138, b2139, b2140, b2141, b2142, b2143, b2144, b2145, b2146, b2147, b2148, b2149, b2150, b2151, b2152, b2153, b2154, b2155, b2156, b2157, b2158, b2159, b2160, b2161, b2162, b2163, b2164, b2165, b2166, b2167, b2168, b2169, b2170, b2171, b2172, b2173, b2174, b2175, b2176, b2177, b2178, b2179, b2180, b2181, b2182, b2183, b2184, b2185, b2186, b2187, b2188, b2189, b2190, b2191, b2192, b2193, b2194, b2195, b2196, b2197, b2198, b2199, + b2200, b2201, b2202, b2203, b2204, b2205, b2206, b2207, b2208, b2209, b2210, b2211, b2212, b2213, b2214, b2215, b2216, b2217, b2218, b2219, b2220, b2221, b2222, b2223, b2224, b2225, b2226, b2227, b2228, b2229, b2230, b2231, b2232, b2233, b2234, b2235, b2236, b2237, b2238, b2239, b2240, b2241, b2242, b2243, b2244, b2245, b2246, b2247, b2248, b2249, b2250, b2251, b2252, b2253, b2254, b2255, b2256, b2257, b2258, b2259, b2260, b2261, b2262, b2263, b2264, b2265, b2266, b2267, b2268, b2269, b2270, b2271, b2272, b2273, b2274, b2275, b2276, b2277, b2278, b2279, b2280, b2281, b2282, b2283, b2284, b2285, b2286, b2287, b2288, b2289, b2290, b2291, b2292, b2293, b2294, b2295, b2296, b2297, b2298, b2299, + b2300, b2301, b2302, b2303, b2304, b2305, b2306, b2307, b2308, b2309, b2310, b2311, b2312, b2313, b2314, b2315, b2316, b2317, b2318, b2319, b2320, b2321, b2322, b2323, b2324, b2325, b2326, b2327, b2328, b2329, b2330, b2331, b2332, b2333, b2334, b2335, b2336, b2337, b2338, b2339, b2340, b2341, b2342, b2343, b2344, b2345, b2346, b2347, b2348, b2349, b2350, b2351, b2352, b2353, b2354, b2355, b2356, b2357, b2358, b2359, b2360, b2361, b2362, b2363, b2364, b2365, b2366, b2367, b2368, b2369, b2370, b2371, b2372, b2373, b2374, b2375, b2376, b2377, b2378, b2379, b2380, b2381, b2382, b2383, b2384, b2385, b2386, b2387, b2388, b2389, b2390, b2391, b2392, b2393, b2394, b2395, b2396, b2397, b2398, b2399, + b2400, b2401, b2402, b2403, b2404, b2405, b2406, b2407, b2408, b2409, b2410, b2411, b2412, b2413, b2414, b2415, b2416, b2417, b2418, b2419, b2420, b2421, b2422, b2423, b2424, b2425, b2426, b2427, b2428, b2429, b2430, b2431, b2432, b2433, b2434, b2435, b2436, b2437, b2438, b2439, b2440, b2441, b2442, b2443, b2444, b2445, b2446, b2447, b2448, b2449, b2450, b2451, b2452, b2453, b2454, b2455, b2456, b2457, b2458, b2459, b2460, b2461, b2462, b2463, b2464, b2465, b2466, b2467, b2468, b2469, b2470, b2471, b2472, b2473, b2474, b2475, b2476, b2477, b2478, b2479, b2480, b2481, b2482, b2483, b2484, b2485, b2486, b2487, b2488, b2489, b2490, b2491, b2492, b2493, b2494, b2495, b2496, b2497, b2498, b2499, + b2500, b2501, b2502, b2503, b2504, b2505, b2506, b2507, b2508, b2509, b2510, b2511, b2512, b2513, b2514, b2515, b2516, b2517, b2518, b2519, b2520, b2521, b2522, b2523, b2524, b2525, b2526, b2527, b2528, b2529, b2530, b2531, b2532, b2533, b2534, b2535, b2536, b2537, b2538, b2539, b2540, b2541, b2542, b2543, b2544, b2545, b2546, b2547, b2548, b2549, b2550, b2551, b2552, b2553, b2554, b2555, b2556, b2557, b2558, b2559, b2560, b2561, b2562, b2563, b2564, b2565, b2566, b2567, b2568, b2569, b2570, b2571, b2572, b2573, b2574, b2575, b2576, b2577, b2578, b2579, b2580, b2581, b2582, b2583, b2584, b2585, b2586, b2587, b2588, b2589, b2590, b2591, b2592, b2593, b2594, b2595, b2596, b2597, b2598, b2599, + b2600, b2601, b2602, b2603, b2604, b2605, b2606, b2607, b2608, b2609, b2610, b2611, b2612, b2613, b2614, b2615, b2616, b2617, b2618, b2619, b2620, b2621, b2622, b2623, b2624, b2625, b2626, b2627, b2628, b2629, b2630, b2631, b2632, b2633, b2634, b2635, b2636, b2637, b2638, b2639, b2640, b2641, b2642, b2643, b2644, b2645, b2646, b2647, b2648, b2649, b2650, b2651, b2652, b2653, b2654, b2655, b2656, b2657, b2658, b2659, b2660, b2661, b2662, b2663, b2664, b2665, b2666, b2667, b2668, b2669, b2670, b2671, b2672, b2673, b2674, b2675, b2676, b2677, b2678, b2679, b2680, b2681, b2682, b2683, b2684, b2685, b2686, b2687, b2688, b2689, b2690, b2691, b2692, b2693, b2694, b2695, b2696, b2697, b2698, b2699, + b2700, b2701, b2702, b2703, b2704, b2705, b2706, b2707, b2708, b2709, b2710, b2711, b2712, b2713, b2714, b2715, b2716, b2717, b2718, b2719, b2720, b2721, b2722, b2723, b2724, b2725, b2726, b2727, b2728, b2729, b2730, b2731, b2732, b2733, b2734, b2735, b2736, b2737, b2738, b2739, b2740, b2741, b2742, b2743, b2744, b2745, b2746, b2747, b2748, b2749, b2750, b2751, b2752, b2753, b2754, b2755, b2756, b2757, b2758, b2759, b2760, b2761, b2762, b2763, b2764, b2765, b2766, b2767, b2768, b2769, b2770, b2771, b2772, b2773, b2774, b2775, b2776, b2777, b2778, b2779, b2780, b2781, b2782, b2783, b2784, b2785, b2786, b2787, b2788, b2789, b2790, b2791, b2792, b2793, b2794, b2795, b2796, b2797, b2798, b2799, + b2800, b2801, b2802, b2803, b2804, b2805, b2806, b2807, b2808, b2809, b2810, b2811, b2812, b2813, b2814, b2815, b2816, b2817, b2818, b2819, b2820, b2821, b2822, b2823, b2824, b2825, b2826, b2827, b2828, b2829, b2830, b2831, b2832, b2833, b2834, b2835, b2836, b2837, b2838, b2839, b2840, b2841, b2842, b2843, b2844, b2845, b2846, b2847, b2848, b2849, b2850, b2851, b2852, b2853, b2854, b2855, b2856, b2857, b2858, b2859, b2860, b2861, b2862, b2863, b2864, b2865, b2866, b2867, b2868, b2869, b2870, b2871, b2872, b2873, b2874, b2875, b2876, b2877, b2878, b2879, b2880, b2881, b2882, b2883, b2884, b2885, b2886, b2887, b2888, b2889, b2890, b2891, b2892, b2893, b2894, b2895, b2896, b2897, b2898, b2899, + b2900, b2901, b2902, b2903, b2904, b2905, b2906, b2907, b2908, b2909, b2910, b2911, b2912, b2913, b2914, b2915, b2916, b2917, b2918, b2919, b2920, b2921, b2922, b2923, b2924, b2925, b2926, b2927, b2928, b2929, b2930, b2931, b2932, b2933, b2934, b2935, b2936, b2937, b2938, b2939, b2940, b2941, b2942, b2943, b2944, b2945, b2946, b2947, b2948, b2949, b2950, b2951, b2952, b2953, b2954, b2955, b2956, b2957, b2958, b2959, b2960, b2961, b2962, b2963, b2964, b2965, b2966, b2967, b2968, b2969, b2970, b2971, b2972, b2973, b2974, b2975, b2976, b2977, b2978, b2979, b2980, b2981, b2982, b2983, b2984, b2985, b2986, b2987, b2988, b2989, b2990, b2991, b2992, b2993, b2994, b2995, b2996, b2997, b2998, b2999, + b3000, b3001, b3002, b3003, b3004, b3005, b3006, b3007, b3008, b3009, b3010, b3011, b3012, b3013, b3014, b3015, b3016, b3017, b3018, b3019, b3020, b3021, b3022, b3023, b3024, b3025, b3026, b3027, b3028, b3029, b3030, b3031, b3032, b3033, b3034, b3035, b3036, b3037, b3038, b3039, b3040, b3041, b3042, b3043, b3044, b3045, b3046, b3047, b3048, b3049, b3050, b3051, b3052, b3053, b3054, b3055, b3056, b3057, b3058, b3059, b3060, b3061, b3062, b3063, b3064, b3065, b3066, b3067, b3068, b3069, b3070, b3071, b3072, b3073, b3074, b3075, b3076, b3077, b3078, b3079, b3080, b3081, b3082, b3083, b3084, b3085, b3086, b3087, b3088, b3089, b3090, b3091, b3092, b3093, b3094, b3095, b3096, b3097, b3098, b3099, + b3100, b3101, b3102, b3103, b3104, b3105, b3106, b3107, b3108, b3109, b3110, b3111, b3112, b3113, b3114, b3115, b3116, b3117, b3118, b3119, b3120, b3121, b3122, b3123, b3124, b3125, b3126, b3127, b3128, b3129, b3130, b3131, b3132, b3133, b3134, b3135, b3136, b3137, b3138, b3139, b3140, b3141, b3142, b3143, b3144, b3145, b3146, b3147, b3148, b3149, b3150, b3151, b3152, b3153, b3154, b3155, b3156, b3157, b3158, b3159, b3160, b3161, b3162, b3163, b3164, b3165, b3166, b3167, b3168, b3169, b3170, b3171, b3172, b3173, b3174, b3175, b3176, b3177, b3178, b3179, b3180, b3181, b3182, b3183, b3184, b3185, b3186, b3187, b3188, b3189, b3190, b3191, b3192, b3193, b3194, b3195, b3196, b3197, b3198, b3199, + b3200, b3201, b3202, b3203, b3204, b3205, b3206, b3207, b3208, b3209, b3210, b3211, b3212, b3213, b3214, b3215, b3216, b3217, b3218, b3219, b3220, b3221, b3222, b3223, b3224, b3225, b3226, b3227, b3228, b3229, b3230, b3231, b3232, b3233, b3234, b3235, b3236, b3237, b3238, b3239, b3240, b3241, b3242, b3243, b3244, b3245, b3246, b3247, b3248, b3249, b3250, b3251, b3252, b3253, b3254, b3255, b3256, b3257, b3258, b3259, b3260, b3261, b3262, b3263, b3264, b3265, b3266, b3267, b3268, b3269, b3270, b3271, b3272, b3273, b3274, b3275, b3276, b3277, b3278, b3279, b3280, b3281, b3282, b3283, b3284, b3285, b3286, b3287, b3288, b3289, b3290, b3291, b3292, b3293, b3294, b3295, b3296, b3297, b3298, b3299, + b3300, b3301, b3302, b3303, b3304, b3305, b3306, b3307, b3308, b3309, b3310, b3311, b3312, b3313, b3314, b3315, b3316, b3317, b3318, b3319, b3320, b3321, b3322, b3323, b3324, b3325, b3326, b3327, b3328, b3329, b3330, b3331, b3332, b3333, b3334, b3335, b3336, b3337, b3338, b3339, b3340, b3341, b3342, b3343, b3344, b3345, b3346, b3347, b3348, b3349, b3350, b3351, b3352, b3353, b3354, b3355, b3356, b3357, b3358, b3359, b3360, b3361, b3362, b3363, b3364, b3365, b3366, b3367, b3368, b3369, b3370, b3371, b3372, b3373, b3374, b3375, b3376, b3377, b3378, b3379, b3380, b3381, b3382, b3383, b3384, b3385, b3386, b3387, b3388, b3389, b3390, b3391, b3392, b3393, b3394, b3395, b3396, b3397, b3398, b3399, + b3400, b3401, b3402, b3403, b3404, b3405, b3406, b3407, b3408, b3409, b3410, b3411, b3412, b3413, b3414, b3415, b3416, b3417, b3418, b3419, b3420, b3421, b3422, b3423, b3424, b3425, b3426, b3427, b3428, b3429, b3430, b3431, b3432, b3433, b3434, b3435, b3436, b3437, b3438, b3439, b3440, b3441, b3442, b3443, b3444, b3445, b3446, b3447, b3448, b3449, b3450, b3451, b3452, b3453, b3454, b3455, b3456, b3457, b3458, b3459, b3460, b3461, b3462, b3463, b3464, b3465, b3466, b3467, b3468, b3469, b3470, b3471, b3472, b3473, b3474, b3475, b3476, b3477, b3478, b3479, b3480, b3481, b3482, b3483, b3484, b3485, b3486, b3487, b3488, b3489, b3490, b3491, b3492, b3493, b3494, b3495, b3496, b3497, b3498, b3499, + b3500, b3501, b3502, b3503, b3504, b3505, b3506, b3507, b3508, b3509, b3510, b3511, b3512, b3513, b3514, b3515, b3516, b3517, b3518, b3519, b3520, b3521, b3522, b3523, b3524, b3525, b3526, b3527, b3528, b3529, b3530, b3531, b3532, b3533, b3534, b3535, b3536, b3537, b3538, b3539, b3540, b3541, b3542, b3543, b3544, b3545, b3546, b3547, b3548, b3549, b3550, b3551, b3552, b3553, b3554, b3555, b3556, b3557, b3558, b3559, b3560, b3561, b3562, b3563, b3564, b3565, b3566, b3567, b3568, b3569, b3570, b3571, b3572, b3573, b3574, b3575, b3576, b3577, b3578, b3579, b3580, b3581, b3582, b3583, b3584, b3585, b3586, b3587, b3588, b3589, b3590, b3591, b3592, b3593, b3594, b3595, b3596, b3597, b3598, b3599, + b3600, b3601, b3602, b3603, b3604, b3605, b3606, b3607, b3608, b3609, b3610, b3611, b3612, b3613, b3614, b3615, b3616, b3617, b3618, b3619, b3620, b3621, b3622, b3623, b3624, b3625, b3626, b3627, b3628, b3629, b3630, b3631, b3632, b3633, b3634, b3635, b3636, b3637, b3638, b3639, b3640, b3641, b3642, b3643, b3644, b3645, b3646, b3647, b3648, b3649, b3650, b3651, b3652, b3653, b3654, b3655, b3656, b3657, b3658, b3659, b3660, b3661, b3662, b3663, b3664, b3665, b3666, b3667, b3668, b3669, b3670, b3671, b3672, b3673, b3674, b3675, b3676, b3677, b3678, b3679, b3680, b3681, b3682, b3683, b3684, b3685, b3686, b3687, b3688, b3689, b3690, b3691, b3692, b3693, b3694, b3695, b3696, b3697, b3698, b3699, + b3700, b3701, b3702, b3703, b3704, b3705, b3706, b3707, b3708, b3709, b3710, b3711, b3712, b3713, b3714, b3715, b3716, b3717, b3718, b3719, b3720, b3721, b3722, b3723, b3724, b3725, b3726, b3727, b3728, b3729, b3730, b3731, b3732, b3733, b3734, b3735, b3736, b3737, b3738, b3739, b3740, b3741, b3742, b3743, b3744, b3745, b3746, b3747, b3748, b3749, b3750, b3751, b3752, b3753, b3754, b3755, b3756, b3757, b3758, b3759, b3760, b3761, b3762, b3763, b3764, b3765, b3766, b3767, b3768, b3769, b3770, b3771, b3772, b3773, b3774, b3775, b3776, b3777, b3778, b3779, b3780, b3781, b3782, b3783, b3784, b3785, b3786, b3787, b3788, b3789, b3790, b3791, b3792, b3793, b3794, b3795, b3796, b3797, b3798, b3799, + b3800, b3801, b3802, b3803, b3804, b3805, b3806, b3807, b3808, b3809, b3810, b3811, b3812, b3813, b3814, b3815, b3816, b3817, b3818, b3819, b3820, b3821, b3822, b3823, b3824, b3825, b3826, b3827, b3828, b3829, b3830, b3831, b3832, b3833, b3834, b3835, b3836, b3837, b3838, b3839, b3840, b3841, b3842, b3843, b3844, b3845, b3846, b3847, b3848, b3849, b3850, b3851, b3852, b3853, b3854, b3855, b3856, b3857, b3858, b3859, b3860, b3861, b3862, b3863, b3864, b3865, b3866, b3867, b3868, b3869, b3870, b3871, b3872, b3873, b3874, b3875, b3876, b3877, b3878, b3879, b3880, b3881, b3882, b3883, b3884, b3885, b3886, b3887, b3888, b3889, b3890, b3891, b3892, b3893, b3894, b3895, b3896, b3897, b3898, b3899, + b3900, b3901, b3902, b3903, b3904, b3905, b3906, b3907, b3908, b3909, b3910, b3911, b3912, b3913, b3914, b3915, b3916, b3917, b3918, b3919, b3920, b3921, b3922, b3923, b3924, b3925, b3926, b3927, b3928, b3929, b3930, b3931, b3932, b3933, b3934, b3935, b3936, b3937, b3938, b3939, b3940, b3941, b3942, b3943, b3944, b3945, b3946, b3947, b3948, b3949, b3950, b3951, b3952, b3953, b3954, b3955, b3956, b3957, b3958, b3959, b3960, b3961, b3962, b3963, b3964, b3965, b3966, b3967, b3968, b3969, b3970, b3971, b3972, b3973, b3974, b3975, b3976, b3977, b3978, b3979, b3980, b3981, b3982, b3983, b3984, b3985, b3986, b3987, b3988, b3989, b3990, b3991, b3992, b3993, b3994, b3995, b3996, b3997, b3998, b3999, + b4000, b4001, b4002, b4003, b4004, b4005, b4006, b4007, b4008, b4009, b4010, b4011, b4012, b4013, b4014, b4015, b4016, b4017, b4018, b4019, b4020, b4021, b4022, b4023, b4024, b4025, b4026, b4027, b4028, b4029, b4030, b4031, b4032, b4033, b4034, b4035, b4036, b4037, b4038, b4039, b4040, b4041, b4042, b4043, b4044, b4045, b4046, b4047, b4048, b4049, b4050, b4051, b4052, b4053, b4054, b4055, b4056, b4057, b4058, b4059, b4060, b4061, b4062, b4063, b4064, b4065, b4066, b4067, b4068, b4069, b4070, b4071, b4072, b4073, b4074, b4075, b4076, b4077, b4078, b4079, b4080, b4081, b4082, b4083, b4084, b4085, b4086, b4087, b4088, b4089, b4090, b4091, b4092, b4093, b4094, b4095, b4096, b4097, b4098, b4099; + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/TestCallDevirtualizationWithInfiniteLoop.java b/test/hotspot/jtreg/compiler/c2/TestCallDevirtualizationWithInfiniteLoop.java new file mode 100644 index 0000000000000..1afbe8d94653e --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestCallDevirtualizationWithInfiniteLoop.java @@ -0,0 +1,76 @@ +/* + * 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 8336726 + * @summary Test that post-parse call devirtualization works when call does not have an IO projection. + * @run main/othervm -XX:-TieredCompilation -Xcomp -XX:CompileCommand=compileonly,TestCallDevirtualizationWithInfiniteLoop::test + * TestCallDevirtualizationWithInfiniteLoop + */ + +public class TestCallDevirtualizationWithInfiniteLoop { + + static interface I { + public void method(); + } + + static final class A implements I { + @Override + public void method() { }; + } + + static final class B implements I { + @Override + public void method() { }; + } + + static final A a = new A(); + static final B b = new B(); + + public static void test(boolean flag) { + // Avoid executing endless loop + if (flag) { + return; + } + + // We only know after loop opts that the receiver type is B. + I recv = a; + for (int i = 0; i < 3; ++i) { + if (i > 1) { + recv = b; + } + } + // Post-parse call devirtualization will then convert below + // virtual call to a static call. + recv.method(); + + // Endless loop which does not use IO. As a result the IO + // projection of the call is removed unexpectedly. + while (true) { } + } + + public static void main(String[] args) { + test(true); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java b/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java index 60086dba32713..3d4584714d757 100644 --- a/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java +++ b/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java @@ -36,6 +36,7 @@ * -XX:CompileCommand=inline,*String*::* * -XX:CompileCommand=dontinline,*StringBuilder*::ensureCapacityInternal * -XX:CompileCommand=dontinline,*String*::substring + * -XX:CompileCommand=MemLimit,*.*,0 * -XX:NodeCountInliningCutoff=220000 * -XX:DesiredMethodLimit=100000 * compiler.c2.TestScalarReplacementMaxLiveNodes diff --git a/test/hotspot/jtreg/compiler/c2/TestSerialAdditions.java b/test/hotspot/jtreg/compiler/c2/TestSerialAdditions.java new file mode 100644 index 0000000000000..c52f17dd9757b --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestSerialAdditions.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2024 Red Hat and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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; + +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +import java.util.Random; + +/* + * @test + * @bug 8325495 + * @summary C2 should optimize for series of Add of unique value. e.g., a + a + ... + a => a*n + * @library /test/lib / + * @run driver compiler.c2.TestSerialAdditions + */ +public class TestSerialAdditions { + private static final Random RNG = Utils.getRandomInstance(); + + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = { + "addTo2", + "addTo3", + "addTo4", + "shiftAndAddTo4", + "mulAndAddTo4", + "addTo5", + "addTo6", + "addTo7", + "addTo8", + "addTo16", + "addAndShiftTo16", + "addTo42", + "mulAndAddTo42", + "mulAndAddToMax", + "mulAndAddToOverflow", + "mulAndAddToZero", + "mulAndAddToMinus1", + "mulAndAddToMinus42" + }) + private void runIntTests() { + for (int a : new int[] { 0, 1, Integer.MIN_VALUE, Integer.MAX_VALUE, RNG.nextInt() }) { + Asserts.assertEQ(a * 2, addTo2(a)); + Asserts.assertEQ(a * 3, addTo3(a)); + Asserts.assertEQ(a * 4, addTo4(a)); + Asserts.assertEQ(a * 4, shiftAndAddTo4(a)); + Asserts.assertEQ(a * 4, mulAndAddTo4(a)); + Asserts.assertEQ(a * 5, addTo5(a)); + Asserts.assertEQ(a * 6, addTo6(a)); + Asserts.assertEQ(a * 7, addTo7(a)); + Asserts.assertEQ(a * 8, addTo8(a)); + Asserts.assertEQ(a * 16, addTo16(a)); + Asserts.assertEQ(a * 16, addAndShiftTo16(a)); + Asserts.assertEQ(a * 42, addTo42(a)); + Asserts.assertEQ(a * 42, mulAndAddTo42(a)); + Asserts.assertEQ(a * Integer.MAX_VALUE, mulAndAddToMax(a)); + Asserts.assertEQ(a * Integer.MIN_VALUE, mulAndAddToOverflow(a)); + Asserts.assertEQ(0, mulAndAddToZero(a)); + Asserts.assertEQ(a * -1, mulAndAddToMinus1(a)); + Asserts.assertEQ(a * -42, mulAndAddToMinus42(a)); + } + } + + @Run(test = { + "mulAndAddToIntOverflowL", + "mulAndAddToMaxL", + "mulAndAddToOverflowL" + }) + private void runLongTests() { + for (long a : new long[] { 0, 1, Long.MIN_VALUE, Long.MAX_VALUE, RNG.nextLong() }) { + Asserts.assertEQ(a * (Integer.MAX_VALUE + 1L), mulAndAddToIntOverflowL(a)); + Asserts.assertEQ(a * Long.MAX_VALUE, mulAndAddToMaxL(a)); + Asserts.assertEQ(a * Long.MIN_VALUE, mulAndAddToOverflowL(a)); + } + } + + // ----- integer tests ----- + @Test + @IR(counts = { IRNode.ADD_I, "1" }) + @IR(failOn = IRNode.LSHIFT_I) + private static int addTo2(int a) { + return a + a; // Simple additions like a + a should be kept as-is + } + + @Test + @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "1" }) + private static int addTo3(int a) { + return a + a + a; // a*3 => (a<<1) + a + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int addTo4(int a) { + return a + a + a + a; // a*4 => a<<2 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int shiftAndAddTo4(int a) { + return (a << 1) + a + a; // a*2 + a + a => a*3 + a => a*4 => a<<2 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int mulAndAddTo4(int a) { + return a * 3 + a; // a*4 => a<<2 + } + + @Test + @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "1" }) + private static int addTo5(int a) { + return a + a + a + a + a; // a*5 => (a<<2) + a + } + + @Test + @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "2" }) + private static int addTo6(int a) { + return a + a + a + a + a + a; // a*6 => (a<<1) + (a<<2) + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1", IRNode.SUB_I, "1" }) + private static int addTo7(int a) { + return a + a + a + a + a + a + a; // a*7 => (a<<3) - a + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int addTo8(int a) { + return a + a + a + a + a + a + a + a; // a*8 => a<<3 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int addTo16(int a) { + return a + a + a + a + a + a + a + a + a + a + + a + a + a + a + a + a; // a*16 => a<<4 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int addAndShiftTo16(int a) { + return (a + a) << 3; // a<<(3 + 1) => a<<4 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.MUL_I, "1" }) + private static int addTo42(int a) { + return a + a + a + a + a + a + a + a + a + a + + a + a + a + a + a + a + a + a + a + a + + a + a + a + a + a + a + a + a + a + a + + a + a + a + a + a + a + a + a + a + a + + a + a; // a*42 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.MUL_I, "1" }) + private static int mulAndAddTo42(int a) { + return a * 40 + a + a; // a*41 + a => a*42 + } + + private static final int INT_MAX_MINUS_ONE = Integer.MAX_VALUE - 1; + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1", IRNode.SUB_I, "1" }) + private static int mulAndAddToMax(int a) { + return a * INT_MAX_MINUS_ONE + a; // a*MAX => a*(MIN-1) => a*MIN - a => (a<<31) - a + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int mulAndAddToOverflow(int a) { + return a * Integer.MAX_VALUE + a; // a*(MAX+1) => a*(MIN) => a<<31 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.CON_I, "1" }) + private static int mulAndAddToZero(int a) { + return a * -1 + a; // 0 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1", IRNode.SUB_I, "1" }) + private static int mulAndAddToMinus1(int a) { + return a * -2 + a; // a*-1 => a - (a<<1) + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.MUL_I, "1" }) + private static int mulAndAddToMinus42(int a) { + return a * -43 + a; // a*-42 + } + + // --- long tests --- + @Test + @IR(failOn = IRNode.ADD_L) + @IR(counts = { IRNode.LSHIFT_L, "1" }) + private static long mulAndAddToIntOverflowL(long a) { + return a * Integer.MAX_VALUE + a; // a*(INT_MAX+1) + } + + private static final long LONG_MAX_MINUS_ONE = Long.MAX_VALUE - 1; + + @Test + @IR(failOn = IRNode.ADD_L) + @IR(counts = { IRNode.LSHIFT_L, "1", IRNode.SUB_L, "1" }) + private static long mulAndAddToMaxL(long a) { + return a * LONG_MAX_MINUS_ONE + a; // a*MAX => a*(MIN-1) => a*MIN - 1 => (a<<63) - 1 + } + + @Test + @IR(failOn = IRNode.ADD_L) + @IR(counts = { IRNode.LSHIFT_L, "1" }) + private static long mulAndAddToOverflowL(long a) { + return a * Long.MAX_VALUE + a; // a*(MAX+1) => a*(MIN) => a<<63 + } +} diff --git a/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java b/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java index 033ea49e60955..d05dbad4a73ba 100644 --- a/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java +++ b/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java @@ -46,11 +46,20 @@ public class TestUnalignedAccess { static final Unsafe UNSAFE = Unsafe.getUnsafe(); static void sink(int x) {} + public static long lseed = 1; + public static int iseed = 2; + public static short sseed = 3; + public static byte bseed = 4; + public static long lres = lseed; + public static int ires = iseed; + public static short sres = sseed; + public static byte bres = bseed; + public static class TestLong { private static final byte[] BYTES = new byte[LEN]; private static final long rawdata = 0xbeef; - private static final long lseed = 1; + private static final long data; static { sink(2); @@ -60,10 +69,13 @@ public static class TestLong { // 1030 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putLongUnaligned(BYTES, 1030, rawdata); + lres += UNSAFE.getLongUnaligned(BYTES, 1030); // 127 can be encoded into simm9 field. - UNSAFE.putLongUnaligned(BYTES, 127, rawdata+lseed); + UNSAFE.putLongUnaligned(BYTES, 127, lres); + lres += UNSAFE.getLongUnaligned(BYTES, 127); // 1096 can be encoded into uimm12 field. - UNSAFE.putLongUnaligned(BYTES, 1096, rawdata-lseed); + UNSAFE.putLongUnaligned(BYTES, 1096, lres); + data = UNSAFE.getLongUnaligned(BYTES, 1096); } } @@ -72,7 +84,7 @@ public static class TestInt { private static final byte[] BYTES = new byte[LEN]; private static final int rawdata = 0xbeef; - private static final int iseed = 2; + private static final int data; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -81,10 +93,13 @@ public static class TestInt { // 274 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putIntUnaligned(BYTES, 274, rawdata); + ires += UNSAFE.getIntUnaligned(BYTES, 274); // 255 can be encoded into simm9 field. - UNSAFE.putIntUnaligned(BYTES, 255, rawdata + iseed); + UNSAFE.putIntUnaligned(BYTES, 255, ires); + ires += UNSAFE.getIntUnaligned(BYTES, 255); // 528 can be encoded into uimm12 field. - UNSAFE.putIntUnaligned(BYTES, 528, rawdata - iseed); + UNSAFE.putIntUnaligned(BYTES, 528, ires); + data = UNSAFE.getIntUnaligned(BYTES, 528); } } @@ -93,7 +108,7 @@ public static class TestShort { private static final byte[] BYTES = new byte[LEN]; private static final short rawdata = (short)0xbeef; - private static final short sseed = 3; + private static final short data; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -102,10 +117,13 @@ public static class TestShort { // 257 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putShortUnaligned(BYTES, 257, rawdata); + sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 257)); // 253 can be encoded into simm9 field. - UNSAFE.putShortUnaligned(BYTES, 253, (short) (rawdata + sseed)); + UNSAFE.putShortUnaligned(BYTES, 253, sres); + sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 253)); // 272 can be encoded into uimm12 field. - UNSAFE.putShortUnaligned(BYTES, 272, (short) (rawdata - sseed)); + UNSAFE.putShortUnaligned(BYTES, 272, sres); + data = UNSAFE.getShortUnaligned(BYTES, 272); } } @@ -114,7 +132,7 @@ public static class TestByte { private static final byte[] BYTES = new byte[LEN]; private static final byte rawdata = (byte)0x3f; - private static final byte bseed = 4; + private static final byte data; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -123,34 +141,29 @@ public static class TestByte { // 272 can be encoded into simm9 field. UNSAFE.putByte(BYTES, 272, rawdata); + bres = (byte) (bres + UNSAFE.getByte(BYTES, 272)); // 53 can be encoded into simm9 field. - UNSAFE.putByte(BYTES, 53, (byte) (rawdata + bseed)); + UNSAFE.putByte(BYTES, 53, bres); + bres = (byte) (bres + UNSAFE.getByte(BYTES, 53)); // 1027 can be encoded into uimm12 field. - UNSAFE.putByte(BYTES, 1027, (byte) (rawdata - bseed)); + UNSAFE.putByte(BYTES, 1027, bres); + data = UNSAFE.getByte(BYTES, 1027); } } static void test() { TestLong ta = new TestLong(); - Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 1030), ta.rawdata, "putUnaligned long failed!"); - Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 127), ta.rawdata + ta.lseed, "putUnaligned long failed!"); - Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 1096), ta.rawdata - ta.lseed, "putUnaligned long failed!"); + Asserts.assertEquals(ta.data, (ta.rawdata + lseed) * 2, "putUnaligned long failed!"); TestInt tb = new TestInt(); - Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 274), tb.rawdata, "putUnaligned int failed!"); - Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 255), tb.rawdata + tb.iseed, "putUnaligned int failed!"); - Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 528), tb.rawdata - tb.iseed, "putUnaligned int failed!"); + Asserts.assertEquals(tb.data, (tb.rawdata + iseed) * 2, "putUnaligned int failed!"); TestShort tc = new TestShort(); - Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 257), tc.rawdata, "putUnaligned short failed!"); - Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 253), (short) (tc.rawdata + tc.sseed), "putUnaligned short failed!"); - Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 272), (short) (tc.rawdata - tc.sseed), "putUnaligned short failed!"); + Asserts.assertEquals(tc.data, (short) (((short) (tc.rawdata + sseed)) * 2), "putUnaligned short failed!"); TestByte td = new TestByte(); - Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 272), td.rawdata, "put byte failed!"); - Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 53), (byte) (td.rawdata + td.bseed), "put byte failed!"); - Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 1027), (byte) (td.rawdata - td.bseed), "put byte failed!"); + Asserts.assertEquals(td.data, (byte) (((byte) (td.rawdata + bseed)) * 2), "put byte failed!"); } public static void main(String[] strArr) { diff --git a/test/hotspot/jtreg/compiler/c2/TestUnresolvedConstantDynamic.java b/test/hotspot/jtreg/compiler/c2/TestUnresolvedConstantDynamic.java new file mode 100644 index 0000000000000..e5879eb88a175 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestUnresolvedConstantDynamic.java @@ -0,0 +1,42 @@ +/* + * 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 8339694 + * @summary Test compilation of unresolved constant dynamics. + * @library /test/lib + * @compile TestUnresolvedConstantDynamicHelper.jasm + * @run driver TestUnresolvedConstantDynamic + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileCommand=compileonly,TestUnresolvedConstantDynamicHelper::test* TestUnresolvedConstantDynamic + */ + +import jdk.test.lib.Asserts; + +public class TestUnresolvedConstantDynamic { + + public static void main(String[] args) { + Asserts.assertEquals(TestUnresolvedConstantDynamicHelper.testBooleanArray(true)[0], true); + Asserts.assertEquals(TestUnresolvedConstantDynamicHelper.testStringArray("42")[0], "42"); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/TestUnresolvedConstantDynamicHelper.jasm b/test/hotspot/jtreg/compiler/c2/TestUnresolvedConstantDynamicHelper.jasm new file mode 100644 index 0000000000000..e633065b26d16 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestUnresolvedConstantDynamicHelper.jasm @@ -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. + * + */ + +public class TestUnresolvedConstantDynamicHelper version 55:0 { + public Method "":"()V" stack 1 locals 1 { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + private static Method newBooleanArray:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)[Z" stack 1 locals 3 { + iconst_1; + newarray boolean; + areturn; + } + + private static Method newStringArray:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)[Ljava/lang/String;" stack 1 locals 3 { + iconst_1; + anewarray class java/lang/String; + areturn; + } + + public static Method testBooleanArray:"(Z)[Z" stack 4 locals 2 { + ldc Dynamic REF_invokeStatic:TestUnresolvedConstantDynamicHelper.newBooleanArray:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)[Z":name:"[Z"; + dup; + iconst_0; + iload_0; + bastore; + areturn; + } + + public static Method testStringArray:"(Ljava/lang/String;)[Ljava/lang/String;" stack 4 locals 2 { + ldc Dynamic REF_invokeStatic:TestUnresolvedConstantDynamicHelper.newStringArray:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)[Ljava/lang/String;":name:"[Ljava/lang/String;"; + dup; + iconst_0; + aload_0; + aastore; + areturn; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java index 23b9321fc35c1..3f82c3e00b3ac 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java @@ -261,20 +261,11 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useCompr }; break; case "G1": - // a card mark volatile barrier should be generated - // before the card mark strb - // - // following the fix for 8225776 the G1 barrier is now - // scheduled out of line after the membar volatile and - // and subsequent return matches = new String[] { "membar_release \\(elided\\)", useCompressedOops ? "stlrw?" : "stlr", "membar_volatile \\(elided\\)", - "ret", - "membar_volatile", - "dmb ish", - "strb" + "ret" }; break; case "Shenandoah": @@ -332,20 +323,11 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useCompres }; break; case "G1": - // a card mark volatile barrier should be generated - // before the card mark strb - // - // following the fix for 8225776 the G1 barrier is now - // scheduled out of line after the membar acquire and - // and subsequent return matches = new String[] { "membar_release \\(elided\\)", useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", "membar_acquire \\(elided\\)", - "ret", - "membar_volatile", - "dmb ish", - "strb" + "ret" }; break; case "Shenandoah": @@ -418,20 +400,11 @@ private void checkcae(OutputAnalyzer output, String testType, boolean useCompres return; case "G1": - // a card mark volatile barrier should be generated - // before the card mark strb - // - // following the fix for 8225776 the G1 barrier is now - // scheduled out of line after the membar acquire and - // and subsequent return matches = new String[] { "membar_release \\(elided\\)", useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", "membar_acquire \\(elided\\)", - "ret", - "membar_volatile", - "dmb ish", - "strb" + "ret" }; break; case "Shenandoah": @@ -484,20 +457,11 @@ private void checkgas(OutputAnalyzer output, String testType, boolean useCompres }; break; case "G1": - // a card mark volatile barrier should be generated - // before the card mark strb - // - // following the fix for 8225776 the G1 barrier is now - // scheduled out of line after the membar acquire and - // and subsequent return matches = new String[] { "membar_release \\(elided\\)", useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq", "membar_acquire \\(elided\\)", - "ret", - "membar_volatile", - "dmb ish", - "strb" + "ret" }; break; case "Shenandoah": diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestPadding.java b/test/hotspot/jtreg/compiler/c2/irTests/TestPadding.java index 25225e86b2846..17b2817a9a29d 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestPadding.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestPadding.java @@ -48,7 +48,7 @@ public static void test_runner() { } @Test - @IR(counts = { IRNode.NOP, "1" }) + @IR(counts = { IRNode.NOP, "<=1" }) static int test(int i) { TestPadding tp = tpf; if (tp.b1 > 42) { // Big 'cmpb' instruction at offset 0x30 diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java index b68ddfe2799ce..2d17753ba941b 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +36,6 @@ * @test * @bug 8300258 * @key randomness - * @requires (os.simpleArch == "x64") | (os.simpleArch == "aarch64") * @summary C2: vectorization fails on simple ByteBuffer loop * @modules java.base/jdk.internal.misc * @library /test/lib / @@ -50,9 +50,6 @@ public class TestVectorizationMismatchedAccess { private final static WhiteBox wb = WhiteBox.getWhiteBox(); public static void main(String[] args) { - if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) { - throw new RuntimeException("fix test that was written for a little endian platform"); - } TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"); } @@ -77,6 +74,14 @@ public static void main(String[] args) { } } + // Method to adjust the value for the native byte order + static private long handleByteOrder(long value) { + if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) { + value = Long.reverseBytes(value); + } + return value; + } + static private void runAndVerify(Runnable test, int offset) { System.arraycopy(verifyLongArray, 0, longArray, 0, longArray.length); Arrays.fill(byteArray, (byte)0); @@ -147,193 +152,420 @@ static private void runAndVerify3(Runnable test, int offset) { } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteLong1(byte[] dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteLong1a(byte[] dest, long[] src) { + for (int i = 0; i < src.length; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i, handleByteOrder(src[i])); + } + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteLong1b(byte[] dest, long[] src) { for (int i = 0; i < src.length; i++) { - UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i, src[i]); + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i, handleByteOrder(src[i])); } } - @Run(test = "testByteLong1") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + public static void testByteLong1c(byte[] dest, long[] src) { + long base = 64; // make sure it is big enough and 8 byte aligned (required for 32-bit) + for (int i = 0; i < src.length - 8; i++) { + UNSAFE.putLongUnaligned(dest, base + 8 * i, handleByteOrder(src[i])); + } + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteLong1d(byte[] dest, long[] src) { + long base = 64; // make sure it is big enough and 8 byte aligned (required for 32-bit) + for (int i = 0; i < src.length - 8; i++) { + UNSAFE.putLongUnaligned(dest, base + 8L * i, handleByteOrder(src[i])); + } + } + + @Run(test = {"testByteLong1a", "testByteLong1b", "testByteLong1c", "testByteLong1d"}) public static void testByteLong1_runner() { - runAndVerify(() -> testByteLong1(byteArray, longArray), 0); + runAndVerify(() -> testByteLong1a(byteArray, longArray), 0); + runAndVerify(() -> testByteLong1b(byteArray, longArray), 0); + testByteLong1c(byteArray, longArray); + testByteLong1d(byteArray, longArray); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteLong2a(byte[] dest, long[] src) { + for (int i = 1; i < src.length; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i - 1), handleByteOrder(src[i])); + } } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteLong2(byte[] dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteLong2b(byte[] dest, long[] src) { for (int i = 1; i < src.length; i++) { - UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i - 1), src[i]); + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i - 1), handleByteOrder(src[i])); } } - @Run(test = "testByteLong2") + @Run(test = {"testByteLong2a", "testByteLong2b"}) public static void testByteLong2_runner() { - runAndVerify(() -> testByteLong2(byteArray, longArray), -8); + runAndVerify(() -> testByteLong2a(byteArray, longArray), -8); + runAndVerify(() -> testByteLong2b(byteArray, longArray), -8); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteLong3a(byte[] dest, long[] src) { + for (int i = 0; i < src.length - 1; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + 1), handleByteOrder(src[i])); + } } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteLong3(byte[] dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteLong3b(byte[] dest, long[] src) { for (int i = 0; i < src.length - 1; i++) { - UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + 1), src[i]); + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + 1), handleByteOrder(src[i])); } } - @Run(test = "testByteLong3") + @Run(test = {"testByteLong3a", "testByteLong3b"}) public static void testByteLong3_runner() { - runAndVerify(() -> testByteLong3(byteArray, longArray), 8); + runAndVerify(() -> testByteLong3a(byteArray, longArray), 8); + runAndVerify(() -> testByteLong3b(byteArray, longArray), 8); } @Test @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, applyIf = {"AlignVector", "false"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. // AlignVector cannot guarantee that invar is aligned. - public static void testByteLong4(byte[] dest, long[] src, int start, int stop) { + public static void testByteLong4a(byte[] dest, long[] src, int start, int stop) { for (int i = start; i < stop; i++) { - UNSAFE.putLongUnaligned(dest, 8 * i + baseOffset, src[i]); + UNSAFE.putLongUnaligned(dest, 8 * i + baseOffset, handleByteOrder(src[i])); } } - @Run(test = "testByteLong4") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + // AlignVector cannot guarantee that invar is aligned. + public static void testByteLong4b(byte[] dest, long[] src, int start, int stop) { + for (int i = start; i < stop; i++) { + UNSAFE.putLongUnaligned(dest, 8L * i + baseOffset, handleByteOrder(src[i])); + } + } + + @Run(test = {"testByteLong4a", "testByteLong4b"}) public static void testByteLong4_runner() { baseOffset = UNSAFE.ARRAY_BYTE_BASE_OFFSET; - runAndVerify(() -> testByteLong4(byteArray, longArray, 0, size), 0); + runAndVerify(() -> testByteLong4a(byteArray, longArray, 0, size), 0); + runAndVerify(() -> testByteLong4b(byteArray, longArray, 0, size), 0); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteLong5(byte[] dest, long[] src, int start, int stop) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteLong5a(byte[] dest, long[] src, int start, int stop) { for (int i = start; i < stop; i++) { - UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + baseOffset), src[i]); + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + baseOffset), handleByteOrder(src[i])); } } - @Run(test = "testByteLong5") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteLong5b(byte[] dest, long[] src, int start, int stop) { + for (int i = start; i < stop; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + baseOffset), handleByteOrder(src[i])); + } + } + + @Run(test = {"testByteLong5a", "testByteLong5b"}) public static void testByteLong5_runner() { baseOffset = 1; - runAndVerify(() -> testByteLong5(byteArray, longArray, 0, size-1), 8); + runAndVerify(() -> testByteLong5a(byteArray, longArray, 0, size-1), 8); + runAndVerify(() -> testByteLong5b(byteArray, longArray, 0, size-1), 8); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteByte1(byte[] dest, byte[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteByte1a(byte[] dest, byte[] src) { for (int i = 0; i < src.length / 8; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); } } - @Run(test = "testByteByte1") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteByte1b(byte[] dest, byte[] src) { + for (int i = 0; i < src.length / 8; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); + } + } + + @Run(test = {"testByteByte1a", "testByteByte1b"}) public static void testByteByte1_runner() { - runAndVerify2(() -> testByteByte1(byteArray, byteArray), 0); + runAndVerify2(() -> testByteByte1a(byteArray, byteArray), 0); + runAndVerify2(() -> testByteByte1b(byteArray, byteArray), 0); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteByte2(byte[] dest, byte[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteByte2a(byte[] dest, byte[] src) { for (int i = 1; i < src.length / 8; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i - 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); } } - @Run(test = "testByteByte2") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteByte2b(byte[] dest, byte[] src) { + for (int i = 1; i < src.length / 8; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i - 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); + } + } + + @Run(test = {"testByteByte2a", "testByteByte2b"}) public static void testByteByte2_runner() { - runAndVerify2(() -> testByteByte2(byteArray, byteArray), -8); + runAndVerify2(() -> testByteByte2a(byteArray, byteArray), -8); + runAndVerify2(() -> testByteByte2b(byteArray, byteArray), -8); } @Test @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) - public static void testByteByte3(byte[] dest, byte[] src) { + public static void testByteByte3a(byte[] dest, byte[] src) { for (int i = 0; i < src.length / 8 - 1; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); } } - @Run(test = "testByteByte3") + @Test + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + public static void testByteByte3b(byte[] dest, byte[] src) { + for (int i = 0; i < src.length / 8 - 1; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); + } + } + + @Run(test = {"testByteByte3a", "testByteByte3b"}) public static void testByteByte3_runner() { - runAndVerify2(() -> testByteByte3(byteArray, byteArray), 8); + runAndVerify2(() -> testByteByte3a(byteArray, byteArray), 8); + runAndVerify2(() -> testByteByte3b(byteArray, byteArray), 8); } @Test @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) - public static void testByteByte4(byte[] dest, byte[] src, int start, int stop) { + public static void testByteByte4a(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, 8 * i + baseOffset, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); } } - @Run(test = "testByteByte4") + @Test + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + public static void testByteByte4b(byte[] dest, byte[] src, int start, int stop) { + for (int i = start; i < stop; i++) { + UNSAFE.putLongUnaligned(dest, 8L * i + baseOffset, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); + } + } + + @Run(test = {"testByteByte4a", "testByteByte4b"}) public static void testByteByte4_runner() { baseOffset = UNSAFE.ARRAY_BYTE_BASE_OFFSET; - runAndVerify2(() -> testByteByte4(byteArray, byteArray, 0, size), 0); + runAndVerify2(() -> testByteByte4a(byteArray, byteArray, 0, size), 0); + runAndVerify2(() -> testByteByte4b(byteArray, byteArray, 0, size), 0); } @Test @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) - public static void testByteByte5(byte[] dest, byte[] src, int start, int stop) { + public static void testByteByte5a(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + baseOffset), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); } } - @Run(test = "testByteByte5") + @Test + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + public static void testByteByte5b(byte[] dest, byte[] src, int start, int stop) { + for (int i = start; i < stop; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + baseOffset), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); + } + } + + @Run(test = {"testByteByte5a", "testByteByte5b"}) public static void testByteByte5_runner() { baseOffset = 1; - runAndVerify2(() -> testByteByte5(byteArray, byteArray, 0, size-1), 8); + runAndVerify2(() -> testByteByte5a(byteArray, byteArray, 0, size-1), 8); + runAndVerify2(() -> testByteByte5b(byteArray, byteArray, 0, size-1), 8); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testOffHeapLong1(long dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P(dest + 8 * (i + int_con)) + // See: JDK-8331576 + public static void testOffHeapLong1a(long dest, long[] src) { for (int i = 0; i < src.length; i++) { - UNSAFE.putLongUnaligned(null, dest + 8 * i, src[i]); + UNSAFE.putLongUnaligned(null, dest + 8 * i, handleByteOrder(src[i])); } } - @Run(test = "testOffHeapLong1") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P(dest + 8L * (i + int_con)) + // See: JDK-8331576 + public static void testOffHeapLong1b(long dest, long[] src) { + for (int i = 0; i < src.length; i++) { + UNSAFE.putLongUnaligned(null, dest + 8L * i, handleByteOrder(src[i])); + } + } + + @Run(test = {"testOffHeapLong1a", "testOffHeapLong1b"}) public static void testOffHeapLong1_runner() { - runAndVerify3(() -> testOffHeapLong1(baseOffHeap, longArray), 0); + runAndVerify3(() -> testOffHeapLong1a(baseOffHeap, longArray), 0); + runAndVerify3(() -> testOffHeapLong1b(baseOffHeap, longArray), 0); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P + // See: JDK-8331576 + public static void testOffHeapLong2a(long dest, long[] src) { + for (int i = 1; i < src.length; i++) { + UNSAFE.putLongUnaligned(null, dest + 8 * (i - 1), handleByteOrder(src[i])); + } } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testOffHeapLong2(long dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P + // See: JDK-8331576 + public static void testOffHeapLong2b(long dest, long[] src) { for (int i = 1; i < src.length; i++) { - UNSAFE.putLongUnaligned(null, dest + 8 * (i - 1), src[i]); + UNSAFE.putLongUnaligned(null, dest + 8L * (i - 1), handleByteOrder(src[i])); } } - @Run(test = "testOffHeapLong2") + @Run(test = {"testOffHeapLong2a", "testOffHeapLong2b"}) public static void testOffHeapLong2_runner() { - runAndVerify3(() -> testOffHeapLong2(baseOffHeap, longArray), -8); + runAndVerify3(() -> testOffHeapLong2a(baseOffHeap, longArray), -8); + runAndVerify3(() -> testOffHeapLong2b(baseOffHeap, longArray), -8); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testOffHeapLong3(long dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P + // See: JDK-8331576 + public static void testOffHeapLong3a(long dest, long[] src) { for (int i = 0; i < src.length - 1; i++) { - UNSAFE.putLongUnaligned(null, dest + 8 * (i + 1), src[i]); + UNSAFE.putLongUnaligned(null, dest + 8 * (i + 1), handleByteOrder(src[i])); } } - @Run(test = "testOffHeapLong3") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P + // See: JDK-8331576 + public static void testOffHeapLong3b(long dest, long[] src) { + for (int i = 0; i < src.length - 1; i++) { + UNSAFE.putLongUnaligned(null, dest + 8L * (i + 1), handleByteOrder(src[i])); + } + } + + @Run(test = {"testOffHeapLong3a", "testOffHeapLong3b"}) public static void testOffHeapLong3_runner() { - runAndVerify3(() -> testOffHeapLong3(baseOffHeap, longArray), 8); + runAndVerify3(() -> testOffHeapLong3a(baseOffHeap, longArray), 8); + runAndVerify3(() -> testOffHeapLong3b(baseOffHeap, longArray), 8); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, - applyIf = {"AlignVector", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + // applyIf = {"AlignVector", "false"}) + // FAILS: adr is CastX2P + // See: JDK-8331576 + // AlignVector cannot guarantee that invar is aligned. + public static void testOffHeapLong4a(long dest, long[] src, int start, int stop) { + for (int i = start; i < stop; i++) { + UNSAFE.putLongUnaligned(null, dest + 8 * i + baseOffset, handleByteOrder(src[i])); + } + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + // applyIf = {"AlignVector", "false"}) + // FAILS: adr is CastX2P + // See: JDK-8331576 // AlignVector cannot guarantee that invar is aligned. - public static void testOffHeapLong4(long dest, long[] src, int start, int stop) { + public static void testOffHeapLong4b(long dest, long[] src, int start, int stop) { for (int i = start; i < stop; i++) { - UNSAFE.putLongUnaligned(null, dest + 8 * i + baseOffset, src[i]); + UNSAFE.putLongUnaligned(null, dest + 8L * i + baseOffset, handleByteOrder(src[i])); } } - @Run(test = "testOffHeapLong4") + @Run(test = {"testOffHeapLong4a", "testOffHeapLong4b"}) public static void testOffHeapLong4_runner() { baseOffset = 8; - runAndVerify3(() -> testOffHeapLong4(baseOffHeap, longArray, 0, size-1), 8); + runAndVerify3(() -> testOffHeapLong4a(baseOffHeap, longArray, 0, size-1), 8); + runAndVerify3(() -> testOffHeapLong4b(baseOffHeap, longArray, 0, size-1), 8); } } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceClearTests.java b/test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceClearTests.java new file mode 100644 index 0000000000000..c56ffc88778ae --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceClearTests.java @@ -0,0 +1,138 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.c2.irTests.gc; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; +import jdk.test.whitebox.gc.GC; + +import java.lang.ref.*; +import java.util.*; + +/* + * @test + * @bug 8329597 + * @summary Test that Reference.clear intrinsics are properly handled + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @requires vm.compiler2.enabled + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI compiler.c2.irTests.gc.ReferenceClearTests + + */ +public class ReferenceClearTests { + + private static String[] args(String... add) { + List args = new ArrayList<>(); + + // Use PerMethodTrapLimit=0 to compile all branches in the intrinsics. + args.add("-XX:PerMethodTrapLimit=0"); + + // Forcefully inline all methods to reach the intrinsic code. + args.add("-XX:CompileCommand=inline,compiler.c2.irTests.gc.ReferenceClearTests::*"); + args.add("-XX:CompileCommand=inline,java.lang.ref.Reference::*"); + args.add("-XX:CompileCommand=inline,java.lang.ref.PhantomReference::*"); + + // Mix in test config code. + args.addAll(Arrays.asList(add)); + + return args.toArray(new String[0]); + } + + public static void main(String[] args) { + TestFramework framework = new TestFramework(); + + int idx = 0; + if (GC.isSelectedErgonomically() && GC.Serial.isSupported()) { + // Serial does not have SATB/keep-alive barriers at all. + // There are inter-generational barriers on stores, but they are + // folded away for null stores like clear(). + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseSerialGC" + ))); + } + if (GC.isSelectedErgonomically() && GC.Parallel.isSupported()) { + // Parallel does not have SATB/keep-alive barriers at all. + // There are inter-generational barriers on stores, but they + // should be folded away for null stores like clear(). + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseParallelGC" + ))); + } + if (GC.isSelectedErgonomically() && GC.G1.isSupported()) { + // G1 does not have barriers in C2 IR. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseG1GC" + ))); + } + if (GC.isSelectedErgonomically() && GC.Shenandoah.isSupported()) { + // Shenandoah has SATB/keep-alive barriers, but they should not be + // present clear()-s. There are load-reference barriers, which would + // confuse the tests, so we enable only SATB barriers. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:ShenandoahGCMode=passive", + "-XX:+ShenandoahSATBBarrier", + "-XX:+UseShenandoahGC" + ))); + } + if (GC.isSelectedErgonomically() && GC.Z.isSupported()) { + // Z does not have barriers in C2 IR. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseZGC" + ))); + } + framework.start(); + } + + static final Object REF = new Object(); + + static final SoftReference SR = new SoftReference<>(REF); + static final WeakReference WR = new WeakReference<>(REF); + static final PhantomReference PR = new PhantomReference<>(REF, null); + + // We assert there is only a single load and a single store of Reference.referent. + // This serves as signal that no GC barriers are emitted in IR. + + @Test + @IR(counts = { IRNode.STORE, "1", + IRNode.LOAD, "1" }) + public void soft() { + SR.clear(); + } + + @Test + @IR(counts = { IRNode.STORE, "1", + IRNode.LOAD, "1" }) + public void weak() { + WR.clear(); + } + + @Test + @IR(counts = { IRNode.STORE, "1", + IRNode.LOAD, "1" }) + public void phantom() { + PR.clear(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java index cd3d5329771ef..69b3cb5274b57 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java @@ -1355,9 +1355,12 @@ int testReReduce(boolean cond, int x, int y) { } @Test - @IR(counts = { IRNode.ALLOC, "1" }) - // The last allocation won't be reduced because it would cause the creation - // of a nested SafePointScalarMergeNode. + // Using G1, all allocations are reduced. + @IR(applyIf = {"UseG1GC", "true"}, failOn = { IRNode.ALLOC }) + // Otherwise, the last allocation won't be reduced because it would cause + // the creation of a nested SafePointScalarMergeNode. This is caused by the + // store barrier corresponding to 'C.other = B'. + @IR(applyIf = {"UseG1GC", "false"}, counts = { IRNode.ALLOC, "1" }) int testReReduce_C2(boolean cond1, int x, int y) { return testReReduce(cond1, x, y); } @DontCompile diff --git a/test/hotspot/jtreg/compiler/controldependency/TestAntiDependencyForPinnedLoads.java b/test/hotspot/jtreg/compiler/controldependency/TestAntiDependencyForPinnedLoads.java new file mode 100644 index 0000000000000..05673015ebe04 --- /dev/null +++ b/test/hotspot/jtreg/compiler/controldependency/TestAntiDependencyForPinnedLoads.java @@ -0,0 +1,44 @@ +/* + * 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 8337066 + * @summary Test that MergeMem is skipped when looking for stores + * @run main/othervm -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,java.lang.StringUTF16::reverse + * compiler.controldependency.TestAntiDependencyForPinnedLoads + */ + +package compiler.controldependency; + +public class TestAntiDependencyForPinnedLoads { + public static void main(String[] args) { + for(int i = 0; i < 50_000; i++) { + String str = "YYYY年MM月DD日"; + StringBuffer strBuffer = new StringBuffer(str); + String revStr = strBuffer.reverse().toString(); + if (!revStr.equals("日DD月MM年YYYY")) throw new InternalError("FAIL"); + } + } +} diff --git a/test/hotspot/jtreg/gc/z/TestDefault.java b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java similarity index 52% rename from test/hotspot/jtreg/gc/z/TestDefault.java rename to test/hotspot/jtreg/compiler/debug/TestStressBailout.java index 1f1b7d49408e7..68610576a390f 100644 --- a/test/hotspot/jtreg/gc/z/TestDefault.java +++ b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java @@ -21,31 +21,39 @@ * questions. */ -package gc.z; +package compiler.debug; + +import java.util.Random; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Utils; /* - * @test TestDefault - * @requires vm.gc.ZGenerational - * @summary Test that ZGC Generational Mode is Default - * @library /test/lib - * @run driver gc.z.TestDefault + * @test + * @key stress randomness + * @bug 8330157 + * @requires vm.debug == true & vm.compiler2.enabled & (vm.opt.AbortVMOnCompilationFailure == "null" | !vm.opt.AbortVMOnCompilationFailure) + * @summary Basic tests for bailout stress flag. + * @library /test/lib / + * @run driver compiler.debug.TestStressBailout */ -import java.util.LinkedList; -import jdk.test.lib.process.ProcessTools; +public class TestStressBailout { -public class TestDefault { - static class Test { - public static void main(String[] args) throws Exception {} + static void runTest(int invprob) throws Exception { + String[] procArgs = {"-Xcomp", "-XX:-TieredCompilation", "-XX:+StressBailout", + "-XX:StressBailoutMean=" + invprob, "-version"}; + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(procArgs); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); } + public static void main(String[] args) throws Exception { - ProcessTools.executeLimitedTestJava("-XX:+UseZGC", - "-Xlog:gc+init", - Test.class.getName()) - .shouldNotContain("Option ZGenerational was deprecated") - .shouldNotContain("Using deprecated non-generational mode") - .shouldContain("GC Workers for Old Generation") - .shouldContain("GC Workers for Young Generation") - .shouldHaveExitValue(0); + Random r = Utils.getRandomInstance(); + // Likely bail out on -version, for some low Mean value. + runTest(r.nextInt(1, 10)); + // Higher value + runTest(r.nextInt(10, 1_000_000)); } } diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestCanReduceCheckUsersDifferentIfs.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestCanReduceCheckUsersDifferentIfs.java new file mode 100644 index 0000000000000..b71f9b2cef2bd --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestCanReduceCheckUsersDifferentIfs.java @@ -0,0 +1,107 @@ +/* + * 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 8343380 + * @summary Test that can_reduce_check_users() can handle different If nodes and that we bail out properly if it's not + * an actual IfNode. + * @run main/othervm -XX:CompileCommand=compileonly,compiler.escapeAnalysis.TestCanReduceCheckUsersDifferentIfs::test* + * -Xcomp compiler.escapeAnalysis.TestCanReduceCheckUsersDifferentIfs + */ + +package compiler.escapeAnalysis; + +public class TestCanReduceCheckUsersDifferentIfs { + static int iFld, iFld2; + static boolean flag; + + public static void main(String[] args) { + // Make sure classes are loaded. + new B(); + new C(); + testParsePredicate(); + testOuterStripMinedLoopEnd(); + } + + static void testOuterStripMinedLoopEnd() { + // (1) phi1 for a: phi(CheckCastPP(B), CheckCastPP(c)) with type A:NotNull + A a = flag ? new B() : new C(); + + // (4) Loop removed in PhaseIdealLoop before EA and we know that x == 77. + int x = 77; + int y = 0; + do { + x--; + y++; + } while (x > 0); + + // (L) + for (int i = 0; i < 100; i++) { + iFld += 34; + } + // (6) CastPP(phi1) ends up at IfFalse of OuterStripMinedLoopEnd of loop (L). + // (7) EA tries to reduce phi1(CheckCastPP(B), CheckCastPP(c)) and looks at + // OuterStripMinedLoopEnd and asserts that if it's not an IfNode that it has + // an OpaqueNotNull which obviously is not the case and the assert fails. + + // (5) Found to be false after PhaseIdealLoop before EA and is folded away. + if (y == 76) { + a = (B) a; // (2) a = CheckCastPP(phi1) + } + // (3) phi2 for a: phi(if, else) = phi(CheckCastPP(phi1), phi1) + // phi(CheckCastPP(phi1), phi1) is replaced in PhiNode::Ideal with a CastPP: + // a = CastPP(phi1) with type A:NotNull + iFld2 = a.iFld; + } + + // Same as testOuterStripMinedLoopEnd() but we find in (7) a ParsePredicate from the + // removed loop (L) which also does not have an OpaqueNotNull and the assert fails. + static void testParsePredicate() { + A a = flag ? new B() : new C(); + + int x = 77; + int y = 0; + // (L) + do { + x--; + y++; + } while (x > 0); + + if (y == 76) { + a = (B) a; + } + iFld2 = a.iFld; + } +} + +class A { + int iFld; +} + +class B extends A { +} + +class C extends A { +} diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndJVMStates.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndJVMStates.java new file mode 100644 index 0000000000000..3b0513003aeff --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndJVMStates.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 8335977 + * @summary Check that Reduce Allocation Merges doesn't crash when there + * is an uncommon_trap with a chain of JVMS and, the reduced phi + * input(s) are local(s) in an old JVMS but not in a younger JVMS. + * I.e., check that we don't lose track of "_is_root" when traversing + * a JVMS chain. + * @run main/othervm -Xbatch + * -XX:CompileOnly=compiler.escapeAnalysis.TestReduceAllocationAndJVMStates::test* + * compiler.escapeAnalysis.TestReduceAllocationAndJVMStates + * @run main compiler.escapeAnalysis.TestReduceAllocationAndJVMStates + */ +package compiler.escapeAnalysis; + +public class TestReduceAllocationAndJVMStates { + static boolean bFld; + static int iFld; + + public static void main(String[] args) { + bFld = false; + + for (int i = 0; i < 10000; i++) { + test(i % 2 == 0); + } + bFld = true; + + // This will trigger a deoptimization which + // will make the issue manifest to the user + test(true); + } + + static int test(boolean flag) { + Super a = new A(); + Super b = new B(); + Super s = (flag ? a : b); + + // This needs to be inlined by C2 + check(); + + return a.i + b.i + s.i; + } + + // This shouldn't be manually inlined + static void check() { + if (bFld) { + iFld = 34; + } + } +} + +class Super { + int i; +} +class A extends Super {} +class B extends Super {} diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestArrayCopyWithLargeObjectAlignment.java b/test/hotspot/jtreg/compiler/gcbarriers/TestArrayCopyWithLargeObjectAlignment.java index dd2d485fb76df..494c571450dc8 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/TestArrayCopyWithLargeObjectAlignment.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestArrayCopyWithLargeObjectAlignment.java @@ -30,11 +30,11 @@ * @summary Test that, when using a larger object alignment, ZGC arraycopy * barriers are only applied to actual OOPs, and not to object * alignment padding words. - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @run main/othervm -Xbatch -XX:-TieredCompilation * -XX:CompileOnly=compiler.gcbarriers.TestArrayCopyWithLargeObjectAlignment::* * -XX:ObjectAlignmentInBytes=16 - * -XX:+UseZGC -XX:+ZGenerational + * -XX:+UseZGC * compiler.gcbarriers.TestArrayCopyWithLargeObjectAlignment */ diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.java b/test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.java new file mode 100644 index 0000000000000..36ad0bf84a40b --- /dev/null +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.java @@ -0,0 +1,639 @@ +/* + * 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.gcbarriers; + +import compiler.lib.ir_framework.*; +import java.lang.invoke.VarHandle; +import java.lang.invoke.MethodHandles; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.util.concurrent.ThreadLocalRandom; +import jdk.test.lib.Asserts; + +/** + * @test + * @summary Test that G1 barriers are generated and optimized as expected. + * @library /test/lib / + * @requires vm.gc.G1 + * @run driver compiler.gcbarriers.TestG1BarrierGeneration + */ + +public class TestG1BarrierGeneration { + static final String PRE_ONLY = "pre"; + static final String POST_ONLY = "post"; + static final String POST_ONLY_NOT_NULL = "post notnull"; + static final String PRE_AND_POST = "pre post"; + static final String PRE_AND_POST_NOT_NULL = "pre post notnull"; + + static class Outer { + Object f; + } + + static class OuterWithVolatileField { + volatile Object f; + } + + static class OuterWithFewFields implements Cloneable { + Object f1; + Object f2; + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + } + + static class OuterWithManyFields implements Cloneable { + Object f1; + Object f2; + Object f3; + Object f4; + Object f5; + Object f6; + Object f7; + Object f8; + Object f9; + Object f10; + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + } + + static final VarHandle fVarHandle; + static { + MethodHandles.Lookup l = MethodHandles.lookup(); + try { + fVarHandle = l.findVarHandle(Outer.class, "f", Object.class); + } catch (Exception e) { + throw new Error(e); + } + } + + public static void main(String[] args) { + TestFramework framework = new TestFramework(); + Scenario[] scenarios = new Scenario[2*2]; + int scenarioIndex = 0; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + scenarios[scenarioIndex] = + new Scenario(scenarioIndex, + "-XX:CompileCommand=inline,java.lang.ref.*::*", + "-XX:" + (i == 0 ? "-" : "+") + "UseCompressedOops", + "-XX:" + (j == 0 ? "-" : "+") + "ReduceInitialCardMarks"); + scenarioIndex++; + } + } + framework.addScenarios(scenarios); + framework.start(); + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testStore(Outer o, Object o1) { + o.f = o1; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testStoreNull(Outer o) { + o.f = null; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testStoreObfuscatedNull(Outer o, Object o1) { + Object o2 = o1; + for (int i = 0; i < 4; i++) { + if ((i % 2) == 0) { + o2 = null; + } + } + // o2 is null here, but this is only known to C2 after applying some + // optimizations (loop unrolling, IGVN). + o.f = o2; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testStoreNotNull(Outer o, Object o1) { + if (o1.hashCode() == 42) { + return; + } + o.f = o1; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "2"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "2"}, + phase = CompilePhase.FINAL_CODE) + public static void testStoreTwice(Outer o, Outer p, Object o1) { + o.f = o1; + p.f = o1; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testStoreVolatile(OuterWithVolatileField o, Object o1) { + o.f = o1; + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + phase = CompilePhase.FINAL_CODE) + public static Outer testStoreOnNewObject(Object o1) { + Outer o = new Outer(); + o.f = o1; + return o; + } + + @Test + @IR(failOn = {IRNode.STORE_P, IRNode.STORE_N}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION) + public static Outer testStoreNullOnNewObject() { + Outer o = new Outer(); + o.f = null; + return o; + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + phase = CompilePhase.FINAL_CODE) + public static Outer testStoreNotNullOnNewObject(Object o1) { + if (o1.hashCode() == 42) { + return null; + } + Outer o = new Outer(); + o.f = o1; + return o; + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "2"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "2"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + phase = CompilePhase.FINAL_CODE) + public static Outer testStoreOnNewObjectInTwoPaths(Object o1, boolean c) { + Outer o; + if (c) { + o = new Outer(); + o.f = o1; + } else { + o = new Outer(); + o.f = o1; + } + return o; + } + + @Run(test = {"testStore", + "testStoreNull", + "testStoreObfuscatedNull", + "testStoreNotNull", + "testStoreTwice", + "testStoreVolatile", + "testStoreOnNewObject", + "testStoreNullOnNewObject", + "testStoreNotNullOnNewObject", + "testStoreOnNewObjectInTwoPaths"}) + public void runStoreTests() { + { + Outer o = new Outer(); + Object o1 = new Object(); + testStore(o, o1); + Asserts.assertEquals(o1, o.f); + } + { + Outer o = new Outer(); + testStoreNull(o); + Asserts.assertNull(o.f); + } + { + Outer o = new Outer(); + Object o1 = new Object(); + testStoreObfuscatedNull(o, o1); + Asserts.assertNull(o.f); + } + { + Outer o = new Outer(); + Object o1 = new Object(); + testStoreNotNull(o, o1); + Asserts.assertEquals(o1, o.f); + } + { + Outer o = new Outer(); + Outer p = new Outer(); + Object o1 = new Object(); + testStoreTwice(o, p, o1); + Asserts.assertEquals(o1, o.f); + Asserts.assertEquals(o1, p.f); + } + { + OuterWithVolatileField o = new OuterWithVolatileField(); + Object o1 = new Object(); + testStoreVolatile(o, o1); + Asserts.assertEquals(o1, o.f); + } + { + Object o1 = new Object(); + Outer o = testStoreOnNewObject(o1); + Asserts.assertEquals(o1, o.f); + } + { + Outer o = testStoreNullOnNewObject(); + Asserts.assertNull(o.f); + } + { + Object o1 = new Object(); + Outer o = testStoreNotNullOnNewObject(o1); + Asserts.assertEquals(o1, o.f); + } + { + Object o1 = new Object(); + Outer o = testStoreOnNewObjectInTwoPaths(o1, ThreadLocalRandom.current().nextBoolean()); + Asserts.assertEquals(o1, o.f); + } + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testArrayStore(Object[] a, int index, Object o1) { + a[index] = o1; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testArrayStoreNull(Object[] a, int index) { + a[index] = null; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testArrayStoreNotNull(Object[] a, int index, Object o1) { + if (o1.hashCode() == 42) { + return; + } + a[index] = o1; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "2"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "2"}, + phase = CompilePhase.FINAL_CODE) + public static void testArrayStoreTwice(Object[] a, Object[] b, int index, Object o1) { + a[index] = o1; + b[index] = o1; + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + phase = CompilePhase.FINAL_CODE) + public static Object[] testStoreOnNewArray(Object o1) { + Object[] a = new Object[10]; + // The index needs to be concrete for C2 to detect that it is safe to + // remove the pre-barrier. + a[4] = o1; + return a; + } + + @Run(test = {"testArrayStore", + "testArrayStoreNull", + "testArrayStoreNotNull", + "testArrayStoreTwice", + "testStoreOnNewArray"}) + public void runArrayStoreTests() { + { + Object[] a = new Object[10]; + Object o1 = new Object(); + testArrayStore(a, 4, o1); + Asserts.assertEquals(o1, a[4]); + } + { + Object[] a = new Object[10]; + testArrayStoreNull(a, 4); + Asserts.assertNull(a[4]); + } + { + Object[] a = new Object[10]; + Object o1 = new Object(); + testArrayStoreNotNull(a, 4, o1); + Asserts.assertEquals(o1, a[4]); + } + { + Object[] a = new Object[10]; + Object[] b = new Object[10]; + Object o1 = new Object(); + testArrayStoreTwice(a, b, 4, o1); + Asserts.assertEquals(o1, a[4]); + Asserts.assertEquals(o1, b[4]); + } + { + Object o1 = new Object(); + Object[] a = testStoreOnNewArray(o1); + Asserts.assertEquals(o1, a[4]); + } + } + + @Test + public static Object[] testCloneArrayOfObjects(Object[] a) { + Object[] a1 = null; + try { + a1 = a.clone(); + } catch (Exception e) {} + return a1; + } + + @Test + @IR(applyIf = {"ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P, IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"ReduceInitialCardMarks", "false", "UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "2"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"ReduceInitialCardMarks", "false", "UseCompressedOops", "true"}, + counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "2"}, + phase = CompilePhase.FINAL_CODE) + public static OuterWithFewFields testCloneObjectWithFewFields(OuterWithFewFields o) { + Object o1 = null; + try { + o1 = o.clone(); + } catch (Exception e) {} + return (OuterWithFewFields)o1; + } + + @Test + @IR(applyIf = {"ReduceInitialCardMarks", "true"}, + counts = {IRNode.CALL_OF, "jlong_disjoint_arraycopy", "1"}) + @IR(applyIf = {"ReduceInitialCardMarks", "false"}, + counts = {IRNode.CALL_OF, "G1BarrierSetRuntime::clone", "1"}) + public static OuterWithManyFields testCloneObjectWithManyFields(OuterWithManyFields o) { + Object o1 = null; + try { + o1 = o.clone(); + } catch (Exception e) {} + return (OuterWithManyFields)o1; + } + + @Run(test = {"testCloneArrayOfObjects", + "testCloneObjectWithFewFields", + "testCloneObjectWithManyFields"}) + public void runCloneTests() { + { + Object o1 = new Object(); + Object[] a = new Object[4]; + for (int i = 0; i < 4; i++) { + a[i] = o1; + } + Object[] a1 = testCloneArrayOfObjects(a); + for (int i = 0; i < 4; i++) { + Asserts.assertEquals(o1, a1[i]); + } + } + { + Object a = new Object(); + Object b = new Object(); + OuterWithFewFields o = new OuterWithFewFields(); + o.f1 = a; + o.f2 = b; + OuterWithFewFields o1 = testCloneObjectWithFewFields(o); + Asserts.assertEquals(a, o1.f1); + Asserts.assertEquals(b, o1.f2); + } + { + Object a = new Object(); + Object b = new Object(); + Object c = new Object(); + Object d = new Object(); + Object e = new Object(); + Object f = new Object(); + Object g = new Object(); + Object h = new Object(); + Object i = new Object(); + Object j = new Object(); + OuterWithManyFields o = new OuterWithManyFields(); + o.f1 = a; + o.f2 = b; + o.f3 = c; + o.f4 = d; + o.f5 = e; + o.f6 = f; + o.f7 = g; + o.f8 = h; + o.f9 = i; + o.f10 = j; + OuterWithManyFields o1 = testCloneObjectWithManyFields(o); + Asserts.assertEquals(a, o1.f1); + Asserts.assertEquals(b, o1.f2); + Asserts.assertEquals(c, o1.f3); + Asserts.assertEquals(d, o1.f4); + Asserts.assertEquals(e, o1.f5); + Asserts.assertEquals(f, o1.f6); + Asserts.assertEquals(g, o1.f7); + Asserts.assertEquals(h, o1.f8); + Asserts.assertEquals(i, o1.f9); + Asserts.assertEquals(j, o1.f10); + } + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + static Object testCompareAndExchange(Outer o, Object oldVal, Object newVal) { + return fVarHandle.compareAndExchange(o, oldVal, newVal); + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + static boolean testCompareAndSwap(Outer o, Object oldVal, Object newVal) { + return fVarHandle.compareAndSet(o, oldVal, newVal); + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + static Object testGetAndSet(Outer o, Object newVal) { + return fVarHandle.getAndSet(o, newVal); + } + + @Run(test = {"testCompareAndExchange", + "testCompareAndSwap", + "testGetAndSet"}) + public void runAtomicTests() { + { + Outer o = new Outer(); + Object oldVal = new Object(); + o.f = oldVal; + Object newVal = new Object(); + Object oldVal2 = testCompareAndExchange(o, oldVal, newVal); + Asserts.assertEquals(oldVal, oldVal2); + Asserts.assertEquals(o.f, newVal); + } + { + Outer o = new Outer(); + Object oldVal = new Object(); + o.f = oldVal; + Object newVal = new Object(); + boolean b = testCompareAndSwap(o, oldVal, newVal); + Asserts.assertTrue(b); + Asserts.assertEquals(o.f, newVal); + } + { + Outer o = new Outer(); + Object oldVal = new Object(); + o.f = oldVal; + Object newVal = new Object(); + Object oldVal2 = testGetAndSet(o, newVal); + Asserts.assertEquals(oldVal, oldVal2); + Asserts.assertEquals(o.f, newVal); + } + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_LOAD_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_LOAD_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + static Object testLoadSoftReference(SoftReference ref) { + return ref.get(); + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_LOAD_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_LOAD_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + static Object testLoadWeakReference(WeakReference ref) { + return ref.get(); + } + + @Run(test = {"testLoadSoftReference", + "testLoadWeakReference"}) + public void runReferenceTests() { + { + Object o1 = new Object(); + SoftReference sref = new SoftReference(o1); + Object o2 = testLoadSoftReference(sref); + Asserts.assertTrue(o2 == o1 || o2 == null); + } + { + Object o1 = new Object(); + WeakReference wref = new WeakReference(o1); + Object o2 = testLoadWeakReference(wref); + Asserts.assertTrue(o2 == o1 || o2 == null); + } + } +} diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestZGCBarrierElision.java b/test/hotspot/jtreg/compiler/gcbarriers/TestZGCBarrierElision.java index af047dd54572a..6f39ba7a8a1e9 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/TestZGCBarrierElision.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestZGCBarrierElision.java @@ -34,7 +34,7 @@ * necessary barriers. The tests use volatile memory accesses and * blackholes to prevent C2 from simply optimizing them away. * @library /test/lib / - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @run driver compiler.gcbarriers.TestZGCBarrierElision test-correctness */ @@ -43,7 +43,7 @@ * @summary Test that the ZGC barrier elision optimization elides unnecessary * barriers following simple allocation and domination rules. * @library /test/lib / - * @requires vm.gc.ZGenerational & (vm.simpleArch == "x64" | vm.simpleArch == "aarch64") + * @requires vm.gc.Z & (vm.simpleArch == "x64" | vm.simpleArch == "aarch64") * @run driver compiler.gcbarriers.TestZGCBarrierElision test-effectiveness */ @@ -99,7 +99,7 @@ public static void main(String[] args) { } String commonName = Common.class.getName(); TestFramework test = new TestFramework(testClass); - test.addFlags("-XX:+UseZGC", "-XX:+ZGenerational", "-XX:+UnlockExperimentalVMOptions", + test.addFlags("-XX:+UseZGC", "-XX:+UnlockExperimentalVMOptions", "-XX:CompileCommand=blackhole," + commonName + "::blackhole", "-XX:CompileCommand=dontinline," + commonName + "::nonInlinedMethod", "-XX:LoopMaxUnroll=0"); diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestZGCUnrolling.java b/test/hotspot/jtreg/compiler/gcbarriers/TestZGCUnrolling.java index 618b03e4cfb79..0c30531285e89 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/TestZGCUnrolling.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestZGCUnrolling.java @@ -34,7 +34,7 @@ * The tests use volatile memory accesses to prevent C2 from simply * optimizing them away. * @library /test/lib / - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @run driver compiler.gcbarriers.TestZGCUnrolling */ @@ -55,8 +55,7 @@ static class Outer { } public static void main(String[] args) { - TestFramework.runWithFlags("-XX:+UseZGC", "-XX:+ZGenerational", - "-XX:LoopUnrollLimit=24"); + TestFramework.runWithFlags("-XX:+UseZGC", "-XX:LoopUnrollLimit=24"); } @Test diff --git a/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java b/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java index 6a511fd60d96a..65901f5e65656 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java @@ -22,14 +22,14 @@ */ /* - * @test id=ZSinglegenDebug + * @test id=ZDebug * @key randomness * @bug 8059022 8271855 * @modules java.base/jdk.internal.misc:+open * @summary Validate barriers after Unsafe getReference, CAS and swap (GetAndSet) - * @requires vm.gc.ZSinglegen & vm.debug + * @requires vm.gc.Z & vm.debug * @library /test/lib - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational + * @run main/othervm -XX:+UseZGC * -XX:+UnlockDiagnosticVMOptions * -XX:+ZVerifyOops -XX:ZCollectionInterval=1 * -XX:-CreateCoredumpOnCrash @@ -38,46 +38,14 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @key randomness * @bug 8059022 8271855 * @modules java.base/jdk.internal.misc:+open * @summary Validate barriers after Unsafe getReference, CAS and swap (GetAndSet) - * @requires vm.gc.ZSinglegen & !vm.debug + * @requires vm.gc.Z & !vm.debug * @library /test/lib - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational - * -XX:+UnlockDiagnosticVMOptions - * -XX:ZCollectionInterval=1 - * -XX:-CreateCoredumpOnCrash - * -XX:CompileCommand=dontinline,*::mergeImpl* - * compiler.gcbarriers.UnsafeIntrinsicsTest - */ - -/* - * @test id=ZGenerationalDebug - * @key randomness - * @bug 8059022 8271855 - * @modules java.base/jdk.internal.misc:+open - * @summary Validate barriers after Unsafe getReference, CAS and swap (GetAndSet) - * @requires vm.gc.ZGenerational & vm.debug - * @library /test/lib - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational - * -XX:+UnlockDiagnosticVMOptions - * -XX:+ZVerifyOops -XX:ZCollectionInterval=1 - * -XX:-CreateCoredumpOnCrash - * -XX:CompileCommand=dontinline,*::mergeImpl* - * compiler.gcbarriers.UnsafeIntrinsicsTest - */ - -/* - * @test id=ZGenerational - * @key randomness - * @bug 8059022 8271855 - * @modules java.base/jdk.internal.misc:+open - * @summary Validate barriers after Unsafe getReference, CAS and swap (GetAndSet) - * @requires vm.gc.ZGenerational & !vm.debug - * @library /test/lib - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational + * @run main/othervm -XX:+UseZGC * -XX:+UnlockDiagnosticVMOptions * -XX:ZCollectionInterval=1 * -XX:-CreateCoredumpOnCrash diff --git a/test/hotspot/jtreg/compiler/jvmci/TestJVMCISavedProperties.java b/test/hotspot/jtreg/compiler/jvmci/TestJVMCISavedProperties.java index 31e592ef906fa..0bddce28325c4 100644 --- a/test/hotspot/jtreg/compiler/jvmci/TestJVMCISavedProperties.java +++ b/test/hotspot/jtreg/compiler/jvmci/TestJVMCISavedProperties.java @@ -48,15 +48,13 @@ public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:+UnlockExperimentalVMOptions", "-XX:+EagerJVMCI", - "-XX:+UseJVMCICompiler", - "-Djvmci.Compiler=null", + "-XX:+EnableJVMCI", "-Ddebug.jvmci.PrintSavedProperties=true", "-Dapp1.propX=true", "-Dapp2.propY=SomeStringValue", "TestJVMCISavedProperties", "true"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.stdoutShouldContain("debug.jvmci.PrintSavedProperties=true"); - output.stdoutShouldContain("jvmci.Compiler=null"); output.stdoutShouldContain("app1.propX=true"); output.stdoutShouldContain("app2.propY=SomeStringValue"); output.stdoutShouldContain("java.specification.version=" + Runtime.version().feature()); diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/ClassLoaderBuilder.java b/test/hotspot/jtreg/compiler/lib/compile_framework/ClassLoaderBuilder.java new file mode 100644 index 0000000000000..2f14cfb0f0489 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/ClassLoaderBuilder.java @@ -0,0 +1,64 @@ +/* + * 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.compile_framework; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/** + * Build a ClassLoader that loads from classpath and {@code classesDir}. + * Helper class that generates a ClassLoader which allows loading classes + * from the classpath (see {@link Utils#getClassPaths()}) and {@code classesDir}. + *

            + * The CompileFramework compiles all its classes to a specific {@code classesDir}, + * and this generated ClassLoader thus can be used to load those classes. + */ +class ClassLoaderBuilder { + + /** + * Build a ClassLoader that loads from classpath and {@code classesDir}. + */ + public static ClassLoader build(Path classesDir) { + ClassLoader sysLoader = ClassLoader.getSystemClassLoader(); + + try { + // Classpath for all included classes (e.g. IR Framework). + // Get all class paths, convert to URLs. + List urls = new ArrayList<>(); + for (String path : Utils.getClassPaths()) { + urls.add(new File(path).toURI().toURL()); + } + // And add in the compiled classes from this instance of CompileFramework. + urls.add(new File(classesDir.toString()).toURI().toURL()); + return URLClassLoader.newInstance(urls.toArray(URL[]::new), sysLoader); + } catch (IOException e) { + throw new CompileFrameworkException("IOException while creating ClassLoader", e); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/Compile.java b/test/hotspot/jtreg/compiler/lib/compile_framework/Compile.java new file mode 100644 index 0000000000000..0f45d982af6d6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/Compile.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.lib.compile_framework; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; +import java.util.List; +import jdk.test.lib.JDKToolFinder; + +/** + * Helper class for compilation of Java and Jasm {@link SourceCode}. + */ +class Compile { + private static final int COMPILE_TIMEOUT = 60; + + private static final String JAVA_PATH = JDKToolFinder.getJDKTool("java"); + private static final String JAVAC_PATH = JDKToolFinder.getJDKTool("javac"); + + /** + * Compile all sources in {@code javaSources}. First write them to the {@code sourceDir}, + * then compile them to class-files which are stored in {@code classesDir}. + */ + public static void compileJavaSources(List javaSources, Path sourceDir, Path classesDir) { + if (javaSources.isEmpty()) { + Utils.printlnVerbose("No java sources to compile."); + return; + } + Utils.printlnVerbose("Compiling Java sources: " + javaSources.size()); + + List javaFilePaths = writeSourcesToFiles(javaSources, sourceDir); + compileJavaFiles(javaFilePaths, classesDir); + Utils.printlnVerbose("Java sources compiled."); + } + + /** + * Compile a list of files (i.e. {@code paths}) using javac and store + * them in {@code classesDir}. + */ + private static void compileJavaFiles(List paths, Path classesDir) { + List command = new ArrayList<>(); + + command.add(JAVAC_PATH); + command.add("-classpath"); + // Note: the backslashes from windows paths must be escaped! + command.add(Utils.getEscapedClassPathAndClassesDir(classesDir)); + command.add("-d"); + command.add(classesDir.toString()); + for (Path path : paths) { + command.add(path.toAbsolutePath().toString()); + } + + executeCompileCommand(command); + } + + /** + * Compile all sources in {@code jasmSources}. First write them to the {@code sourceDir}, + * then compile them to class-files which are stored in {@code classesDir}. + */ + public static void compileJasmSources(List jasmSources, Path sourceDir, Path classesDir) { + if (jasmSources.isEmpty()) { + Utils.printlnVerbose("No jasm sources to compile."); + return; + } + Utils.printlnVerbose("Compiling jasm sources: " + jasmSources.size()); + + List jasmFilePaths = writeSourcesToFiles(jasmSources, sourceDir); + compileJasmFiles(jasmFilePaths, classesDir); + Utils.printlnVerbose("Jasm sources compiled."); + } + + /** + * Compile a list of files (i.e. {@code paths}) using asmtools jasm and store + * them in {@code classesDir}. + */ + private static void compileJasmFiles(List paths, Path classesDir) { + List command = new ArrayList<>(); + + command.add(JAVA_PATH); + command.add("-classpath"); + command.add(getAsmToolsPath()); + command.add("org.openjdk.asmtools.jasm.Main"); + command.add("-d"); + command.add(classesDir.toString()); + for (Path path : paths) { + command.add(path.toAbsolutePath().toString()); + } + + executeCompileCommand(command); + } + + /** + * Get the path of asmtools, which is shipped with JTREG. + */ + private static String getAsmToolsPath() { + for (String path : Utils.getClassPaths()) { + if (path.endsWith("jtreg.jar")) { + File jtreg = new File(path); + File dir = jtreg.getAbsoluteFile().getParentFile(); + File asmtools = new File(dir, "asmtools.jar"); + if (!asmtools.exists()) { + throw new InternalCompileFrameworkException("Found jtreg.jar in classpath, but could not find asmtools.jar"); + } + return asmtools.getAbsolutePath(); + } + } + throw new InternalCompileFrameworkException("Could not find asmtools because could not find jtreg.jar in classpath"); + } + + private static void writeCodeToFile(String code, Path path) { + Utils.printlnVerbose("File: " + path); + + // Ensure directory of the file exists. + Path dir = path.getParent(); + try { + Files.createDirectories(dir); + } catch (Exception e) { + throw new CompileFrameworkException("Could not create directory: " + dir, e); + } + + // Write to file. + try (BufferedWriter writer = Files.newBufferedWriter(path)) { + writer.write(code); + } catch (Exception e) { + throw new CompileFrameworkException("Could not write file: " + path, e); + } + } + + /** + * Write each source in {@code sources} to a file inside {@code sourceDir}. + */ + private static List writeSourcesToFiles(List sources, Path sourceDir) { + List storedFiles = new ArrayList<>(); + for (SourceCode sourceCode : sources) { + Path path = sourceDir.resolve(sourceCode.filePathName()); + writeCodeToFile(sourceCode.code(), path); + storedFiles.add(path); + } + return storedFiles; + } + + /** + * Execute a given compilation, given as a {@code command}. + */ + private static void executeCompileCommand(List command) { + Utils.printlnVerbose("Compile command: " + String.join(" ", command)); + + ProcessBuilder builder = new ProcessBuilder(command); + builder.redirectErrorStream(true); + + String output; + int exitCode; + try { + Process process = builder.start(); + boolean exited = process.waitFor(COMPILE_TIMEOUT, TimeUnit.SECONDS); + if (!exited) { + process.destroyForcibly(); + System.out.println("Timeout: compile command: " + String.join(" ", command)); + throw new InternalCompileFrameworkException("Process timeout: compilation took too long."); + } + output = new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8); + exitCode = process.exitValue(); + } catch (IOException e) { + throw new InternalCompileFrameworkException("IOException during compilation", e); + } catch (InterruptedException e) { + throw new CompileFrameworkException("InterruptedException during compilation", e); + } + + if (exitCode != 0 || !output.isEmpty()) { + System.err.println("Compilation failed."); + System.err.println("Exit code: " + exitCode); + System.err.println("Output: '" + output + "'"); + throw new CompileFrameworkException("Compilation failed."); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFramework.java b/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFramework.java new file mode 100644 index 0000000000000..fe23d596f3c64 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFramework.java @@ -0,0 +1,169 @@ +/* + * 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.compile_framework; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/** + * This is the entry-point for the Compile Framework. Its purpose it to allow + * compilation and execution of Java and Jasm sources generated at runtime. + * + *

            Please reference the README.md for more details and examples. + */ +public class CompileFramework { + private final List javaSources = new ArrayList<>(); + private final List jasmSources = new ArrayList<>(); + private final Path sourceDir = Utils.makeUniqueDir("compile-framework-sources-"); + private final Path classesDir = Utils.makeUniqueDir("compile-framework-classes-"); + private ClassLoader classLoader; + + /** + * Set up a new Compile Framework instance, for a new compilation unit. + */ + public CompileFramework() {} + + /** + * Add a Java source to the compilation. + * + * @param className Class name of the class (e.g. "{@code p.xyz.YXZ}"). + * @param code Java code for the class, in the form of a {@link String}. + */ + public void addJavaSourceCode(String className, String code) { + javaSources.add(new SourceCode(className, "java", code)); + } + + /** + * Add a Jasm source to the compilation. + * + * @param className Class name of the class (e.g. "{@code p.xyz.YXZ}"). + * @param code Jasm code for the class, in the form of a {@link String}. + */ + public void addJasmSourceCode(String className, String code) { + jasmSources.add(new SourceCode(className, "jasm", code)); + } + + /** + * Compile all sources: store the sources to the {@link sourceDir} directory, compile + * Java and Jasm sources and store the generated class-files in the {@link classesDir} + * directory. + */ + public void compile() { + if (classLoader != null) { + throw new CompileFrameworkException("Cannot compile twice!"); + } + + Utils.printlnVerbose("------------------ CompileFramework: SourceCode -------------------"); + Utils.printlnVerbose(sourceCodesAsString(jasmSources)); + Utils.printlnVerbose(sourceCodesAsString(javaSources)); + + System.out.println("------------------ CompileFramework: Compilation ------------------"); + System.out.println("Source directory: " + sourceDir); + System.out.println("Classes directory: " + classesDir); + + Compile.compileJasmSources(jasmSources, sourceDir, classesDir); + Compile.compileJavaSources(javaSources, sourceDir, classesDir); + classLoader = ClassLoaderBuilder.build(classesDir); + } + + private static String sourceCodesAsString(List sourceCodes) { + StringBuilder builder = new StringBuilder(); + for (SourceCode sourceCode : sourceCodes) { + builder.append("SourceCode: ").append(sourceCode.filePathName()).append(System.lineSeparator()); + builder.append(sourceCode.code()).append(System.lineSeparator()); + } + return builder.toString(); + } + + /** + * Access a class from the compiled code. + * + * @param name Name of the class to be retrieved. + * @return The class corresponding to the {@code name}. + */ + public Class getClass(String name) { + try { + return Class.forName(name, true, classLoader); + } catch (ClassNotFoundException e) { + throw new CompileFrameworkException("Class not found:", e); + } + } + + /** + * Invoke a static method from the compiled code. + * + * @param className Class name of a compiled class. + * @param methodName Method name of the class. + * @param args List of arguments for the method invocation. + * @return Return value from the invocation. + */ + public Object invoke(String className, String methodName, Object[] args) { + Method method = findMethod(className, methodName); + + try { + return method.invoke(null, args); + } catch (IllegalAccessException e) { + throw new CompileFrameworkException("Illegal access:", e); + } catch (InvocationTargetException e) { + throw new CompileFrameworkException("Invocation target:", e); + } + } + + private Method findMethod(String className, String methodName) { + Class c = getClass(className); + Method[] methods = c.getDeclaredMethods(); + Method method = null; + + for (Method m : methods) { + if (m.getName().equals(methodName)) { + if (method != null) { + throw new CompileFrameworkException("Method name \"" + methodName + "\" not unique in class \n" + className + "\"."); + } + method = m; + } + } + + if (method == null) { + throw new CompileFrameworkException("Method \"" + methodName + "\" not found in class \n" + className + "\"."); + } + + return method; + } + + /** + * Returns the classpath appended with the {@link classesDir}, where + * the compiled classes are stored. This enables another VM to load + * the compiled classes. Note, the string is already backslash escaped, + * so that Windows paths which use backslashes can be used directly + * as strings. + * + * @return Classpath appended with the path to the compiled classes. + */ + public String getEscapedClassPathOfCompiledClasses() { + return Utils.getEscapedClassPathAndClassesDir(classesDir); + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XHash.java b/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFrameworkException.java similarity index 63% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XHash.java rename to test/hotspot/jtreg/compiler/lib/compile_framework/CompileFrameworkException.java index 79b1f5c2e70a0..5c71a33a533fd 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XHash.java +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFrameworkException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 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 @@ -19,23 +19,19 @@ * Please 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.jvm.hotspot.gc.x; +package compiler.lib.compile_framework; -class XHash { - private static long uint32(long value) { - return value & 0xFFFFFFFFL; +/** + * Exception thrown in the Compilation Framework. Most likely, the user is responsible for the failure. + */ +public class CompileFrameworkException extends RuntimeException { + public CompileFrameworkException(String message) { + super("Exception in Compile Framework:" + System.lineSeparator() + message); } - static long uint32_to_uint32(long key) { - key = uint32(~key + (key << 15)); - key = uint32(key ^ (key >>> 12)); - key = uint32(key + (key << 2)); - key = uint32(key ^ (key >>> 4)); - key = uint32(key * 2057); - key = uint32(key ^ (key >>> 16)); - return key; + public CompileFrameworkException(String message, Throwable e) { + super("Exception in Compile Framework:" + System.lineSeparator() + message, e); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingTableEntry.java b/test/hotspot/jtreg/compiler/lib/compile_framework/InternalCompileFrameworkException.java similarity index 59% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingTableEntry.java rename to test/hotspot/jtreg/compiler/lib/compile_framework/InternalCompileFrameworkException.java index 7c629f7c5cf9f..0cfed80ce1cd6 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XForwardingTableEntry.java +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/InternalCompileFrameworkException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -19,37 +19,19 @@ * Please 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.jvm.hotspot.gc.x; - -import sun.jvm.hotspot.debugger.Address; - -class XForwardingTableEntry { - private Address entry; - - XForwardingTableEntry(Address addr) { - entry = addr; - } - - private static long empty() { - return ~0L; - } - - boolean is_empty() { - return entry.asLongValue() == empty(); - } +package compiler.lib.compile_framework; - Address to_offset() { - return entry.andWithMask((1L << 42) - 1); - } - - long from_index() { - return entry.asLongValue() >>> 42; +/** + * Internal exception thrown in Compilation Framework. Most likely, this is due to a bug in the CompileFramework. + */ +public class InternalCompileFrameworkException extends RuntimeException { + public InternalCompileFrameworkException(String message) { + super("Internal exception in Compile Framework, please file a bug:" + System.lineSeparator() + message); } - public String toString() { - return entry + " - from_index: " + from_index() + " to_offset: " + to_offset(); + public InternalCompileFrameworkException(String message, Throwable e) { + super("Internal exception in Compile Framework, please file a bug:" + System.lineSeparator() + message, e); } } diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/README.md b/test/hotspot/jtreg/compiler/lib/compile_framework/README.md new file mode 100644 index 0000000000000..76ddf677811c7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/README.md @@ -0,0 +1,57 @@ +# Compile Framework +The Compile Framework allows the compilation and execution of Java and Jasm sources, which are generated at runtime. + +## Motivation +We want to be able to generate Java and Jasm source code in the form of Strings at runtime, then compile them, load the classes and invoke some methods. This allows us to write more elaborate tests. For example small dedicated fuzzers that are targetted at some specific compiler optimization. + +This is more powerful than hand-written tests, as we can generalize tests and cover more examples. It can also be better than a script-generated test: those are static and often the script is not integrated with the generated test. Another limitation of a generator script is that it is only run once, creating fixed static tests. Compilation at runtime allows us to randomly generate tests each time. + +Of course we could compile at runtime without this framework, but it abstracts away the complexity of compilation, and allows the test-writer to focus on the generation of the source code. + +## How to Use the Compile Framework + +Please reference the examples found in [examples](../../../testlibrary_tests/compile_framework/examples/). Some basic tests can be found in [tests](../../../testlibrary_tests/compile_framework/tests/). + +Here a very simple example: + + // Create a new CompileFramework instance. + CompileFramework compileFramework = new CompileFramework(); + + // Add a java source file. + compileFramework.addJavaSourceCode("XYZ", ""); + + // Compile the source file. + compileFramework.compile(); + + // Object returnValue = XYZ.test(5); + Object returnValue = compileFramework.invoke("XYZ", "test", new Object[] {5}); + +### Creating a new Compile Framework Instance + +First, one must create a `new CompileFramework()`, which creates two directories: a sources and a classes directory (see `sourcesDir` and `classesDir` in [CompileFramework](./CompileFramework.java)). The sources directory is where all the sources are placed by the Compile Framework, and the classes directory is where all the compiled classes are placed by the Compile Framework. + +The Compile Framework prints the names of the directories, they are subdirectories of the JTREG scratch directory `JTWork/scratch`. + +### Adding Sources to the Compilation + +Java and Jasm sources can be added to the compilation using `compileFramework.addJavaSourceCode()` and `compileFramework.addJasmSourceCode()`. The source classes can depend on each other, and they can also use the IR Framework ([IRFrameworkJavaExample](../../../testlibrary_tests/compile_framework/examples/IRFrameworkJavaExample.java)). + +When using the IR Framework, or any other library that needs to be compiled, it can be necessary to explicitly let JTREG compile that library. For example with `@compile ../../../compiler/lib/ir_framework/TestFramework.java`. Otherwise, the corresponding class files may not be available, and a corresponding failure will be encounter at class loading. + +### Compiling + +All sources are compiled with `compileFramework.compile()`. First, the sources are stored to the sources directory, then compiled, and then the class-files stored in the classes directory. The respective directory names are printed, so that the user can easily access the generated files for debugging. + +### Interacting with the Compiled Code + +The compiled code is then loaded with a `ClassLoader`. The classes can be accessed directly with `compileFramework.getClass(name)`. Specific methods can also directly be invoked with `compileFramework.invoke()`. + +Should one require the modified classpath that includes the compiled classes, this is available with `compileFramework.getEscapedClassPathOfCompiledClasses()`. This can be necessary if the test launches any other VMs that also access the compiled classes. This is for example necessary when using the IR Framework. + +### Running the Compiled Code in a New VM + +One can also run the compiled code in a new VM. For this, one has to set the classpath with `compileFramework.getEscapedClassPathOfCompiledClasses()` ([RunWithFlagsExample](../../../testlibrary_tests/compile_framework/examples/RunWithFlagsExample.java)) + +### Verbose Printing + +For debugging purposes, one can enable verbose printing, with `-DCompileFrameworkVerbose=true`. diff --git a/src/hotspot/os/linux/gc/x/xLargePages_linux.cpp b/test/hotspot/jtreg/compiler/lib/compile_framework/SourceCode.java similarity index 68% rename from src/hotspot/os/linux/gc/x/xLargePages_linux.cpp rename to test/hotspot/jtreg/compiler/lib/compile_framework/SourceCode.java index 6ad956b1e63fe..df38e420758e6 100644 --- a/src/hotspot/os/linux/gc/x/xLargePages_linux.cpp +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/SourceCode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,18 +21,15 @@ * questions. */ -#include "precompiled.hpp" -#include "gc/x/xLargePages.hpp" -#include "runtime/globals.hpp" +package compiler.lib.compile_framework; -void XLargePages::pd_initialize() { - if (UseLargePages) { - if (UseTransparentHugePages) { - _state = Transparent; - } else { - _state = Explicit; +/** + * This class represents the source code of a specific class. + */ +record SourceCode(String className, String extension, String code) { + public String filePathName() { + StringBuilder builder = new StringBuilder(); + builder.append(className.replace('.','/')).append(".").append(extension); + return builder.toString(); } - } else { - _state = Disabled; - } } diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/Utils.java b/test/hotspot/jtreg/compiler/lib/compile_framework/Utils.java new file mode 100644 index 0000000000000..0ac2720f33b19 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/Utils.java @@ -0,0 +1,81 @@ +/* + * 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.compile_framework; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * Utility class, with many helper methods for the Compile Framework. + */ +class Utils { + private static final boolean VERBOSE = Boolean.getBoolean("CompileFrameworkVerbose"); + + /** + * Verbose printing, enabled with {@code -DCompileFrameworkVerbose=true}. + */ + public static void printlnVerbose(String s) { + if (VERBOSE) { + System.out.println(s); + } + } + + /** + * Create a temporary directory with a unique name to avoid collisions + * with multi-threading. Used to create the sources and classes directories. Since they + * are unique even across threads, the Compile Framework is multi-threading safe, i.e. + * it does not have collisions if two instances generate classes with the same name. + */ + public static Path makeUniqueDir(String prefix) { + try { + return Files.createTempDirectory(Paths.get("."), prefix); + } catch (Exception e) { + throw new InternalCompileFrameworkException("Could not set up temporary directory", e); + } + } + + /** + * Get all paths in the classpath. + */ + public static String[] getClassPaths() { + String separator = File.pathSeparator; + return System.getProperty("java.class.path").split(separator); + } + + /** + * Return the classpath, appended with the {@code classesDir}. + */ + public static String getEscapedClassPathAndClassesDir(Path classesDir) { + String cp = System.getProperty("java.class.path") + + File.pathSeparator + + classesDir.toAbsolutePath(); + // Escape the backslash for Windows paths. We are using the path in the + // command-line and Java code, so we always want it to be escaped. + return cp.replace("\\", "\\\\"); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 16f56012d3dd9..8c4b3c93343f6 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -119,13 +119,13 @@ public class IRNode { public static final String VECTOR_SIZE_32 = VECTOR_SIZE + "32"; public static final String VECTOR_SIZE_64 = VECTOR_SIZE + "64"; - private static final String TYPE_BYTE = "byte"; - private static final String TYPE_CHAR = "char"; - private static final String TYPE_SHORT = "short"; - private static final String TYPE_INT = "int"; - private static final String TYPE_LONG = "long"; - private static final String TYPE_FLOAT = "float"; - private static final String TYPE_DOUBLE = "double"; + private static final String TYPE_BYTE = "B"; + private static final String TYPE_CHAR = "C"; + private static final String TYPE_SHORT = "S"; + private static final String TYPE_INT = "I"; + private static final String TYPE_LONG = "J"; + private static final String TYPE_FLOAT = "F"; + private static final String TYPE_DOUBLE = "D"; /** * IR placeholder string to regex-for-compile-phase map. @@ -358,6 +358,11 @@ public class IRNode { beforeMatchingNameRegex(CALL, "Call.*Java"); } + public static final String CALL_OF = COMPOSITE_PREFIX + "CALL_OF" + POSTFIX; + static { + callOfNodes(CALL_OF, "Call.*"); + } + public static final String CALL_OF_METHOD = COMPOSITE_PREFIX + "CALL_OF_METHOD" + POSTFIX; static { callOfNodes(CALL_OF_METHOD, "Call.*Java"); @@ -581,6 +586,92 @@ public class IRNode { vectorNode(FMA_VD, "FmaVD", TYPE_DOUBLE); } + public static final String G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1CompareAndExchangeN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1CompareAndExchangeP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1CompareAndSwapN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1CompareAndSwapP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_ENCODE_P_AND_STORE_N = PREFIX + "G1_ENCODE_P_AND_STORE_N" + POSTFIX; + static { + machOnlyNameRegex(G1_ENCODE_P_AND_STORE_N, "g1EncodePAndStoreN"); + } + + public static final String G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1EncodePAndStoreN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_GET_AND_SET_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_GET_AND_SET_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1GetAndSetN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_GET_AND_SET_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_GET_AND_SET_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_GET_AND_SET_P_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1GetAndSetP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_GET_AND_SET_P_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_LOAD_N = PREFIX + "G1_LOAD_N" + POSTFIX; + static { + machOnlyNameRegex(G1_LOAD_N, "g1LoadN"); + } + + public static final String G1_LOAD_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_LOAD_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1LoadN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_LOAD_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_LOAD_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_LOAD_P_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1LoadP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_LOAD_P_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_STORE_N = PREFIX + "G1_STORE_N" + POSTFIX; + static { + machOnlyNameRegex(G1_STORE_N, "g1StoreN"); + } + + public static final String G1_STORE_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_STORE_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1StoreN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_STORE_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_STORE_P = PREFIX + "G1_STORE_P" + POSTFIX; + static { + machOnlyNameRegex(G1_STORE_P, "g1StoreP"); + } + + public static final String G1_STORE_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_STORE_P_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1StoreP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_STORE_P_WITH_BARRIER_FLAG, regex); + } + public static final String IF = PREFIX + "IF" + POSTFIX; static { beforeMatchingNameRegex(IF, "If\\b"); @@ -852,6 +943,11 @@ public class IRNode { vectorNode(LSHIFT_VL, "LShiftVL", TYPE_LONG); } + public static final String MACH_TEMP = PREFIX + "MACH_TEMP" + POSTFIX; + static { + machOnlyNameRegex(MACH_TEMP, "MachTemp"); + } + public static final String MACRO_LOGIC_V = PREFIX + "MACRO_LOGIC_V" + POSTFIX; static { afterBarrierExpansionToBeforeMatching(MACRO_LOGIC_V, "MacroLogicV"); @@ -1148,6 +1244,12 @@ public class IRNode { trapNodes(NULL_CHECK_TRAP, "null_check"); } + public static final String OOPMAP_WITH = COMPOSITE_PREFIX + "OOPMAP_WITH" + POSTFIX; + static { + String regex = "(#\\s*OopMap\\s*\\{.*" + IS_REPLACED + ".*\\})"; + optoOnly(OOPMAP_WITH, regex); + } + public static final String OR_VB = VECTOR_PREFIX + "OR_VB" + POSTFIX; static { vectorNode(OR_VB, "OrV", TYPE_BYTE); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/checkattribute/parsing/RawIRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/checkattribute/parsing/RawIRNode.java index e7db6c4844ca2..bf3021a6868f1 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/checkattribute/parsing/RawIRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/checkattribute/parsing/RawIRNode.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 @@ -133,7 +133,6 @@ private String regexForVectorIRNode(String nodeRegex, VMInfo vmInfo, Comparison. } } String sizeRegex = IRNode.parseVectorNodeSize(size, type, vmInfo); - return nodeRegex.replaceAll(IRNode.IS_REPLACED, - "vector[A-Za-z]\\\\[" + sizeRegex + "\\\\]:\\\\{" + type + "\\\\}"); + return nodeRegex.replaceAll(IRNode.IS_REPLACED, "vector[A-Za-z]<" + type + "," + sizeRegex + ">"); } } 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 73943db3f5374..cd524622f4e9c 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java @@ -109,7 +109,8 @@ public class IREncodingPrinter { "sve", // Riscv64 "rvv", - "zvbb" + "zvbb", + "zvfh" )); public IREncodingPrinter() { diff --git a/src/hotspot/share/gc/x/xNUMA.hpp b/test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java similarity index 53% rename from src/hotspot/share/gc/x/xNUMA.hpp rename to test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java index 6331a62c042dc..a04af09570fb9 100644 --- a/src/hotspot/share/gc/x/xNUMA.hpp +++ b/test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,28 +21,43 @@ * questions. */ -#ifndef SHARE_GC_X_XNUMA_HPP -#define SHARE_GC_X_XNUMA_HPP - -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" - -class XNUMA : public AllStatic { -private: - static bool _enabled; - - static void pd_initialize(); - -public: - static void initialize(); - static bool is_enabled(); - - static uint32_t count(); - static uint32_t id(); - - static uint32_t memory_id(uintptr_t addr); - - static const char* to_string(); -}; +/** + * @test + * @bug 8336702 + * @summary C2 compilation fails with "all memory state should have been processed" assert + * + * @run main/othervm TestSafePointWithEAState + * + */ -#endif // SHARE_GC_X_XNUMA_HPP +public class TestSafePointWithEAState { + int[] b = new int[400]; + + void c() { + int e; + float f; + for (long d = 0; d < 5000; d++) { + e = 1; + while ((e += 3) < 200) { + if (d < b.length) { + for (int g = 0; g < 10000; ++g) ; + } + } + synchronized (TestSafePointWithEAState.class) { + f = new h(e).n; + } + } + } + + public static void main(String[] m) { + TestSafePointWithEAState o = new TestSafePointWithEAState(); + o.c(); + } +} + +class h { + float n; + h(float n) { + this.n = n; + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestRangeCheckPredicatesControl.java b/test/hotspot/jtreg/compiler/loopopts/TestRangeCheckPredicatesControl.java index a46de67de052e..1f64ed28d8aa1 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestRangeCheckPredicatesControl.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestRangeCheckPredicatesControl.java @@ -22,25 +22,14 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @key stress randomness - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @bug 8237859 * @summary A LoadP node has a wrong control input (too early) which results in an out-of-bounds read of an object array with ZGC. * - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational compiler.loopopts.TestRangeCheckPredicatesControl - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+StressGCM compiler.loopopts.TestRangeCheckPredicatesControl - */ - -/* - * @test id=ZGenerational - * @key stress randomness - * @requires vm.gc.ZGenerational - * @bug 8237859 - * @summary A LoadP node has a wrong control input (too early) which results in an out-of-bounds read of an object array with ZGC. - * - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational compiler.loopopts.TestRangeCheckPredicatesControl - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+StressGCM compiler.loopopts.TestRangeCheckPredicatesControl + * @run main/othervm -XX:+UseZGC compiler.loopopts.TestRangeCheckPredicatesControl + * @run main/othervm -XX:+UseZGC -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+StressGCM compiler.loopopts.TestRangeCheckPredicatesControl */ package compiler.loopopts; diff --git a/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java b/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java new file mode 100644 index 0000000000000..95ba9e6e795ae --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2024 Red Hat and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts.parallel_iv; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +import java.util.Random; + +/** + * @test + * @bug 8328528 + * @summary test the long typed parallel iv replacing transformation for int counted loop + * @library /test/lib / + * @requires vm.compiler2.enabled + * @run driver compiler.loopopts.parallel_iv.TestParallelIvInIntCountedLoop + */ +public class TestParallelIvInIntCountedLoop { + private static final Random RNG = Utils.getRandomInstance(); + + // stride2 must be a multiple of stride and must not overflow for the optimization to work + private static final int STRIDE = RNG.nextInt(1, Integer.MAX_VALUE / 16); + private static final int STRIDE_2 = STRIDE * RNG.nextInt(1, 16); + + public static void main(String[] args) { + TestFramework.runWithFlags( + "-XX:+IgnoreUnrecognizedVMOptions", // StressLongCountedLoop is only available in debug builds + "-XX:StressLongCountedLoop=0", // Don't convert int counted loops to long ones + "-XX:PerMethodTrapLimit=100" // allow slow-path loop limit checks + ); + } + + /* + * The IR framework can only test against static code, and the transformation relies on strides being constants to + * perform constant propagation. Therefore, we have no choice but repeating the same test case multiple times with + * different numbers. + * + * For good measures, randomly initialized static final stride and stride2 is also tested. + */ + + // A controlled test making sure a simple non-counted loop can be found by the test framework. + @Test + @Arguments(values = { Argument.NUMBER_42 }) // otherwise a large number may take too long + @IR(counts = { IRNode.COUNTED_LOOP, ">=1" }) + private static int testControlledSimpleLoop(int stop) { + int a = 0; + for (int i = 0; i < stop; i++) { + a += i; // cannot be extracted to multiplications + } + + return a; + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static int testIntCountedLoopWithIntIV(int stop) { + int a = 0; + for (int i = 0; i < stop; i++) { + a += 1; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithIntIV") + private static void runTestIntCountedLoopWithIntIv() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ(s, testIntCountedLoopWithIntIV(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static int testIntCountedLoopWithIntIVZero(int stop) { + int a = 0; + for (int i = 0; i < stop; i++) { + a += 0; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithIntIVZero") + private static void runTestIntCountedLoopWithIntIVZero() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ(0, testIntCountedLoopWithIntIVZero(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static int testIntCountedLoopWithIntIVMax(int stop) { + int a = 0; + for (int i = 0; i < stop; i++) { + a += Integer.MAX_VALUE; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithIntIVMax") + private static void runTestIntCountedLoopWithIntIVMax() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ(s * Integer.MAX_VALUE, testIntCountedLoopWithIntIVMax(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static int testIntCountedLoopWithIntIVMaxMinusOne(int stop) { + int a = 0; + for (int i = 0; i < stop; i++) { + a += Integer.MAX_VALUE - 1; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithIntIVMaxMinusOne") + private static void runTestIntCountedLoopWithIntIVMaxMinusOne() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ(s * (Integer.MAX_VALUE - 1), testIntCountedLoopWithIntIVMaxMinusOne(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static int testIntCountedLoopWithIntIVMaxPlusOne(int stop) { + int a = 0; + for (int i = 0; i < stop; i++) { + a += Integer.MAX_VALUE + 1; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithIntIVMaxPlusOne") + private static void runTestIntCountedLoopWithIntIVMaxPlusOne() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ(s * (Integer.MAX_VALUE + 1), testIntCountedLoopWithIntIVMaxPlusOne(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static int testIntCountedLoopWithIntIVWithStrideTwo(int stop) { + int a = 0; + for (int i = 0; i < stop; i += 2) { + a += 2; // this stride2 constant must be a multiple of the first stride (i += ...) for optimization + } + + return a; + } + + @Run(test = "testIntCountedLoopWithIntIVWithStrideTwo") + private static void runTestIntCountedLoopWithIntIVWithStrideTwo() { + // Since we can't easily determine expected values if loop variables overflow when incrementing, we make sure + // `stop` is less than (MAX_VALUE - stride). + int s = RNG.nextInt(0, Integer.MAX_VALUE - 2); + Asserts.assertEQ(Math.ceilDiv(s, 2) * 2, testIntCountedLoopWithIntIVWithStrideTwo(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static int testIntCountedLoopWithIntIVWithStrideMinusOne(int stop) { + int a = 0; + for (int i = stop; i > 0; i += -1) { + a += 1; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithIntIVWithStrideMinusOne") + private static void runTestIntCountedLoopWithIntIVWithStrideMinusOne() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ(s, testIntCountedLoopWithIntIVWithStrideMinusOne(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static int testIntCountedLoopWithIntIVWithRandomStrides(int stop) { + int a = 0; + for (int i = 0; i < stop; i += STRIDE) { + a += STRIDE_2; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithIntIVWithRandomStrides") + private static void runTestIntCountedLoopWithIntIVWithRandomStrides() { + // Make sure `stop` is less than (MAX_VALUE - stride) to avoid overflows. + int s = RNG.nextInt(0, Integer.MAX_VALUE - STRIDE); + Asserts.assertEQ(Math.ceilDiv(s, STRIDE) * STRIDE_2, testIntCountedLoopWithIntIVWithRandomStrides(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static int testIntCountedLoopWithIntIVWithRandomStridesAndInits(int init, int init2, int stop) { + int a = init; + for (int i = init2; i < stop; i += STRIDE) { + a += STRIDE_2; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithIntIVWithRandomStridesAndInits") + private static void runTestIntCountedLoopWithIntIVWithRandomStridesAndInits() { + int s = RNG.nextInt(0, Integer.MAX_VALUE - STRIDE); + int init1 = RNG.nextInt(); + int init2 = RNG.nextInt(Integer.MIN_VALUE + s + 1, s); // Limit bounds to avoid loop variables from overflowing. + Asserts.assertEQ(Math.ceilDiv((s - init2), STRIDE) * STRIDE_2 + init1, + testIntCountedLoopWithIntIVWithRandomStridesAndInits(init1, init2, s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static long testIntCountedLoopWithLongIV(int stop) { + long a = 0; + for (int i = 0; i < stop; i++) { + a += 1; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithLongIV") + private static void runTestIntCountedLoopWithLongIV() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ((long) s, testIntCountedLoopWithLongIV(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static long testIntCountedLoopWithLongIVZero(int stop) { + long a = 0; + for (int i = 0; i < stop; i++) { + a += 0; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithLongIVZero") + private static void runTestIntCountedLoopWithLongIVZero() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ((long) 0, testIntCountedLoopWithLongIVZero(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static long testIntCountedLoopWithLongIVMax(int stop) { + long a = 0; + for (int i = 0; i < stop; i++) { + a += Long.MAX_VALUE; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithLongIVMax") + private static void runTestIntCountedLoopWithLongIVMax() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ((long) s * Long.MAX_VALUE, testIntCountedLoopWithLongIVMax(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static long testIntCountedLoopWithLongIVMaxMinusOne(int stop) { + long a = 0; + for (int i = 0; i < stop; i++) { + a += Long.MAX_VALUE - 1; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithLongIVMaxMinusOne") + private static void runTestIntCountedLoopWithLongIVMaxMinusOne() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ((long) s * (Long.MAX_VALUE - 1L), testIntCountedLoopWithLongIVMaxMinusOne(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static long testIntCountedLoopWithLongIVMaxPlusOne(int stop) { + long a = 0; + for (int i = 0; i < stop; i++) { + a += Long.MAX_VALUE + 1; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithLongIVMaxPlusOne") + private static void runTestIntCountedLoopWithLongIVMaxPlusOne() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ((long) s * (Long.MAX_VALUE + 1L), testIntCountedLoopWithLongIVMaxPlusOne(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static long testIntCountedLoopWithLongIVWithStrideTwo(int stop) { + long a = 0; + for (int i = 0; i < stop; i += 2) { + a += 2; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithLongIVWithStrideTwo") + private static void runTestIntCountedLoopWithLongIVWithStrideTwo() { + int s = RNG.nextInt(0, Integer.MAX_VALUE - 2); + Asserts.assertEQ(Math.ceilDiv(s, 2L) * 2L, testIntCountedLoopWithLongIVWithStrideTwo(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static long testIntCountedLoopWithLongIVWithStrideMinusOne(int stop) { + long a = 0; + for (int i = stop; i > 0; i += -1) { + a += 1; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithLongIVWithStrideMinusOne") + private static void runTestIntCountedLoopWithLongIVWithStrideMinusOne() { + int s = RNG.nextInt(0, Integer.MAX_VALUE); + Asserts.assertEQ((long) s, testIntCountedLoopWithLongIVWithStrideMinusOne(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static long testIntCountedLoopWithLongIVWithRandomStrides(int stop) { + long a = 0; + for (int i = 0; i < stop; i += STRIDE) { + a += STRIDE_2; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithLongIVWithRandomStrides") + private static void runTestIntCountedLoopWithLongIVWithRandomStrides() { + int s = RNG.nextInt(0, Integer.MAX_VALUE - STRIDE); + Asserts.assertEQ(Math.ceilDiv(s, (long) STRIDE) * (long) STRIDE_2, + testIntCountedLoopWithLongIVWithRandomStrides(s)); + } + + @Test + @IR(failOn = { IRNode.COUNTED_LOOP }) + private static long testIntCountedLoopWithLongIVWithRandomStridesAndInits(long init, int init2, int stop) { + long a = init; + for (int i = init2; i < stop; i += STRIDE) { + a += STRIDE_2; + } + + return a; + } + + @Run(test = "testIntCountedLoopWithLongIVWithRandomStridesAndInits") + private static void runTestIntCountedLoopWithLongIVWithRandomStridesAndInits() { + int s = RNG.nextInt(0, Integer.MAX_VALUE - STRIDE); + long init1 = RNG.nextLong(); + int init2 = RNG.nextInt(Integer.MIN_VALUE + s + 1, s); // Limit bounds to avoid loop variables from overflowing. + Asserts.assertEQ(Math.ceilDiv(((long) s - init2), (long) STRIDE) * (long) STRIDE_2 + init1, + testIntCountedLoopWithLongIVWithRandomStridesAndInits(init1, init2, s)); + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java index fd5c2969074f9..c77f4f6fa2e25 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java @@ -1363,7 +1363,7 @@ static Object[] test16b(byte[] a) { static Object[] test17a(long[] a) { // Unsafe: vectorizes with profiling (not xcomp) for (int i = 0; i < RANGE; i++) { - int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i; + long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i; long v = UNSAFE.getLongUnaligned(a, adr); UNSAFE.putLongUnaligned(a, adr, v + 1); } @@ -1375,7 +1375,7 @@ static Object[] test17a(long[] a) { static Object[] test17b(long[] a) { // Not alignable for (int i = 0; i < RANGE-1; i++) { - int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i + 1; + long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i + 1; long v = UNSAFE.getLongUnaligned(a, adr); UNSAFE.putLongUnaligned(a, adr, v + 1); } @@ -1392,7 +1392,7 @@ static Object[] test17b(long[] a) { static Object[] test17c(long[] a) { // Unsafe: aligned vectorizes for (int i = 0; i < RANGE-1; i+=4) { - int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i; + long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i; long v0 = UNSAFE.getLongUnaligned(a, adr + 0); long v1 = UNSAFE.getLongUnaligned(a, adr + 8); UNSAFE.putLongUnaligned(a, adr + 0, v0 + 1); @@ -1422,7 +1422,7 @@ static Object[] test17c(long[] a) { static Object[] test17d(long[] a) { // Not alignable for (int i = 0; i < RANGE-1; i+=4) { - int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i + 1; + long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i + 1; long v0 = UNSAFE.getLongUnaligned(a, adr + 0); long v1 = UNSAFE.getLongUnaligned(a, adr + 8); UNSAFE.putLongUnaligned(a, adr + 0, v0 + 1); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java index 7b95781905ead..d75db965ea3c1 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java @@ -1090,11 +1090,11 @@ static Object[] testUU_unsafe_BasI(byte[] a) { int init = init_con_or_var(); int limit = limit_con_or_var(); int stride = stride_con(); - int scale = scale_con(); - int offset = offset1_con_or_var(); + long scale = scale_con(); + long offset = offset1_con_or_var(); for (int i = init; i < limit; i += stride) { - int adr = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + i * scale; + long adr = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + i * scale; int v = UNSAFE.getIntUnaligned(a, adr); UNSAFE.putIntUnaligned(a, adr, v + 1); } @@ -1105,19 +1105,19 @@ static Object[] testUU_unsafe_BasIH(byte[] a, byte[] b, byte[] c) { int init = init_con_or_var(); int limit = limit_con_or_var(); int stride = stride_con(); - int scale = scale_con(); - int offset1 = offset1_con_or_var(); - int offset2 = offset2_con_or_var(); - int offset3 = offset3_con_or_var(); + long scale = scale_con(); + long offset1 = offset1_con_or_var(); + long offset2 = offset2_con_or_var(); + long offset3 = offset3_con_or_var(); int h1 = hand_unrolling1_con(); int h2 = hand_unrolling2_con(); int h3 = hand_unrolling3_con(); for (int i = init; i < limit; i += stride) { - int adr1 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset1 + i * scale; - int adr2 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset2 + i * scale; - int adr3 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset3 + i * scale; + long adr1 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset1 + i * scale; + long adr2 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset2 + i * scale; + long adr3 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset3 + i * scale; if (h1 >= 1) { UNSAFE.putIntUnaligned(a, adr1 + 0*4, UNSAFE.getIntUnaligned(a, adr1 + 0*4) + 1); } if (h1 >= 2) { UNSAFE.putIntUnaligned(a, adr1 + 1*4, UNSAFE.getIntUnaligned(a, adr1 + 1*4) + 1); } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java index 2f0a5809d0849..8e5ac88a27da4 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java @@ -21,99 +21,12 @@ * questions. */ -/* - * Summary: - * Test SuperWord vectorization with different access offsets - * and various MaxVectorSize values, and +- AlignVector. - * - * Note: this test is auto-generated. Please modify / generate with script: - * https://bugs.openjdk.org/browse/JDK-8333729 - * - * Types: int, long, short, char, byte, float, double - * Offsets: 0, -1, 1, -2, 2, -3, 3, -4, 4, -7, 7, -8, 8, -14, 14, -16, 16, -18, 18, -20, 20, -31, 31, -32, 32, -63, 63, -64, 64, -65, 65, -128, 128, -129, 129, -192, 192 - * - * Checking if we should vectorize is a bit complicated. It depends on - * Matcher::vector_width_in_bytes, of the respective platforms (eg. x86.ad) - * This vector_width can be further constrained by MaxVectorSize. - * - * With '-XX:-AlignVector', we vectorize if: - * - Vectors have at least 4 bytes: vector_width >= 4 - * - Vectors hold at least 2 elements: vector_width >= 2 * sizeofop(velt_type) - * -> min_vector_width = max(4, 2 * sizeofop(velt_type)) - * -> simplifies to: vector_width >= min_vector_width - * - No cyclic dependency: - * - Access: data[i + offset] = data[i] * fac; - * - byte_offset = offset * sizeofop(type) - * - Cyclic dependency if: 0 < byte_offset < vector_width - * - * Note: sizeofop(type) = sizeof(type), except sizeofop(char) = 2 - * - * Different types can lead to different vector_width. This depends on - * the CPU-features. - * - * Definition: - * MaxVectorSize: limit through flag - * vector_width: limit given by specific CPU feature for a specific velt_type - * actual_vector_width: what is actually vectorized with - * min_vector_width: what is minimally required for vectorization - * - * min_vector_width = max(4, 2 * sizeofop(velt_type)) - * MaxVectorSize >= vector_width >= actual_vector_width >= min_vector_width - * - * In general, we cannot easily specify negative IR rules, that require no - * vectorization to happen. We may improve the SuperWord algorithm later, - * or some additional optimization collapses some Loads, and suddenly cyclic - * dependency disappears, and we can vectorize. - * - * With '-XX:+AlignVector' we do the following: - * - * Must vectorize cleanly if: - * 1) guaranteed no misalignment AND - * 2) guaratneed no cyclic dependency - * - * Must not vectorize at all if: - * 1) guaranteed misalignment AND - * 2) guaranteed no cyclic dependency - * - * We could imagine a case with cyclic dependency, where C2 detects - * that only the first load is needed, and so no vectorization is - * required for it, and hence the store vector can be aligned. - * - * The alignment criteria is - * byte_offset % aw == 0 - * where align width (aw) is - * aw = min(actual_vector_width, ObjectAlignmentInBytes) - * For simplicity, we assume that ObjectAlignmentInBytes == 8, - * which currently can only be changed manually and then no IR - * rule is run. - * This allows us to do the computation statically. - * Further, we define: - * aw_min = min(min_vector_width, ObjectAlignmentInBytes) - * aw_max = min(vector_width, ObjectAlignmentInBytes) - * aw_min <= aw <= aw_max - * - * Again, we have no cyclic dependency, except when: - * byte_offset > 0 and p.vector_width > byte_offset - * Here we must ensure that: - * byte_offset >= MaxVectorSize - * - * Guaranteed no misalignment: - * byte_offset % aw_max == 0 - * implies - * byte_offset % aw == 0 - * - * Guaranteed misalignment: - * byte_offset % aw_min != 0 - * implies - * byte_offset % aw != 0 - * - */ - /* * @test id=vanilla-A * @bug 8298935 8308606 8310308 8312570 8310190 * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vanilla-A */ @@ -122,6 +35,7 @@ * @bug 8298935 8308606 8310308 8312570 8310190 * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vanilla-U */ @@ -133,6 +47,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v016-A */ @@ -144,6 +59,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v016-U */ @@ -155,6 +71,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v008-A */ @@ -166,6 +83,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v008-U */ @@ -177,6 +95,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v004-A */ @@ -188,31 +107,10 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v004-U */ -/* - * @test id=sse4-v002-A - * @bug 8298935 8308606 8310308 8312570 8310190 - * @summary Test SuperWord: vector size, offsets, dependencies, alignment. - * @requires vm.compiler2.enabled - * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") - * @requires vm.cpu.features ~= ".*sse4.*" - * @library /test/lib / - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v002-A - */ - -/* - * @test id=sse4-v002-U - * @bug 8298935 8308606 8310308 8312570 8310190 - * @summary Test SuperWord: vector size, offsets, dependencies, alignment. - * @requires vm.compiler2.enabled - * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") - * @requires vm.cpu.features ~= ".*sse4.*" - * @library /test/lib / - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v002-U - */ - /* * @test id=avx1-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 @@ -221,6 +119,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v032-A */ @@ -232,6 +131,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v032-U */ @@ -243,6 +143,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v016-A */ @@ -254,6 +155,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v016-U */ @@ -265,6 +167,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v032-A */ @@ -276,6 +179,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v032-U */ @@ -287,6 +191,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v016-A */ @@ -298,6 +203,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v016-U */ @@ -309,6 +215,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v064-A */ @@ -320,6 +227,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v064-U */ @@ -331,6 +239,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v032-A */ @@ -342,6 +251,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v032-U */ @@ -353,6 +263,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v064-A */ @@ -364,6 +275,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v064-U */ @@ -375,6 +287,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v032-A */ @@ -386,6 +299,7 @@ * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v032-U */ @@ -396,6 +310,7 @@ * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v064-A */ @@ -406,6 +321,7 @@ * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v064-U */ @@ -416,6 +332,7 @@ * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v032-A */ @@ -426,6 +343,7 @@ * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v032-U */ @@ -436,6 +354,7 @@ * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v016-A */ @@ -446,6 +365,7 @@ * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v016-U */ @@ -456,6 +376,7 @@ * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v008-A */ @@ -466,6 +387,7 @@ * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v008-U */ @@ -476,6 +398,7 @@ * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v004-A */ @@ -486,15418 +409,500 @@ * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / + * @compile ../../lib/ir_framework/TestFramework.java * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v004-U */ package compiler.loopopts.superword; -import compiler.lib.ir_framework.*; -public class TestDependencyOffsets { - static final int RANGE = 512; - - static int[] goldIntP0 = new int[RANGE]; - static int[] goldIntM1 = new int[RANGE]; - static int[] goldIntP1 = new int[RANGE]; - static int[] goldIntM2 = new int[RANGE]; - static int[] goldIntP2 = new int[RANGE]; - static int[] goldIntM3 = new int[RANGE]; - static int[] goldIntP3 = new int[RANGE]; - static int[] goldIntM4 = new int[RANGE]; - static int[] goldIntP4 = new int[RANGE]; - static int[] goldIntM7 = new int[RANGE]; - static int[] goldIntP7 = new int[RANGE]; - static int[] goldIntM8 = new int[RANGE]; - static int[] goldIntP8 = new int[RANGE]; - static int[] goldIntM14 = new int[RANGE]; - static int[] goldIntP14 = new int[RANGE]; - static int[] goldIntM16 = new int[RANGE]; - static int[] goldIntP16 = new int[RANGE]; - static int[] goldIntM18 = new int[RANGE]; - static int[] goldIntP18 = new int[RANGE]; - static int[] goldIntM20 = new int[RANGE]; - static int[] goldIntP20 = new int[RANGE]; - static int[] goldIntM31 = new int[RANGE]; - static int[] goldIntP31 = new int[RANGE]; - static int[] goldIntM32 = new int[RANGE]; - static int[] goldIntP32 = new int[RANGE]; - static int[] goldIntM63 = new int[RANGE]; - static int[] goldIntP63 = new int[RANGE]; - static int[] goldIntM64 = new int[RANGE]; - static int[] goldIntP64 = new int[RANGE]; - static int[] goldIntM65 = new int[RANGE]; - static int[] goldIntP65 = new int[RANGE]; - static int[] goldIntM128 = new int[RANGE]; - static int[] goldIntP128 = new int[RANGE]; - static int[] goldIntM129 = new int[RANGE]; - static int[] goldIntP129 = new int[RANGE]; - static int[] goldIntM192 = new int[RANGE]; - static int[] goldIntP192 = new int[RANGE]; - static long[] goldLongP0 = new long[RANGE]; - static long[] goldLongM1 = new long[RANGE]; - static long[] goldLongP1 = new long[RANGE]; - static long[] goldLongM2 = new long[RANGE]; - static long[] goldLongP2 = new long[RANGE]; - static long[] goldLongM3 = new long[RANGE]; - static long[] goldLongP3 = new long[RANGE]; - static long[] goldLongM4 = new long[RANGE]; - static long[] goldLongP4 = new long[RANGE]; - static long[] goldLongM7 = new long[RANGE]; - static long[] goldLongP7 = new long[RANGE]; - static long[] goldLongM8 = new long[RANGE]; - static long[] goldLongP8 = new long[RANGE]; - static long[] goldLongM14 = new long[RANGE]; - static long[] goldLongP14 = new long[RANGE]; - static long[] goldLongM16 = new long[RANGE]; - static long[] goldLongP16 = new long[RANGE]; - static long[] goldLongM18 = new long[RANGE]; - static long[] goldLongP18 = new long[RANGE]; - static long[] goldLongM20 = new long[RANGE]; - static long[] goldLongP20 = new long[RANGE]; - static long[] goldLongM31 = new long[RANGE]; - static long[] goldLongP31 = new long[RANGE]; - static long[] goldLongM32 = new long[RANGE]; - static long[] goldLongP32 = new long[RANGE]; - static long[] goldLongM63 = new long[RANGE]; - static long[] goldLongP63 = new long[RANGE]; - static long[] goldLongM64 = new long[RANGE]; - static long[] goldLongP64 = new long[RANGE]; - static long[] goldLongM65 = new long[RANGE]; - static long[] goldLongP65 = new long[RANGE]; - static long[] goldLongM128 = new long[RANGE]; - static long[] goldLongP128 = new long[RANGE]; - static long[] goldLongM129 = new long[RANGE]; - static long[] goldLongP129 = new long[RANGE]; - static long[] goldLongM192 = new long[RANGE]; - static long[] goldLongP192 = new long[RANGE]; - static short[] goldShortP0 = new short[RANGE]; - static short[] goldShortM1 = new short[RANGE]; - static short[] goldShortP1 = new short[RANGE]; - static short[] goldShortM2 = new short[RANGE]; - static short[] goldShortP2 = new short[RANGE]; - static short[] goldShortM3 = new short[RANGE]; - static short[] goldShortP3 = new short[RANGE]; - static short[] goldShortM4 = new short[RANGE]; - static short[] goldShortP4 = new short[RANGE]; - static short[] goldShortM7 = new short[RANGE]; - static short[] goldShortP7 = new short[RANGE]; - static short[] goldShortM8 = new short[RANGE]; - static short[] goldShortP8 = new short[RANGE]; - static short[] goldShortM14 = new short[RANGE]; - static short[] goldShortP14 = new short[RANGE]; - static short[] goldShortM16 = new short[RANGE]; - static short[] goldShortP16 = new short[RANGE]; - static short[] goldShortM18 = new short[RANGE]; - static short[] goldShortP18 = new short[RANGE]; - static short[] goldShortM20 = new short[RANGE]; - static short[] goldShortP20 = new short[RANGE]; - static short[] goldShortM31 = new short[RANGE]; - static short[] goldShortP31 = new short[RANGE]; - static short[] goldShortM32 = new short[RANGE]; - static short[] goldShortP32 = new short[RANGE]; - static short[] goldShortM63 = new short[RANGE]; - static short[] goldShortP63 = new short[RANGE]; - static short[] goldShortM64 = new short[RANGE]; - static short[] goldShortP64 = new short[RANGE]; - static short[] goldShortM65 = new short[RANGE]; - static short[] goldShortP65 = new short[RANGE]; - static short[] goldShortM128 = new short[RANGE]; - static short[] goldShortP128 = new short[RANGE]; - static short[] goldShortM129 = new short[RANGE]; - static short[] goldShortP129 = new short[RANGE]; - static short[] goldShortM192 = new short[RANGE]; - static short[] goldShortP192 = new short[RANGE]; - static char[] goldCharP0 = new char[RANGE]; - static char[] goldCharM1 = new char[RANGE]; - static char[] goldCharP1 = new char[RANGE]; - static char[] goldCharM2 = new char[RANGE]; - static char[] goldCharP2 = new char[RANGE]; - static char[] goldCharM3 = new char[RANGE]; - static char[] goldCharP3 = new char[RANGE]; - static char[] goldCharM4 = new char[RANGE]; - static char[] goldCharP4 = new char[RANGE]; - static char[] goldCharM7 = new char[RANGE]; - static char[] goldCharP7 = new char[RANGE]; - static char[] goldCharM8 = new char[RANGE]; - static char[] goldCharP8 = new char[RANGE]; - static char[] goldCharM14 = new char[RANGE]; - static char[] goldCharP14 = new char[RANGE]; - static char[] goldCharM16 = new char[RANGE]; - static char[] goldCharP16 = new char[RANGE]; - static char[] goldCharM18 = new char[RANGE]; - static char[] goldCharP18 = new char[RANGE]; - static char[] goldCharM20 = new char[RANGE]; - static char[] goldCharP20 = new char[RANGE]; - static char[] goldCharM31 = new char[RANGE]; - static char[] goldCharP31 = new char[RANGE]; - static char[] goldCharM32 = new char[RANGE]; - static char[] goldCharP32 = new char[RANGE]; - static char[] goldCharM63 = new char[RANGE]; - static char[] goldCharP63 = new char[RANGE]; - static char[] goldCharM64 = new char[RANGE]; - static char[] goldCharP64 = new char[RANGE]; - static char[] goldCharM65 = new char[RANGE]; - static char[] goldCharP65 = new char[RANGE]; - static char[] goldCharM128 = new char[RANGE]; - static char[] goldCharP128 = new char[RANGE]; - static char[] goldCharM129 = new char[RANGE]; - static char[] goldCharP129 = new char[RANGE]; - static char[] goldCharM192 = new char[RANGE]; - static char[] goldCharP192 = new char[RANGE]; - static byte[] goldByteP0 = new byte[RANGE]; - static byte[] goldByteM1 = new byte[RANGE]; - static byte[] goldByteP1 = new byte[RANGE]; - static byte[] goldByteM2 = new byte[RANGE]; - static byte[] goldByteP2 = new byte[RANGE]; - static byte[] goldByteM3 = new byte[RANGE]; - static byte[] goldByteP3 = new byte[RANGE]; - static byte[] goldByteM4 = new byte[RANGE]; - static byte[] goldByteP4 = new byte[RANGE]; - static byte[] goldByteM7 = new byte[RANGE]; - static byte[] goldByteP7 = new byte[RANGE]; - static byte[] goldByteM8 = new byte[RANGE]; - static byte[] goldByteP8 = new byte[RANGE]; - static byte[] goldByteM14 = new byte[RANGE]; - static byte[] goldByteP14 = new byte[RANGE]; - static byte[] goldByteM16 = new byte[RANGE]; - static byte[] goldByteP16 = new byte[RANGE]; - static byte[] goldByteM18 = new byte[RANGE]; - static byte[] goldByteP18 = new byte[RANGE]; - static byte[] goldByteM20 = new byte[RANGE]; - static byte[] goldByteP20 = new byte[RANGE]; - static byte[] goldByteM31 = new byte[RANGE]; - static byte[] goldByteP31 = new byte[RANGE]; - static byte[] goldByteM32 = new byte[RANGE]; - static byte[] goldByteP32 = new byte[RANGE]; - static byte[] goldByteM63 = new byte[RANGE]; - static byte[] goldByteP63 = new byte[RANGE]; - static byte[] goldByteM64 = new byte[RANGE]; - static byte[] goldByteP64 = new byte[RANGE]; - static byte[] goldByteM65 = new byte[RANGE]; - static byte[] goldByteP65 = new byte[RANGE]; - static byte[] goldByteM128 = new byte[RANGE]; - static byte[] goldByteP128 = new byte[RANGE]; - static byte[] goldByteM129 = new byte[RANGE]; - static byte[] goldByteP129 = new byte[RANGE]; - static byte[] goldByteM192 = new byte[RANGE]; - static byte[] goldByteP192 = new byte[RANGE]; - static float[] goldFloatP0 = new float[RANGE]; - static float[] goldFloatM1 = new float[RANGE]; - static float[] goldFloatP1 = new float[RANGE]; - static float[] goldFloatM2 = new float[RANGE]; - static float[] goldFloatP2 = new float[RANGE]; - static float[] goldFloatM3 = new float[RANGE]; - static float[] goldFloatP3 = new float[RANGE]; - static float[] goldFloatM4 = new float[RANGE]; - static float[] goldFloatP4 = new float[RANGE]; - static float[] goldFloatM7 = new float[RANGE]; - static float[] goldFloatP7 = new float[RANGE]; - static float[] goldFloatM8 = new float[RANGE]; - static float[] goldFloatP8 = new float[RANGE]; - static float[] goldFloatM14 = new float[RANGE]; - static float[] goldFloatP14 = new float[RANGE]; - static float[] goldFloatM16 = new float[RANGE]; - static float[] goldFloatP16 = new float[RANGE]; - static float[] goldFloatM18 = new float[RANGE]; - static float[] goldFloatP18 = new float[RANGE]; - static float[] goldFloatM20 = new float[RANGE]; - static float[] goldFloatP20 = new float[RANGE]; - static float[] goldFloatM31 = new float[RANGE]; - static float[] goldFloatP31 = new float[RANGE]; - static float[] goldFloatM32 = new float[RANGE]; - static float[] goldFloatP32 = new float[RANGE]; - static float[] goldFloatM63 = new float[RANGE]; - static float[] goldFloatP63 = new float[RANGE]; - static float[] goldFloatM64 = new float[RANGE]; - static float[] goldFloatP64 = new float[RANGE]; - static float[] goldFloatM65 = new float[RANGE]; - static float[] goldFloatP65 = new float[RANGE]; - static float[] goldFloatM128 = new float[RANGE]; - static float[] goldFloatP128 = new float[RANGE]; - static float[] goldFloatM129 = new float[RANGE]; - static float[] goldFloatP129 = new float[RANGE]; - static float[] goldFloatM192 = new float[RANGE]; - static float[] goldFloatP192 = new float[RANGE]; - static double[] goldDoubleP0 = new double[RANGE]; - static double[] goldDoubleM1 = new double[RANGE]; - static double[] goldDoubleP1 = new double[RANGE]; - static double[] goldDoubleM2 = new double[RANGE]; - static double[] goldDoubleP2 = new double[RANGE]; - static double[] goldDoubleM3 = new double[RANGE]; - static double[] goldDoubleP3 = new double[RANGE]; - static double[] goldDoubleM4 = new double[RANGE]; - static double[] goldDoubleP4 = new double[RANGE]; - static double[] goldDoubleM7 = new double[RANGE]; - static double[] goldDoubleP7 = new double[RANGE]; - static double[] goldDoubleM8 = new double[RANGE]; - static double[] goldDoubleP8 = new double[RANGE]; - static double[] goldDoubleM14 = new double[RANGE]; - static double[] goldDoubleP14 = new double[RANGE]; - static double[] goldDoubleM16 = new double[RANGE]; - static double[] goldDoubleP16 = new double[RANGE]; - static double[] goldDoubleM18 = new double[RANGE]; - static double[] goldDoubleP18 = new double[RANGE]; - static double[] goldDoubleM20 = new double[RANGE]; - static double[] goldDoubleP20 = new double[RANGE]; - static double[] goldDoubleM31 = new double[RANGE]; - static double[] goldDoubleP31 = new double[RANGE]; - static double[] goldDoubleM32 = new double[RANGE]; - static double[] goldDoubleP32 = new double[RANGE]; - static double[] goldDoubleM63 = new double[RANGE]; - static double[] goldDoubleP63 = new double[RANGE]; - static double[] goldDoubleM64 = new double[RANGE]; - static double[] goldDoubleP64 = new double[RANGE]; - static double[] goldDoubleM65 = new double[RANGE]; - static double[] goldDoubleP65 = new double[RANGE]; - static double[] goldDoubleM128 = new double[RANGE]; - static double[] goldDoubleP128 = new double[RANGE]; - static double[] goldDoubleM129 = new double[RANGE]; - static double[] goldDoubleP129 = new double[RANGE]; - static double[] goldDoubleM192 = new double[RANGE]; - static double[] goldDoubleP192 = new double[RANGE]; - - static { - // compute the gold standard in interpreter mode - init(goldIntP0); - testIntP0(goldIntP0); - init(goldIntM1); - testIntM1(goldIntM1); - init(goldIntP1); - testIntP1(goldIntP1); - init(goldIntM2); - testIntM2(goldIntM2); - init(goldIntP2); - testIntP2(goldIntP2); - init(goldIntM3); - testIntM3(goldIntM3); - init(goldIntP3); - testIntP3(goldIntP3); - init(goldIntM4); - testIntM4(goldIntM4); - init(goldIntP4); - testIntP4(goldIntP4); - init(goldIntM7); - testIntM7(goldIntM7); - init(goldIntP7); - testIntP7(goldIntP7); - init(goldIntM8); - testIntM8(goldIntM8); - init(goldIntP8); - testIntP8(goldIntP8); - init(goldIntM14); - testIntM14(goldIntM14); - init(goldIntP14); - testIntP14(goldIntP14); - init(goldIntM16); - testIntM16(goldIntM16); - init(goldIntP16); - testIntP16(goldIntP16); - init(goldIntM18); - testIntM18(goldIntM18); - init(goldIntP18); - testIntP18(goldIntP18); - init(goldIntM20); - testIntM20(goldIntM20); - init(goldIntP20); - testIntP20(goldIntP20); - init(goldIntM31); - testIntM31(goldIntM31); - init(goldIntP31); - testIntP31(goldIntP31); - init(goldIntM32); - testIntM32(goldIntM32); - init(goldIntP32); - testIntP32(goldIntP32); - init(goldIntM63); - testIntM63(goldIntM63); - init(goldIntP63); - testIntP63(goldIntP63); - init(goldIntM64); - testIntM64(goldIntM64); - init(goldIntP64); - testIntP64(goldIntP64); - init(goldIntM65); - testIntM65(goldIntM65); - init(goldIntP65); - testIntP65(goldIntP65); - init(goldIntM128); - testIntM128(goldIntM128); - init(goldIntP128); - testIntP128(goldIntP128); - init(goldIntM129); - testIntM129(goldIntM129); - init(goldIntP129); - testIntP129(goldIntP129); - init(goldIntM192); - testIntM192(goldIntM192); - init(goldIntP192); - testIntP192(goldIntP192); - init(goldLongP0); - testLongP0(goldLongP0); - init(goldLongM1); - testLongM1(goldLongM1); - init(goldLongP1); - testLongP1(goldLongP1); - init(goldLongM2); - testLongM2(goldLongM2); - init(goldLongP2); - testLongP2(goldLongP2); - init(goldLongM3); - testLongM3(goldLongM3); - init(goldLongP3); - testLongP3(goldLongP3); - init(goldLongM4); - testLongM4(goldLongM4); - init(goldLongP4); - testLongP4(goldLongP4); - init(goldLongM7); - testLongM7(goldLongM7); - init(goldLongP7); - testLongP7(goldLongP7); - init(goldLongM8); - testLongM8(goldLongM8); - init(goldLongP8); - testLongP8(goldLongP8); - init(goldLongM14); - testLongM14(goldLongM14); - init(goldLongP14); - testLongP14(goldLongP14); - init(goldLongM16); - testLongM16(goldLongM16); - init(goldLongP16); - testLongP16(goldLongP16); - init(goldLongM18); - testLongM18(goldLongM18); - init(goldLongP18); - testLongP18(goldLongP18); - init(goldLongM20); - testLongM20(goldLongM20); - init(goldLongP20); - testLongP20(goldLongP20); - init(goldLongM31); - testLongM31(goldLongM31); - init(goldLongP31); - testLongP31(goldLongP31); - init(goldLongM32); - testLongM32(goldLongM32); - init(goldLongP32); - testLongP32(goldLongP32); - init(goldLongM63); - testLongM63(goldLongM63); - init(goldLongP63); - testLongP63(goldLongP63); - init(goldLongM64); - testLongM64(goldLongM64); - init(goldLongP64); - testLongP64(goldLongP64); - init(goldLongM65); - testLongM65(goldLongM65); - init(goldLongP65); - testLongP65(goldLongP65); - init(goldLongM128); - testLongM128(goldLongM128); - init(goldLongP128); - testLongP128(goldLongP128); - init(goldLongM129); - testLongM129(goldLongM129); - init(goldLongP129); - testLongP129(goldLongP129); - init(goldLongM192); - testLongM192(goldLongM192); - init(goldLongP192); - testLongP192(goldLongP192); - init(goldShortP0); - testShortP0(goldShortP0); - init(goldShortM1); - testShortM1(goldShortM1); - init(goldShortP1); - testShortP1(goldShortP1); - init(goldShortM2); - testShortM2(goldShortM2); - init(goldShortP2); - testShortP2(goldShortP2); - init(goldShortM3); - testShortM3(goldShortM3); - init(goldShortP3); - testShortP3(goldShortP3); - init(goldShortM4); - testShortM4(goldShortM4); - init(goldShortP4); - testShortP4(goldShortP4); - init(goldShortM7); - testShortM7(goldShortM7); - init(goldShortP7); - testShortP7(goldShortP7); - init(goldShortM8); - testShortM8(goldShortM8); - init(goldShortP8); - testShortP8(goldShortP8); - init(goldShortM14); - testShortM14(goldShortM14); - init(goldShortP14); - testShortP14(goldShortP14); - init(goldShortM16); - testShortM16(goldShortM16); - init(goldShortP16); - testShortP16(goldShortP16); - init(goldShortM18); - testShortM18(goldShortM18); - init(goldShortP18); - testShortP18(goldShortP18); - init(goldShortM20); - testShortM20(goldShortM20); - init(goldShortP20); - testShortP20(goldShortP20); - init(goldShortM31); - testShortM31(goldShortM31); - init(goldShortP31); - testShortP31(goldShortP31); - init(goldShortM32); - testShortM32(goldShortM32); - init(goldShortP32); - testShortP32(goldShortP32); - init(goldShortM63); - testShortM63(goldShortM63); - init(goldShortP63); - testShortP63(goldShortP63); - init(goldShortM64); - testShortM64(goldShortM64); - init(goldShortP64); - testShortP64(goldShortP64); - init(goldShortM65); - testShortM65(goldShortM65); - init(goldShortP65); - testShortP65(goldShortP65); - init(goldShortM128); - testShortM128(goldShortM128); - init(goldShortP128); - testShortP128(goldShortP128); - init(goldShortM129); - testShortM129(goldShortM129); - init(goldShortP129); - testShortP129(goldShortP129); - init(goldShortM192); - testShortM192(goldShortM192); - init(goldShortP192); - testShortP192(goldShortP192); - init(goldCharP0); - testCharP0(goldCharP0); - init(goldCharM1); - testCharM1(goldCharM1); - init(goldCharP1); - testCharP1(goldCharP1); - init(goldCharM2); - testCharM2(goldCharM2); - init(goldCharP2); - testCharP2(goldCharP2); - init(goldCharM3); - testCharM3(goldCharM3); - init(goldCharP3); - testCharP3(goldCharP3); - init(goldCharM4); - testCharM4(goldCharM4); - init(goldCharP4); - testCharP4(goldCharP4); - init(goldCharM7); - testCharM7(goldCharM7); - init(goldCharP7); - testCharP7(goldCharP7); - init(goldCharM8); - testCharM8(goldCharM8); - init(goldCharP8); - testCharP8(goldCharP8); - init(goldCharM14); - testCharM14(goldCharM14); - init(goldCharP14); - testCharP14(goldCharP14); - init(goldCharM16); - testCharM16(goldCharM16); - init(goldCharP16); - testCharP16(goldCharP16); - init(goldCharM18); - testCharM18(goldCharM18); - init(goldCharP18); - testCharP18(goldCharP18); - init(goldCharM20); - testCharM20(goldCharM20); - init(goldCharP20); - testCharP20(goldCharP20); - init(goldCharM31); - testCharM31(goldCharM31); - init(goldCharP31); - testCharP31(goldCharP31); - init(goldCharM32); - testCharM32(goldCharM32); - init(goldCharP32); - testCharP32(goldCharP32); - init(goldCharM63); - testCharM63(goldCharM63); - init(goldCharP63); - testCharP63(goldCharP63); - init(goldCharM64); - testCharM64(goldCharM64); - init(goldCharP64); - testCharP64(goldCharP64); - init(goldCharM65); - testCharM65(goldCharM65); - init(goldCharP65); - testCharP65(goldCharP65); - init(goldCharM128); - testCharM128(goldCharM128); - init(goldCharP128); - testCharP128(goldCharP128); - init(goldCharM129); - testCharM129(goldCharM129); - init(goldCharP129); - testCharP129(goldCharP129); - init(goldCharM192); - testCharM192(goldCharM192); - init(goldCharP192); - testCharP192(goldCharP192); - init(goldByteP0); - testByteP0(goldByteP0); - init(goldByteM1); - testByteM1(goldByteM1); - init(goldByteP1); - testByteP1(goldByteP1); - init(goldByteM2); - testByteM2(goldByteM2); - init(goldByteP2); - testByteP2(goldByteP2); - init(goldByteM3); - testByteM3(goldByteM3); - init(goldByteP3); - testByteP3(goldByteP3); - init(goldByteM4); - testByteM4(goldByteM4); - init(goldByteP4); - testByteP4(goldByteP4); - init(goldByteM7); - testByteM7(goldByteM7); - init(goldByteP7); - testByteP7(goldByteP7); - init(goldByteM8); - testByteM8(goldByteM8); - init(goldByteP8); - testByteP8(goldByteP8); - init(goldByteM14); - testByteM14(goldByteM14); - init(goldByteP14); - testByteP14(goldByteP14); - init(goldByteM16); - testByteM16(goldByteM16); - init(goldByteP16); - testByteP16(goldByteP16); - init(goldByteM18); - testByteM18(goldByteM18); - init(goldByteP18); - testByteP18(goldByteP18); - init(goldByteM20); - testByteM20(goldByteM20); - init(goldByteP20); - testByteP20(goldByteP20); - init(goldByteM31); - testByteM31(goldByteM31); - init(goldByteP31); - testByteP31(goldByteP31); - init(goldByteM32); - testByteM32(goldByteM32); - init(goldByteP32); - testByteP32(goldByteP32); - init(goldByteM63); - testByteM63(goldByteM63); - init(goldByteP63); - testByteP63(goldByteP63); - init(goldByteM64); - testByteM64(goldByteM64); - init(goldByteP64); - testByteP64(goldByteP64); - init(goldByteM65); - testByteM65(goldByteM65); - init(goldByteP65); - testByteP65(goldByteP65); - init(goldByteM128); - testByteM128(goldByteM128); - init(goldByteP128); - testByteP128(goldByteP128); - init(goldByteM129); - testByteM129(goldByteM129); - init(goldByteP129); - testByteP129(goldByteP129); - init(goldByteM192); - testByteM192(goldByteM192); - init(goldByteP192); - testByteP192(goldByteP192); - init(goldFloatP0); - testFloatP0(goldFloatP0); - init(goldFloatM1); - testFloatM1(goldFloatM1); - init(goldFloatP1); - testFloatP1(goldFloatP1); - init(goldFloatM2); - testFloatM2(goldFloatM2); - init(goldFloatP2); - testFloatP2(goldFloatP2); - init(goldFloatM3); - testFloatM3(goldFloatM3); - init(goldFloatP3); - testFloatP3(goldFloatP3); - init(goldFloatM4); - testFloatM4(goldFloatM4); - init(goldFloatP4); - testFloatP4(goldFloatP4); - init(goldFloatM7); - testFloatM7(goldFloatM7); - init(goldFloatP7); - testFloatP7(goldFloatP7); - init(goldFloatM8); - testFloatM8(goldFloatM8); - init(goldFloatP8); - testFloatP8(goldFloatP8); - init(goldFloatM14); - testFloatM14(goldFloatM14); - init(goldFloatP14); - testFloatP14(goldFloatP14); - init(goldFloatM16); - testFloatM16(goldFloatM16); - init(goldFloatP16); - testFloatP16(goldFloatP16); - init(goldFloatM18); - testFloatM18(goldFloatM18); - init(goldFloatP18); - testFloatP18(goldFloatP18); - init(goldFloatM20); - testFloatM20(goldFloatM20); - init(goldFloatP20); - testFloatP20(goldFloatP20); - init(goldFloatM31); - testFloatM31(goldFloatM31); - init(goldFloatP31); - testFloatP31(goldFloatP31); - init(goldFloatM32); - testFloatM32(goldFloatM32); - init(goldFloatP32); - testFloatP32(goldFloatP32); - init(goldFloatM63); - testFloatM63(goldFloatM63); - init(goldFloatP63); - testFloatP63(goldFloatP63); - init(goldFloatM64); - testFloatM64(goldFloatM64); - init(goldFloatP64); - testFloatP64(goldFloatP64); - init(goldFloatM65); - testFloatM65(goldFloatM65); - init(goldFloatP65); - testFloatP65(goldFloatP65); - init(goldFloatM128); - testFloatM128(goldFloatM128); - init(goldFloatP128); - testFloatP128(goldFloatP128); - init(goldFloatM129); - testFloatM129(goldFloatM129); - init(goldFloatP129); - testFloatP129(goldFloatP129); - init(goldFloatM192); - testFloatM192(goldFloatM192); - init(goldFloatP192); - testFloatP192(goldFloatP192); - init(goldDoubleP0); - testDoubleP0(goldDoubleP0); - init(goldDoubleM1); - testDoubleM1(goldDoubleM1); - init(goldDoubleP1); - testDoubleP1(goldDoubleP1); - init(goldDoubleM2); - testDoubleM2(goldDoubleM2); - init(goldDoubleP2); - testDoubleP2(goldDoubleP2); - init(goldDoubleM3); - testDoubleM3(goldDoubleM3); - init(goldDoubleP3); - testDoubleP3(goldDoubleP3); - init(goldDoubleM4); - testDoubleM4(goldDoubleM4); - init(goldDoubleP4); - testDoubleP4(goldDoubleP4); - init(goldDoubleM7); - testDoubleM7(goldDoubleM7); - init(goldDoubleP7); - testDoubleP7(goldDoubleP7); - init(goldDoubleM8); - testDoubleM8(goldDoubleM8); - init(goldDoubleP8); - testDoubleP8(goldDoubleP8); - init(goldDoubleM14); - testDoubleM14(goldDoubleM14); - init(goldDoubleP14); - testDoubleP14(goldDoubleP14); - init(goldDoubleM16); - testDoubleM16(goldDoubleM16); - init(goldDoubleP16); - testDoubleP16(goldDoubleP16); - init(goldDoubleM18); - testDoubleM18(goldDoubleM18); - init(goldDoubleP18); - testDoubleP18(goldDoubleP18); - init(goldDoubleM20); - testDoubleM20(goldDoubleM20); - init(goldDoubleP20); - testDoubleP20(goldDoubleP20); - init(goldDoubleM31); - testDoubleM31(goldDoubleM31); - init(goldDoubleP31); - testDoubleP31(goldDoubleP31); - init(goldDoubleM32); - testDoubleM32(goldDoubleM32); - init(goldDoubleP32); - testDoubleP32(goldDoubleP32); - init(goldDoubleM63); - testDoubleM63(goldDoubleM63); - init(goldDoubleP63); - testDoubleP63(goldDoubleP63); - init(goldDoubleM64); - testDoubleM64(goldDoubleM64); - init(goldDoubleP64); - testDoubleP64(goldDoubleP64); - init(goldDoubleM65); - testDoubleM65(goldDoubleM65); - init(goldDoubleP65); - testDoubleP65(goldDoubleP65); - init(goldDoubleM128); - testDoubleM128(goldDoubleM128); - init(goldDoubleP128); - testDoubleP128(goldDoubleP128); - init(goldDoubleM129); - testDoubleM129(goldDoubleM129); - init(goldDoubleP129); - testDoubleP129(goldDoubleP129); - init(goldDoubleM192); - testDoubleM192(goldDoubleM192); - init(goldDoubleP192); - testDoubleP192(goldDoubleP192); - } +import compiler.lib.ir_framework.*; +import compiler.lib.compile_framework.*; - public static void main(String args[]) { - TestFramework framework = new TestFramework(TestDependencyOffsets.class); - framework.addFlags("-XX:-TieredCompilation", - "-XX:CompileCommand=compileonly,compiler.loopopts.superword.TestDependencyOffsets::init", - "-XX:CompileCommand=compileonly,compiler.loopopts.superword.TestDependencyOffsets::test*", - "-XX:CompileCommand=compileonly,compiler.loopopts.superword.TestDependencyOffsets::verify", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:LoopUnrollLimit=250"); +import jdk.test.lib.Utils; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.ArrayList; +import java.util.List; +import java.util.HashSet; +import java.util.Set; +import java.util.HashMap; +import java.util.Random; +/* + * We want to test SuperWord / AutoVectorization with different constant offsets (positive and negative): + * for (int i = ...) { a[i + offset] = b[i] * 11; } + * + * To test aliasing, we have 3 modes: single-array, aliasing and non-aliasing. + * We test for various primitive types (int, long, short, char, byte, float, double). + * We run all test under various settings of MaxVectorSize and +-AlignVector. + * Finally, we verify the results and check that vectors of the expected length were created (IR rules). + */ +public class TestDependencyOffsets { + private static final Random RANDOM = Utils.getRandomInstance(); + private static final int SIZE = 5_000 + RANDOM.nextInt(1000); + + /* + * Template for the inner test class. + */ + private static String generate(CompileFramework comp, String[] flags) { + return String.format(""" + import compiler.lib.ir_framework.*; + + public class InnerTest { + private static int SIZE = %s; + + public static void main(String args[]) { + TestFramework framework = new TestFramework(InnerTest.class); + framework.addFlags("-classpath", "%s"); + framework.addFlags(%s); + framework.setDefaultWarmup(0); + framework.start(); + } + + // ------------------------- Init --------------------------- + %s + + // ------------------------- Verify ------------------------- + %s + + // ------------------------- Tests -------------------------- + %s + } + """, + SIZE, + comp.getEscapedClassPathOfCompiledClasses(), + Arrays.stream(flags).map(s -> "\"" + s + "\"").collect(Collectors.joining(", ")), + Arrays.stream(TYPES).map(Type::generateInit).collect(Collectors.joining("\n")), + Arrays.stream(TYPES).map(Type::generateVerify).collect(Collectors.joining("\n")), + getTests().stream().map(TestDefinition::generate).collect(Collectors.joining("\n"))); + } + + public static void main(String[] args) { if (args.length != 1) { throw new RuntimeException("Test requires exactly one argument!"); } - switch (args[0]) { - case "vanilla-A": - framework.addFlags("-XX:+AlignVector"); - break; - case "vanilla-U": - framework.addFlags("-XX:-AlignVector"); - break; - case "sse4-v016-A": - framework.addFlags("-XX:UseSSE=4", "-XX:MaxVectorSize=16", "-XX:+AlignVector"); - break; - case "sse4-v016-U": - framework.addFlags("-XX:UseSSE=4", "-XX:MaxVectorSize=16", "-XX:-AlignVector"); - break; - case "sse4-v008-A": - framework.addFlags("-XX:UseSSE=4", "-XX:MaxVectorSize=8", "-XX:+AlignVector"); - break; - case "sse4-v008-U": - framework.addFlags("-XX:UseSSE=4", "-XX:MaxVectorSize=8", "-XX:-AlignVector"); - break; - case "sse4-v004-A": - framework.addFlags("-XX:UseSSE=4", "-XX:MaxVectorSize=4", "-XX:+AlignVector"); - break; - case "sse4-v004-U": - framework.addFlags("-XX:UseSSE=4", "-XX:MaxVectorSize=4", "-XX:-AlignVector"); - break; - case "sse4-v002-A": - framework.addFlags("-XX:UseSSE=4", "-XX:MaxVectorSize=4", "-XX:+AlignVector"); - break; - case "sse4-v002-U": - framework.addFlags("-XX:UseSSE=4", "-XX:MaxVectorSize=4", "-XX:-AlignVector"); - break; - case "avx1-v032-A": - framework.addFlags("-XX:UseAVX=1", "-XX:MaxVectorSize=32", "-XX:+AlignVector"); - break; - case "avx1-v032-U": - framework.addFlags("-XX:UseAVX=1", "-XX:MaxVectorSize=32", "-XX:-AlignVector"); - break; - case "avx1-v016-A": - framework.addFlags("-XX:UseAVX=1", "-XX:MaxVectorSize=16", "-XX:+AlignVector"); - break; - case "avx1-v016-U": - framework.addFlags("-XX:UseAVX=1", "-XX:MaxVectorSize=16", "-XX:-AlignVector"); - break; - case "avx2-v032-A": - framework.addFlags("-XX:UseAVX=2", "-XX:MaxVectorSize=32", "-XX:+AlignVector"); - break; - case "avx2-v032-U": - framework.addFlags("-XX:UseAVX=2", "-XX:MaxVectorSize=32", "-XX:-AlignVector"); - break; - case "avx2-v016-A": - framework.addFlags("-XX:UseAVX=2", "-XX:MaxVectorSize=16", "-XX:+AlignVector"); - break; - case "avx2-v016-U": - framework.addFlags("-XX:UseAVX=2", "-XX:MaxVectorSize=16", "-XX:-AlignVector"); - break; - case "avx512-v064-A": - framework.addFlags("-XX:UseAVX=3", "-XX:+UseKNLSetting", "-XX:MaxVectorSize=64", "-XX:+AlignVector"); - break; - case "avx512-v064-U": - framework.addFlags("-XX:UseAVX=3", "-XX:+UseKNLSetting", "-XX:MaxVectorSize=64", "-XX:-AlignVector"); - break; - case "avx512-v032-A": - framework.addFlags("-XX:UseAVX=3", "-XX:+UseKNLSetting", "-XX:MaxVectorSize=32", "-XX:+AlignVector"); - break; - case "avx512-v032-U": - framework.addFlags("-XX:UseAVX=3", "-XX:+UseKNLSetting", "-XX:MaxVectorSize=32", "-XX:-AlignVector"); - break; - case "avx512bw-v064-A": - framework.addFlags("-XX:UseAVX=3", "-XX:MaxVectorSize=64", "-XX:+AlignVector"); - break; - case "avx512bw-v064-U": - framework.addFlags("-XX:UseAVX=3", "-XX:MaxVectorSize=64", "-XX:-AlignVector"); - break; - case "avx512bw-v032-A": - framework.addFlags("-XX:UseAVX=3", "-XX:MaxVectorSize=32", "-XX:+AlignVector"); - break; - case "avx512bw-v032-U": - framework.addFlags("-XX:UseAVX=3", "-XX:MaxVectorSize=32", "-XX:-AlignVector"); - break; - case "vec-v064-A": - framework.addFlags("-XX:MaxVectorSize=64", "-XX:+AlignVector"); - break; - case "vec-v064-U": - framework.addFlags("-XX:MaxVectorSize=64", "-XX:-AlignVector"); - break; - case "vec-v032-A": - framework.addFlags("-XX:MaxVectorSize=32", "-XX:+AlignVector"); - break; - case "vec-v032-U": - framework.addFlags("-XX:MaxVectorSize=32", "-XX:-AlignVector"); - break; - case "vec-v016-A": - framework.addFlags("-XX:MaxVectorSize=16", "-XX:+AlignVector"); - break; - case "vec-v016-U": - framework.addFlags("-XX:MaxVectorSize=16", "-XX:-AlignVector"); - break; - case "vec-v008-A": - framework.addFlags("-XX:MaxVectorSize=8", "-XX:+AlignVector"); - break; - case "vec-v008-U": - framework.addFlags("-XX:MaxVectorSize=8", "-XX:-AlignVector"); - break; - case "vec-v004-A": - framework.addFlags("-XX:MaxVectorSize=4", "-XX:+AlignVector"); - break; - case "vec-v004-U": - framework.addFlags("-XX:MaxVectorSize=4", "-XX:-AlignVector"); - break; - default: - throw new RuntimeException("Test argument not recognized: " + args[0]); - } - framework.start(); - } - - // ------------------- Tests ------------------- - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP0(int[] data) { - for (int j = 0; j < RANGE; j++) { - data[j + 0] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP0") - @Warmup(0) - public static void runIntP0() { - int[] data = new int[RANGE]; - init(data); - testIntP0(data); - verify("testIntP0", data, goldIntP0); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM1(int[] data) { - for (int j = 1; j < RANGE; j++) { - data[j + -1] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM1") - @Warmup(0) - public static void runIntM1() { - int[] data = new int[RANGE]; - init(data); - testIntM1(data); - verify("testIntM1", data, goldIntM1); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 4 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - // positive byte_offset 4 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 4 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 4 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 4 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP1(int[] data) { - for (int j = 0; j < RANGE - 1; j++) { - data[j + 1] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP1") - @Warmup(0) - public static void runIntP1() { - int[] data = new int[RANGE]; - init(data); - testIntP1(data); - verify("testIntP1", data, goldIntP1); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM2(int[] data) { - for (int j = 2; j < RANGE; j++) { - data[j + -2] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM2") - @Warmup(0) - public static void runIntM2() { - int[] data = new int[RANGE]; - init(data); - testIntM2(data); - verify("testIntM2", data, goldIntM2); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP2(int[] data) { - for (int j = 0; j < RANGE - 2; j++) { - data[j + 2] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP2") - @Warmup(0) - public static void runIntP2() { - int[] data = new int[RANGE]; - init(data); - testIntP2(data); - verify("testIntP2", data, goldIntP2); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM3(int[] data) { - for (int j = 3; j < RANGE; j++) { - data[j + -3] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM3") - @Warmup(0) - public static void runIntM3() { - int[] data = new int[RANGE]; - init(data); - testIntM3(data); - verify("testIntM3", data, goldIntM3); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 12 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - // positive byte_offset 12 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 12 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 12 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 12 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP3(int[] data) { - for (int j = 0; j < RANGE - 3; j++) { - data[j + 3] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP3") - @Warmup(0) - public static void runIntP3() { - int[] data = new int[RANGE]; - init(data); - testIntP3(data); - verify("testIntP3", data, goldIntP3); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM4(int[] data) { - for (int j = 4; j < RANGE; j++) { - data[j + -4] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM4") - @Warmup(0) - public static void runIntM4() { - int[] data = new int[RANGE]; - init(data); - testIntM4(data); - verify("testIntM4", data, goldIntM4); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP4(int[] data) { - for (int j = 0; j < RANGE - 4; j++) { - data[j + 4] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP4") - @Warmup(0) - public static void runIntP4() { - int[] data = new int[RANGE]; - init(data); - testIntP4(data); - verify("testIntP4", data, goldIntP4); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM7(int[] data) { - for (int j = 7; j < RANGE; j++) { - data[j + -7] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM7") - @Warmup(0) - public static void runIntM7() { - int[] data = new int[RANGE]; - init(data); - testIntM7(data); - verify("testIntM7", data, goldIntM7); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP7(int[] data) { - for (int j = 0; j < RANGE - 7; j++) { - data[j + 7] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP7") - @Warmup(0) - public static void runIntP7() { - int[] data = new int[RANGE]; - init(data); - testIntP7(data); - verify("testIntP7", data, goldIntP7); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM8(int[] data) { - for (int j = 8; j < RANGE; j++) { - data[j + -8] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM8") - @Warmup(0) - public static void runIntM8() { - int[] data = new int[RANGE]; - init(data); - testIntM8(data); - verify("testIntM8", data, goldIntM8); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP8(int[] data) { - for (int j = 0; j < RANGE - 8; j++) { - data[j + 8] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP8") - @Warmup(0) - public static void runIntP8() { - int[] data = new int[RANGE]; - init(data); - testIntP8(data); - verify("testIntP8", data, goldIntP8); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM14(int[] data) { - for (int j = 14; j < RANGE; j++) { - data[j + -14] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM14") - @Warmup(0) - public static void runIntM14() { - int[] data = new int[RANGE]; - init(data); - testIntM14(data); - verify("testIntM14", data, goldIntM14); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 56 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 56 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP14(int[] data) { - for (int j = 0; j < RANGE - 14; j++) { - data[j + 14] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP14") - @Warmup(0) - public static void runIntP14() { - int[] data = new int[RANGE]; - init(data); - testIntP14(data); - verify("testIntP14", data, goldIntP14); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM16(int[] data) { - for (int j = 16; j < RANGE; j++) { - data[j + -16] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM16") - @Warmup(0) - public static void runIntM16() { - int[] data = new int[RANGE]; - init(data); - testIntM16(data); - verify("testIntM16", data, goldIntM16); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 64 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP16(int[] data) { - for (int j = 0; j < RANGE - 16; j++) { - data[j + 16] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP16") - @Warmup(0) - public static void runIntP16() { - int[] data = new int[RANGE]; - init(data); - testIntP16(data); - verify("testIntP16", data, goldIntP16); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM18(int[] data) { - for (int j = 18; j < RANGE; j++) { - data[j + -18] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM18") - @Warmup(0) - public static void runIntM18() { - int[] data = new int[RANGE]; - init(data); - testIntM18(data); - verify("testIntM18", data, goldIntM18); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 72 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 72"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 72"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP18(int[] data) { - for (int j = 0; j < RANGE - 18; j++) { - data[j + 18] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP18") - @Warmup(0) - public static void runIntP18() { - int[] data = new int[RANGE]; - init(data); - testIntP18(data); - verify("testIntP18", data, goldIntP18); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM20(int[] data) { - for (int j = 20; j < RANGE; j++) { - data[j + -20] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM20") - @Warmup(0) - public static void runIntM20() { - int[] data = new int[RANGE]; - init(data); - testIntM20(data); - verify("testIntM20", data, goldIntM20); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 80 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 80"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 80"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP20(int[] data) { - for (int j = 0; j < RANGE - 20; j++) { - data[j + 20] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP20") - @Warmup(0) - public static void runIntP20() { - int[] data = new int[RANGE]; - init(data); - testIntP20(data); - verify("testIntP20", data, goldIntP20); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM31(int[] data) { - for (int j = 31; j < RANGE; j++) { - data[j + -31] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM31") - @Warmup(0) - public static void runIntM31() { - int[] data = new int[RANGE]; - init(data); - testIntM31(data); - verify("testIntM31", data, goldIntM31); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 124 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 124"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 124"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP31(int[] data) { - for (int j = 0; j < RANGE - 31; j++) { - data[j + 31] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP31") - @Warmup(0) - public static void runIntP31() { - int[] data = new int[RANGE]; - init(data); - testIntP31(data); - verify("testIntP31", data, goldIntP31); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM32(int[] data) { - for (int j = 32; j < RANGE; j++) { - data[j + -32] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM32") - @Warmup(0) - public static void runIntM32() { - int[] data = new int[RANGE]; - init(data); - testIntM32(data); - verify("testIntM32", data, goldIntM32); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 128 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP32(int[] data) { - for (int j = 0; j < RANGE - 32; j++) { - data[j + 32] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP32") - @Warmup(0) - public static void runIntP32() { - int[] data = new int[RANGE]; - init(data); - testIntP32(data); - verify("testIntP32", data, goldIntP32); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM63(int[] data) { - for (int j = 63; j < RANGE; j++) { - data[j + -63] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM63") - @Warmup(0) - public static void runIntM63() { - int[] data = new int[RANGE]; - init(data); - testIntM63(data); - verify("testIntM63", data, goldIntM63); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 252 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 252"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 252"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP63(int[] data) { - for (int j = 0; j < RANGE - 63; j++) { - data[j + 63] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP63") - @Warmup(0) - public static void runIntP63() { - int[] data = new int[RANGE]; - init(data); - testIntP63(data); - verify("testIntP63", data, goldIntP63); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM64(int[] data) { - for (int j = 64; j < RANGE; j++) { - data[j + -64] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM64") - @Warmup(0) - public static void runIntM64() { - int[] data = new int[RANGE]; - init(data); - testIntM64(data); - verify("testIntM64", data, goldIntM64); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP64(int[] data) { - for (int j = 0; j < RANGE - 64; j++) { - data[j + 64] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP64") - @Warmup(0) - public static void runIntP64() { - int[] data = new int[RANGE]; - init(data); - testIntP64(data); - verify("testIntP64", data, goldIntP64); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM65(int[] data) { - for (int j = 65; j < RANGE; j++) { - data[j + -65] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM65") - @Warmup(0) - public static void runIntM65() { - int[] data = new int[RANGE]; - init(data); - testIntM65(data); - verify("testIntM65", data, goldIntM65); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP65(int[] data) { - for (int j = 0; j < RANGE - 65; j++) { - data[j + 65] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP65") - @Warmup(0) - public static void runIntP65() { - int[] data = new int[RANGE]; - init(data); - testIntP65(data); - verify("testIntP65", data, goldIntP65); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM128(int[] data) { - for (int j = 128; j < RANGE; j++) { - data[j + -128] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM128") - @Warmup(0) - public static void runIntM128() { - int[] data = new int[RANGE]; - init(data); - testIntM128(data); - verify("testIntM128", data, goldIntM128); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP128(int[] data) { - for (int j = 0; j < RANGE - 128; j++) { - data[j + 128] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP128") - @Warmup(0) - public static void runIntP128() { - int[] data = new int[RANGE]; - init(data); - testIntP128(data); - verify("testIntP128", data, goldIntP128); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM129(int[] data) { - for (int j = 129; j < RANGE; j++) { - data[j + -129] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntM129") - @Warmup(0) - public static void runIntM129() { - int[] data = new int[RANGE]; - init(data); - testIntM129(data); - verify("testIntM129", data, goldIntM129); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP129(int[] data) { - for (int j = 0; j < RANGE - 129; j++) { - data[j + 129] = (int)(data[j] * (int)-11); - } - } - - @Run(test = "testIntP129") - @Warmup(0) - public static void runIntP129() { - int[] data = new int[RANGE]; - init(data); - testIntP129(data); - verify("testIntP129", data, goldIntP129); - } + String[] flags = switch (args[0]) { + case "vanilla-A" -> new String[] {"-XX:+AlignVector"}; + case "vanilla-U" -> new String[] {"-XX:-AlignVector"}; + case "sse4-v016-A" -> new String[] {"-XX:UseSSE=4", "-XX:MaxVectorSize=16", "-XX:+AlignVector"}; + case "sse4-v016-U" -> new String[] {"-XX:UseSSE=4", "-XX:MaxVectorSize=16", "-XX:-AlignVector"}; + case "sse4-v008-A" -> new String[] {"-XX:UseSSE=4", "-XX:MaxVectorSize=8", "-XX:+AlignVector"}; + case "sse4-v008-U" -> new String[] {"-XX:UseSSE=4", "-XX:MaxVectorSize=8", "-XX:-AlignVector"}; + case "sse4-v004-A" -> new String[] {"-XX:UseSSE=4", "-XX:MaxVectorSize=4", "-XX:+AlignVector"}; + case "sse4-v004-U" -> new String[] {"-XX:UseSSE=4", "-XX:MaxVectorSize=4", "-XX:-AlignVector"}; + case "avx1-v032-A" -> new String[] {"-XX:UseAVX=1", "-XX:MaxVectorSize=32", "-XX:+AlignVector"}; + case "avx1-v032-U" -> new String[] {"-XX:UseAVX=1", "-XX:MaxVectorSize=32", "-XX:-AlignVector"}; + case "avx1-v016-A" -> new String[] {"-XX:UseAVX=1", "-XX:MaxVectorSize=16", "-XX:+AlignVector"}; + case "avx1-v016-U" -> new String[] {"-XX:UseAVX=1", "-XX:MaxVectorSize=16", "-XX:-AlignVector"}; + case "avx2-v032-A" -> new String[] {"-XX:UseAVX=2", "-XX:MaxVectorSize=32", "-XX:+AlignVector"}; + case "avx2-v032-U" -> new String[] {"-XX:UseAVX=2", "-XX:MaxVectorSize=32", "-XX:-AlignVector"}; + case "avx2-v016-A" -> new String[] {"-XX:UseAVX=2", "-XX:MaxVectorSize=16", "-XX:+AlignVector"}; + case "avx2-v016-U" -> new String[] {"-XX:UseAVX=2", "-XX:MaxVectorSize=16", "-XX:-AlignVector"}; + case "avx512-v064-A" -> new String[] {"-XX:UseAVX=3", "-XX:+UseKNLSetting", "-XX:MaxVectorSize=64", "-XX:+AlignVector"}; + case "avx512-v064-U" -> new String[] {"-XX:UseAVX=3", "-XX:+UseKNLSetting", "-XX:MaxVectorSize=64", "-XX:-AlignVector"}; + case "avx512-v032-A" -> new String[] {"-XX:UseAVX=3", "-XX:+UseKNLSetting", "-XX:MaxVectorSize=32", "-XX:+AlignVector"}; + case "avx512-v032-U" -> new String[] {"-XX:UseAVX=3", "-XX:+UseKNLSetting", "-XX:MaxVectorSize=32", "-XX:-AlignVector"}; + case "avx512bw-v064-A" -> new String[] {"-XX:UseAVX=3", "-XX:MaxVectorSize=64", "-XX:+AlignVector"}; + case "avx512bw-v064-U" -> new String[] {"-XX:UseAVX=3", "-XX:MaxVectorSize=64", "-XX:-AlignVector"}; + case "avx512bw-v032-A" -> new String[] {"-XX:UseAVX=3", "-XX:MaxVectorSize=32", "-XX:+AlignVector"}; + case "avx512bw-v032-U" -> new String[] {"-XX:UseAVX=3", "-XX:MaxVectorSize=32", "-XX:-AlignVector"}; + case "vec-v064-A" -> new String[] {"-XX:MaxVectorSize=64", "-XX:+AlignVector"}; + case "vec-v064-U" -> new String[] {"-XX:MaxVectorSize=64", "-XX:-AlignVector"}; + case "vec-v032-A" -> new String[] {"-XX:MaxVectorSize=32", "-XX:+AlignVector"}; + case "vec-v032-U" -> new String[] {"-XX:MaxVectorSize=32", "-XX:-AlignVector"}; + case "vec-v016-A" -> new String[] {"-XX:MaxVectorSize=16", "-XX:+AlignVector"}; + case "vec-v016-U" -> new String[] {"-XX:MaxVectorSize=16", "-XX:-AlignVector"}; + case "vec-v008-A" -> new String[] {"-XX:MaxVectorSize=8", "-XX:+AlignVector"}; + case "vec-v008-U" -> new String[] {"-XX:MaxVectorSize=8", "-XX:-AlignVector"}; + case "vec-v004-A" -> new String[] {"-XX:MaxVectorSize=4", "-XX:+AlignVector"}; + case "vec-v004-U" -> new String[] {"-XX:MaxVectorSize=4", "-XX:-AlignVector"}; + default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); } + }; + + CompileFramework comp = new CompileFramework(); + long time0 = System.currentTimeMillis(); + comp.addJavaSourceCode("InnerTest", generate(comp, flags)); + long time1 = System.currentTimeMillis(); + comp.compile(); + long time2 = System.currentTimeMillis(); + comp.invoke("InnerTest", "main", new Object[] {null}); + long time3 = System.currentTimeMillis(); + System.out.println("Generate: " + (time1 - time0)); + System.out.println("Compile: " + (time2 - time1)); + System.out.println("Run: " + (time3 - time2)); + } + + static record Type (String name, int size, String value, String operator, String irNode) { + String letter() { + return name.substring(0, 1).toUpperCase(); + } + + /* + * Template for init method generation. + */ + String generateInit() { + return String.format(""" + static void init(%s[] a, %s[] b) { + for (int i = 0; i < SIZE; i++) { + a[i] = (%s)(2 * i); + b[i] = (%s)(3 * i); + } + } + """, + name, name, name, name); + } + + /* + * Template for verify method generation. + */ + String generateVerify() { + return String.format(""" + static void verify(String context, %s[] aTest, %s[] bTest, %s[] aGold, %s[] bGold) { + for (int i = 0; i < SIZE; i++) { + if (aTest[i] != aGold[i] || bTest[i] != bGold[i]) { + throw new RuntimeException("Wrong result in " + context + " at i=" + i + ": " + + "aTest=" + aTest[i] + ", aGold=" + aGold[i] + + "bTest=" + bTest[i] + ", bGold=" + bGold[i]); + } + } + } + """, + name, name, name, name); + } + } + + static final Type[] TYPES = new Type[] { + new Type("int", 4, "-11", "*", "MUL_VI"), + new Type("long", 8, "-11", "+", "ADD_VL"), // aarch64 NEON does not support MulVL + new Type("short", 2, "-11", "*", "MUL_VS"), + new Type("char", 2, "-11", "*", "MUL_VS"), // char behaves like short + new Type("byte", 1, "11", "*", "MUL_VB"), + new Type("float", 4, "1.001f", "*", "MUL_VF"), + new Type("double", 8, "1.001", "*", "MUL_VD"), + }; + + /* + * Every CPU can define its own Matcher::min_vector_size. This happens to be different for + * our targeted platforms: x86 / sse4.1 and aarch64 / asimd. + */ + static record CPUMinVectorWidth (String applyIfCPUFeature, int minVectorWidth) {} + + static final String SSE4_ASIMD = " applyIfCPUFeatureOr = {\"sse4.1\", \"true\", \"asimd\", \"true\"})\n"; + static final String SSE4 = " applyIfCPUFeature = {\"sse4.1\", \"true\"})\n"; + static final String ASIMD = " applyIfCPUFeature = {\"asimd\", \"true\"})\n"; + + static CPUMinVectorWidth[] getCPUMinVectorWidth(String typeName) { + return switch (typeName) { + case "byte" -> new CPUMinVectorWidth[]{new CPUMinVectorWidth(SSE4_ASIMD, 4 )}; + case "char" -> new CPUMinVectorWidth[]{new CPUMinVectorWidth(SSE4, 4 ), + new CPUMinVectorWidth(ASIMD, 8 )}; + case "short" -> new CPUMinVectorWidth[]{new CPUMinVectorWidth(SSE4, 4 ), + new CPUMinVectorWidth(ASIMD, 8 )}; + case "int" -> new CPUMinVectorWidth[]{new CPUMinVectorWidth(SSE4_ASIMD, 8 )}; + case "long" -> new CPUMinVectorWidth[]{new CPUMinVectorWidth(SSE4_ASIMD, 16)}; + case "float" -> new CPUMinVectorWidth[]{new CPUMinVectorWidth(SSE4_ASIMD, 8 )}; + case "double" -> new CPUMinVectorWidth[]{new CPUMinVectorWidth(SSE4_ASIMD, 16)}; + default -> { throw new RuntimeException("type not supported: " + typeName); } + }; + } + + static List getOffsets() { + // Some carefully hand-picked values + int[] always = new int[] { + 0, + -1, 1, + -2, 2, // 2^1 + -3, 3, + -4, 4, // 2^2 + -7, 7, + -8, 8, // 2^3 + -14, 14, + -16, 16, // 2^4 + -18, 18, + -20, 20, + -31, 31, + -32, 32, // 2^5 + -63, 63, + -64, 64, // 2^6 + -65, 65, + -128, 128, // 2^7 + -129, 129, + -192, 192, // 3 * 64 + }; + Set set = Arrays.stream(always).boxed().collect(Collectors.toSet()); + + // Sample some random values on an exponential scale + for (int i = 0; i < 10; i++) { + int base = 4 << i; + int offset = base + RANDOM.nextInt(base); + set.add(offset); + set.add(-offset); + } + + return new ArrayList(set); + } + + static record TestDefinition (int id, Type type, int offset) { + + /* + * Template for test generation, together with its static variables, static initialization, + * @IR rules and @Run method (initialization, execution and verification). + */ + String generate() { + int start = offset >= 0 ? 0 : -offset; + String end = offset >= 0 ? "SIZE - " + offset : "SIZE"; + + String aliasingComment; + String secondArgument; + String loadFrom; + switch (RANDOM.nextInt(3)) { + case 0: // a[i + offset] = a[i] + aliasingComment = "single-array"; + secondArgument = "a"; + loadFrom = "a"; + break; + case 1: // a[i + offset] = b[i], but a and b alias, i.e. at runtime a == b. + aliasingComment = "aliasing"; + secondArgument = "a"; + loadFrom = "b"; + break; + case 2: // a[i + offset] = b[i], and a and b do not alias, i.e. at runtime a != b. + aliasingComment = "non-aliasing"; + secondArgument = "b"; + loadFrom = "b"; + break; + default: + throw new RuntimeException("impossible"); + } - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntM192(int[] data) { - for (int j = 192; j < RANGE; j++) { - data[j + -192] = (int)(data[j] * (int)-11); + return String.format(""" + // test%d: type=%s, offset=%d, mode=%s + static %s[] aGold%d = new %s[SIZE]; + static %s[] bGold%d = new %s[SIZE]; + static %s[] aTest%d = new %s[SIZE]; + static %s[] bTest%d = new %s[SIZE]; + + static { + init(aGold%d, bGold%d); + test%d(aGold%d, %sGold%d); + } + + @Test + %s + public static void test%d(%s[] a, %s[] b) { + for (int i = %d; i < %s; i++) { + a[i + %d] = (%s)(%s[i] %s %s); + } + } + + @Run(test = "test%s") + public static void run%s() { + init(aTest%d, bTest%d); + test%d(aTest%d, %sTest%d); + verify("test%d", aTest%d, bTest%d, aGold%d, bGold%d); + } + """, + // title + id, type.name, offset, aliasingComment, + // static + type.name, id, type.name, + type.name, id, type.name, + type.name, id, type.name, + type.name, id, type.name, + id, id, id, id, secondArgument, id, + // IR rules + generateIRRules(), + // test + id, type.name, type.name, + start, end, + offset, type.name, loadFrom, type.operator, type.value, + // run + id, id, id, id, id, id, secondArgument, id, id, id, id, id, id); + } + + /* + * We generate a number of IR rules for every TestDefinition. If an what kind of vectorization we + * expect depends on AlignVector and MaxVectorSize, as well as the byteOffset between the load and + * store. + */ + String generateIRRules() { + StringBuilder builder = new StringBuilder(); + + for (CPUMinVectorWidth cm : getCPUMinVectorWidth(type.name)) { + String applyIfCPUFeature = cm.applyIfCPUFeature; + int minVectorWidth = cm.minVectorWidth; + builder.append(" // minVectorWidth = " + minVectorWidth + "\n"); + + int byteOffset = offset * type.size; + builder.append(" // byteOffset = " + byteOffset + " = offset * type.size\n"); + + // In a store-forward case, later iterations load from stores of previous iterations. + // If the offset is too small, that leads to cyclic dependencies in the vectors. Hence, + // we use shorter vectors to avoid cycles and still vectorize. Vector lengths have to + // be powers-of-2, and smaller or equal to the byteOffset. So we round down to the next + // power of two. + int infinity = 256; // No vector size is ever larger than this. + int maxVectorWidth = infinity; // no constraint by default + if (0 < byteOffset && byteOffset < maxVectorWidth) { + int log2 = 31 - Integer.numberOfLeadingZeros(offset); + int floorPow2 = 1 << log2; + maxVectorWidth = Math.min(maxVectorWidth, floorPow2 * type.size); + builder.append(" // Vectors must have at most " + floorPow2 + + " elements: maxVectorWidth = " + maxVectorWidth + + " to avoid cyclic dependency.\n"); + } + + // Rule 1: No strict alignment: -XX:-AlignVector + IRRule r1 = new IRRule(type, type.irNode, applyIfCPUFeature); + r1.addApplyIf("\"AlignVector\", \"false\""); + r1.addApplyIf("\"MaxVectorSize\", \">=" + minVectorWidth + "\""); + + if (maxVectorWidth < minVectorWidth) { + builder.append(" // maxVectorWidth < minVectorWidth -> expect no vectorization.\n"); + r1.setNegative(); + } else if (maxVectorWidth < infinity) { + r1.setSize("min(" + (maxVectorWidth / type.size) + ",max_" + type.name + ")"); + } + r1.generate(builder); + + // Rule 2: strict alignment: -XX:+AlignVector + IRRule r2 = new IRRule(type, type.irNode, applyIfCPUFeature); + r2.addApplyIf("\"AlignVector\", \"true\""); + r2.addApplyIf("\"MaxVectorSize\", \">=" + minVectorWidth + "\""); + + // All vectors must be aligned by some alignment width aw: + // aw = min(actualVectorWidth, ObjectAlignmentInBytes) + // The runtime aw must thus lay between these two values: + // awMin <= aw <= awMax + int awMin = Math.min(minVectorWidth, 8); + int awMax = 8; + + // We must align both the load and the store, thus we must also be able to align + // for the difference of the two, i.e. byteOffset must be a multiple of aw: + // byteOffset % aw == 0 + // We don't know the aw, only awMin and awMax. But: + // byteOffset % awMax == 0 -> byteOffset % aw == 0 + // byteOffset % awMin != 0 -> byteOffset % aw != 0 + builder.append(" // awMin = " + awMin + " = min(minVectorWidth, 8)\n"); + builder.append(" // awMax = " + awMax + "\n"); + + if (byteOffset % awMax == 0) { + builder.append(" // byteOffset % awMax == 0 -> always trivially aligned\n"); + } else if (byteOffset % awMin != 0) { + builder.append(" // byteOffset % awMin != 0 -> can never align -> expect no vectorization.\n"); + r2.setNegative(); + } else { + builder.append(" // Alignment unknown -> disable IR rule.\n"); + r2.disable(); + } + + if (maxVectorWidth < minVectorWidth) { + builder.append(" // Not at least 2 elements or 4 bytes -> expect no vectorization.\n"); + r2.setNegative(); + } else if (maxVectorWidth < infinity) { + r2.setSize("min(" + (maxVectorWidth / type.size) + ",max_" + type.name + ")"); + } + r2.generate(builder); + } + return builder.toString(); } } - @Run(test = "testIntM192") - @Warmup(0) - public static void runIntM192() { - int[] data = new int[RANGE]; - init(data); - testIntM192(data); - verify("testIntM192", data, goldIntM192); - } + static List getTests() { + List tests = new ArrayList<>(); - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testIntP192(int[] data) { - for (int j = 0; j < RANGE - 192; j++) { - data[j + 192] = (int)(data[j] * (int)-11); + // Cross product of all types and offsets. + int id = 0; + for (Type type : TYPES) { + for (int offset : getOffsets()) { + tests.add(new TestDefinition(id++, type, offset)); + } } - } - @Run(test = "testIntP192") - @Warmup(0) - public static void runIntP192() { - int[] data = new int[RANGE]; - init(data); - testIntP192(data); - verify("testIntP192", data, goldIntP192); + return tests; } - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP0(long[] data) { - for (int j = 0; j < RANGE; j++) { - data[j + 0] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP0") - @Warmup(0) - public static void runLongP0() { - long[] data = new long[RANGE]; - init(data); - testLongP0(data); - verify("testLongP0", data, goldLongP0); - } + static class IRRule { + Type type; + String irNode; + String applyIfCPUFeature; + String size; + boolean isEnabled; + boolean isPositiveRule; + ArrayList applyIf; - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM1(long[] data) { - for (int j = 1; j < RANGE; j++) { - data[j + -1] = (long)(data[j] + (long)-11); + IRRule(Type type, String irNode, String applyIfCPUFeature) { + this.type = type; + this.irNode = irNode; + this.applyIfCPUFeature = applyIfCPUFeature; + this.size = null; + this.isPositiveRule = true; + this.isEnabled = true; + this.applyIf = new ArrayList(); } - } - - @Run(test = "testLongM1") - @Warmup(0) - public static void runLongM1() { - long[] data = new long[RANGE]; - init(data); - testLongM1(data); - verify("testLongM1", data, goldLongM1); - } - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - // positive byte_offset 8 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect alignment. - // No positive IR rule: conditions impossible. - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - // positive byte_offset 8 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect alignment. - // No positive IR rule: conditions impossible. - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - // positive byte_offset 8 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect alignment. - // No positive IR rule: conditions impossible. - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - // positive byte_offset 8 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect alignment. - // No positive IR rule: conditions impossible. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 8 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect alignment. - // No positive IR rule: conditions impossible. - public static void testLongP1(long[] data) { - for (int j = 0; j < RANGE - 1; j++) { - data[j + 1] = (long)(data[j] + (long)-11); + void setSize(String size) { + this.size = size; } - } - @Run(test = "testLongP1") - @Warmup(0) - public static void runLongP1() { - long[] data = new long[RANGE]; - init(data); - testLongP1(data); - verify("testLongP1", data, goldLongP1); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM2(long[] data) { - for (int j = 2; j < RANGE; j++) { - data[j + -2] = (long)(data[j] + (long)-11); + void setNegative() { + this.isPositiveRule = false; } - } - - @Run(test = "testLongM2") - @Warmup(0) - public static void runLongM2() { - long[] data = new long[RANGE]; - init(data); - testLongM2(data); - verify("testLongM2", data, goldLongM2); - } - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP2(long[] data) { - for (int j = 0; j < RANGE - 2; j++) { - data[j + 2] = (long)(data[j] + (long)-11); + void disable() { + this.isEnabled = false; } - } - - @Run(test = "testLongP2") - @Warmup(0) - public static void runLongP2() { - long[] data = new long[RANGE]; - init(data); - testLongP2(data); - verify("testLongP2", data, goldLongP2); - } - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM3(long[] data) { - for (int j = 3; j < RANGE; j++) { - data[j + -3] = (long)(data[j] + (long)-11); + void addApplyIf(String constraint) { + this.applyIf.add(constraint); } - } - - @Run(test = "testLongM3") - @Warmup(0) - public static void runLongM3() { - long[] data = new long[RANGE]; - init(data); - testLongM3(data); - verify("testLongM3", data, goldLongM3); - } - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - // positive byte_offset 24 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - // positive byte_offset 24 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 24 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP3(long[] data) { - for (int j = 0; j < RANGE - 3; j++) { - data[j + 3] = (long)(data[j] + (long)-11); - } - } + void generate(StringBuilder builder) { + if (!isEnabled) { + builder.append(" // No IR rule: disabled.\n"); + } else { + builder.append(counts()); - @Run(test = "testLongP3") - @Warmup(0) - public static void runLongP3() { - long[] data = new long[RANGE]; - init(data); - testLongP3(data); - verify("testLongP3", data, goldLongP3); - } + // applyIf + if (!applyIf.isEmpty()) { + builder.append(" applyIf"); + builder.append(applyIf.size() > 1 ? "And" : ""); + builder.append(" = {"); + builder.append(String.join(", ", applyIf)); + builder.append("},\n"); + } - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM4(long[] data) { - for (int j = 4; j < RANGE; j++) { - data[j + -4] = (long)(data[j] + (long)-11); + // CPU features + builder.append(applyIfCPUFeature); + } } - } - @Run(test = "testLongM4") - @Warmup(0) - public static void runLongM4() { - long[] data = new long[RANGE]; - init(data); - testLongM4(data); - verify("testLongM4", data, goldLongM4); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP4(long[] data) { - for (int j = 0; j < RANGE - 4; j++) { - data[j + 4] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP4") - @Warmup(0) - public static void runLongP4() { - long[] data = new long[RANGE]; - init(data); - testLongP4(data); - verify("testLongP4", data, goldLongP4); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM7(long[] data) { - for (int j = 7; j < RANGE; j++) { - data[j + -7] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM7") - @Warmup(0) - public static void runLongM7() { - long[] data = new long[RANGE]; - init(data); - testLongM7(data); - verify("testLongM7", data, goldLongM7); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - // positive byte_offset 56 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 56 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP7(long[] data) { - for (int j = 0; j < RANGE - 7; j++) { - data[j + 7] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP7") - @Warmup(0) - public static void runLongP7() { - long[] data = new long[RANGE]; - init(data); - testLongP7(data); - verify("testLongP7", data, goldLongP7); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM8(long[] data) { - for (int j = 8; j < RANGE; j++) { - data[j + -8] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM8") - @Warmup(0) - public static void runLongM8() { - long[] data = new long[RANGE]; - init(data); - testLongM8(data); - verify("testLongM8", data, goldLongM8); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 64 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP8(long[] data) { - for (int j = 0; j < RANGE - 8; j++) { - data[j + 8] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP8") - @Warmup(0) - public static void runLongP8() { - long[] data = new long[RANGE]; - init(data); - testLongP8(data); - verify("testLongP8", data, goldLongP8); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM14(long[] data) { - for (int j = 14; j < RANGE; j++) { - data[j + -14] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM14") - @Warmup(0) - public static void runLongM14() { - long[] data = new long[RANGE]; - init(data); - testLongM14(data); - verify("testLongM14", data, goldLongM14); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 112 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 112"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 112"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP14(long[] data) { - for (int j = 0; j < RANGE - 14; j++) { - data[j + 14] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP14") - @Warmup(0) - public static void runLongP14() { - long[] data = new long[RANGE]; - init(data); - testLongP14(data); - verify("testLongP14", data, goldLongP14); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM16(long[] data) { - for (int j = 16; j < RANGE; j++) { - data[j + -16] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM16") - @Warmup(0) - public static void runLongM16() { - long[] data = new long[RANGE]; - init(data); - testLongM16(data); - verify("testLongM16", data, goldLongM16); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 128 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP16(long[] data) { - for (int j = 0; j < RANGE - 16; j++) { - data[j + 16] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP16") - @Warmup(0) - public static void runLongP16() { - long[] data = new long[RANGE]; - init(data); - testLongP16(data); - verify("testLongP16", data, goldLongP16); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM18(long[] data) { - for (int j = 18; j < RANGE; j++) { - data[j + -18] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM18") - @Warmup(0) - public static void runLongM18() { - long[] data = new long[RANGE]; - init(data); - testLongM18(data); - verify("testLongM18", data, goldLongM18); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 144 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 144"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 144"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP18(long[] data) { - for (int j = 0; j < RANGE - 18; j++) { - data[j + 18] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP18") - @Warmup(0) - public static void runLongP18() { - long[] data = new long[RANGE]; - init(data); - testLongP18(data); - verify("testLongP18", data, goldLongP18); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM20(long[] data) { - for (int j = 20; j < RANGE; j++) { - data[j + -20] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM20") - @Warmup(0) - public static void runLongM20() { - long[] data = new long[RANGE]; - init(data); - testLongM20(data); - verify("testLongM20", data, goldLongM20); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 160 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 160"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 160"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP20(long[] data) { - for (int j = 0; j < RANGE - 20; j++) { - data[j + 20] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP20") - @Warmup(0) - public static void runLongP20() { - long[] data = new long[RANGE]; - init(data); - testLongP20(data); - verify("testLongP20", data, goldLongP20); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM31(long[] data) { - for (int j = 31; j < RANGE; j++) { - data[j + -31] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM31") - @Warmup(0) - public static void runLongM31() { - long[] data = new long[RANGE]; - init(data); - testLongM31(data); - verify("testLongM31", data, goldLongM31); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 248 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 248"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 248"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP31(long[] data) { - for (int j = 0; j < RANGE - 31; j++) { - data[j + 31] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP31") - @Warmup(0) - public static void runLongP31() { - long[] data = new long[RANGE]; - init(data); - testLongP31(data); - verify("testLongP31", data, goldLongP31); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM32(long[] data) { - for (int j = 32; j < RANGE; j++) { - data[j + -32] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM32") - @Warmup(0) - public static void runLongM32() { - long[] data = new long[RANGE]; - init(data); - testLongM32(data); - verify("testLongM32", data, goldLongM32); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP32(long[] data) { - for (int j = 0; j < RANGE - 32; j++) { - data[j + 32] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP32") - @Warmup(0) - public static void runLongP32() { - long[] data = new long[RANGE]; - init(data); - testLongP32(data); - verify("testLongP32", data, goldLongP32); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM63(long[] data) { - for (int j = 63; j < RANGE; j++) { - data[j + -63] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM63") - @Warmup(0) - public static void runLongM63() { - long[] data = new long[RANGE]; - init(data); - testLongM63(data); - verify("testLongM63", data, goldLongM63); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP63(long[] data) { - for (int j = 0; j < RANGE - 63; j++) { - data[j + 63] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP63") - @Warmup(0) - public static void runLongP63() { - long[] data = new long[RANGE]; - init(data); - testLongP63(data); - verify("testLongP63", data, goldLongP63); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM64(long[] data) { - for (int j = 64; j < RANGE; j++) { - data[j + -64] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM64") - @Warmup(0) - public static void runLongM64() { - long[] data = new long[RANGE]; - init(data); - testLongM64(data); - verify("testLongM64", data, goldLongM64); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP64(long[] data) { - for (int j = 0; j < RANGE - 64; j++) { - data[j + 64] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP64") - @Warmup(0) - public static void runLongP64() { - long[] data = new long[RANGE]; - init(data); - testLongP64(data); - verify("testLongP64", data, goldLongP64); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM65(long[] data) { - for (int j = 65; j < RANGE; j++) { - data[j + -65] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM65") - @Warmup(0) - public static void runLongM65() { - long[] data = new long[RANGE]; - init(data); - testLongM65(data); - verify("testLongM65", data, goldLongM65); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP65(long[] data) { - for (int j = 0; j < RANGE - 65; j++) { - data[j + 65] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP65") - @Warmup(0) - public static void runLongP65() { - long[] data = new long[RANGE]; - init(data); - testLongP65(data); - verify("testLongP65", data, goldLongP65); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM128(long[] data) { - for (int j = 128; j < RANGE; j++) { - data[j + -128] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM128") - @Warmup(0) - public static void runLongM128() { - long[] data = new long[RANGE]; - init(data); - testLongM128(data); - verify("testLongM128", data, goldLongM128); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP128(long[] data) { - for (int j = 0; j < RANGE - 128; j++) { - data[j + 128] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP128") - @Warmup(0) - public static void runLongP128() { - long[] data = new long[RANGE]; - init(data); - testLongP128(data); - verify("testLongP128", data, goldLongP128); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM129(long[] data) { - for (int j = 129; j < RANGE; j++) { - data[j + -129] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM129") - @Warmup(0) - public static void runLongM129() { - long[] data = new long[RANGE]; - init(data); - testLongM129(data); - verify("testLongM129", data, goldLongM129); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP129(long[] data) { - for (int j = 0; j < RANGE - 129; j++) { - data[j + 129] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP129") - @Warmup(0) - public static void runLongP129() { - long[] data = new long[RANGE]; - init(data); - testLongP129(data); - verify("testLongP129", data, goldLongP129); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongM192(long[] data) { - for (int j = 192; j < RANGE; j++) { - data[j + -192] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongM192") - @Warmup(0) - public static void runLongM192() { - long[] data = new long[RANGE]; - init(data); - testLongM192(data); - verify("testLongM192", data, goldLongM192); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testLongP192(long[] data) { - for (int j = 0; j < RANGE - 192; j++) { - data[j + 192] = (long)(data[j] + (long)-11); - } - } - - @Run(test = "testLongP192") - @Warmup(0) - public static void runLongP192() { - long[] data = new long[RANGE]; - init(data); - testLongP192(data); - verify("testLongP192", data, goldLongP192); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP0(short[] data) { - for (int j = 0; j < RANGE; j++) { - data[j + 0] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP0") - @Warmup(0) - public static void runShortP0() { - short[] data = new short[RANGE]; - init(data); - testShortP0(data); - verify("testShortP0", data, goldShortP0); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM1(short[] data) { - for (int j = 1; j < RANGE; j++) { - data[j + -1] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM1") - @Warmup(0) - public static void runShortM1() { - short[] data = new short[RANGE]; - init(data); - testShortM1(data); - verify("testShortM1", data, goldShortM1); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP1(short[] data) { - for (int j = 0; j < RANGE - 1; j++) { - data[j + 1] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP1") - @Warmup(0) - public static void runShortP1() { - short[] data = new short[RANGE]; - init(data); - testShortP1(data); - verify("testShortP1", data, goldShortP1); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testShortM2(short[] data) { - for (int j = 2; j < RANGE; j++) { - data[j + -2] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM2") - @Warmup(0) - public static void runShortM2() { - short[] data = new short[RANGE]; - init(data); - testShortM2(data); - verify("testShortM2", data, goldShortM2); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testShortP2(short[] data) { - for (int j = 0; j < RANGE - 2; j++) { - data[j + 2] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP2") - @Warmup(0) - public static void runShortP2() { - short[] data = new short[RANGE]; - init(data); - testShortP2(data); - verify("testShortP2", data, goldShortP2); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM3(short[] data) { - for (int j = 3; j < RANGE; j++) { - data[j + -3] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM3") - @Warmup(0) - public static void runShortM3() { - short[] data = new short[RANGE]; - init(data); - testShortM3(data); - verify("testShortM3", data, goldShortM3); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 6 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 6 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 6 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 6 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 6 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP3(short[] data) { - for (int j = 0; j < RANGE - 3; j++) { - data[j + 3] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP3") - @Warmup(0) - public static void runShortP3() { - short[] data = new short[RANGE]; - init(data); - testShortP3(data); - verify("testShortP3", data, goldShortP3); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM4(short[] data) { - for (int j = 4; j < RANGE; j++) { - data[j + -4] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM4") - @Warmup(0) - public static void runShortM4() { - short[] data = new short[RANGE]; - init(data); - testShortM4(data); - verify("testShortM4", data, goldShortM4); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP4(short[] data) { - for (int j = 0; j < RANGE - 4; j++) { - data[j + 4] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP4") - @Warmup(0) - public static void runShortP4() { - short[] data = new short[RANGE]; - init(data); - testShortP4(data); - verify("testShortP4", data, goldShortP4); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM7(short[] data) { - for (int j = 7; j < RANGE; j++) { - data[j + -7] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM7") - @Warmup(0) - public static void runShortM7() { - short[] data = new short[RANGE]; - init(data); - testShortM7(data); - verify("testShortM7", data, goldShortM7); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP7(short[] data) { - for (int j = 0; j < RANGE - 7; j++) { - data[j + 7] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP7") - @Warmup(0) - public static void runShortP7() { - short[] data = new short[RANGE]; - init(data); - testShortP7(data); - verify("testShortP7", data, goldShortP7); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM8(short[] data) { - for (int j = 8; j < RANGE; j++) { - data[j + -8] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM8") - @Warmup(0) - public static void runShortM8() { - short[] data = new short[RANGE]; - init(data); - testShortM8(data); - verify("testShortM8", data, goldShortM8); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP8(short[] data) { - for (int j = 0; j < RANGE - 8; j++) { - data[j + 8] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP8") - @Warmup(0) - public static void runShortP8() { - short[] data = new short[RANGE]; - init(data); - testShortP8(data); - verify("testShortP8", data, goldShortP8); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testShortM14(short[] data) { - for (int j = 14; j < RANGE; j++) { - data[j + -14] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM14") - @Warmup(0) - public static void runShortM14() { - short[] data = new short[RANGE]; - init(data); - testShortM14(data); - verify("testShortM14", data, goldShortM14); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testShortP14(short[] data) { - for (int j = 0; j < RANGE - 14; j++) { - data[j + 14] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP14") - @Warmup(0) - public static void runShortP14() { - short[] data = new short[RANGE]; - init(data); - testShortP14(data); - verify("testShortP14", data, goldShortP14); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM16(short[] data) { - for (int j = 16; j < RANGE; j++) { - data[j + -16] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM16") - @Warmup(0) - public static void runShortM16() { - short[] data = new short[RANGE]; - init(data); - testShortM16(data); - verify("testShortM16", data, goldShortM16); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP16(short[] data) { - for (int j = 0; j < RANGE - 16; j++) { - data[j + 16] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP16") - @Warmup(0) - public static void runShortP16() { - short[] data = new short[RANGE]; - init(data); - testShortP16(data); - verify("testShortP16", data, goldShortP16); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testShortM18(short[] data) { - for (int j = 18; j < RANGE; j++) { - data[j + -18] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM18") - @Warmup(0) - public static void runShortM18() { - short[] data = new short[RANGE]; - init(data); - testShortM18(data); - verify("testShortM18", data, goldShortM18); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 36 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 36"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 36 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 36"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testShortP18(short[] data) { - for (int j = 0; j < RANGE - 18; j++) { - data[j + 18] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP18") - @Warmup(0) - public static void runShortP18() { - short[] data = new short[RANGE]; - init(data); - testShortP18(data); - verify("testShortP18", data, goldShortP18); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM20(short[] data) { - for (int j = 20; j < RANGE; j++) { - data[j + -20] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM20") - @Warmup(0) - public static void runShortM20() { - short[] data = new short[RANGE]; - init(data); - testShortM20(data); - verify("testShortM20", data, goldShortM20); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 40 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 40 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP20(short[] data) { - for (int j = 0; j < RANGE - 20; j++) { - data[j + 20] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP20") - @Warmup(0) - public static void runShortP20() { - short[] data = new short[RANGE]; - init(data); - testShortP20(data); - verify("testShortP20", data, goldShortP20); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM31(short[] data) { - for (int j = 31; j < RANGE; j++) { - data[j + -31] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM31") - @Warmup(0) - public static void runShortM31() { - short[] data = new short[RANGE]; - init(data); - testShortM31(data); - verify("testShortM31", data, goldShortM31); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 62 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 62"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 62"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 62 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 62"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 62"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP31(short[] data) { - for (int j = 0; j < RANGE - 31; j++) { - data[j + 31] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP31") - @Warmup(0) - public static void runShortP31() { - short[] data = new short[RANGE]; - init(data); - testShortP31(data); - verify("testShortP31", data, goldShortP31); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM32(short[] data) { - for (int j = 32; j < RANGE; j++) { - data[j + -32] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM32") - @Warmup(0) - public static void runShortM32() { - short[] data = new short[RANGE]; - init(data); - testShortM32(data); - verify("testShortM32", data, goldShortM32); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 64 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP32(short[] data) { - for (int j = 0; j < RANGE - 32; j++) { - data[j + 32] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP32") - @Warmup(0) - public static void runShortP32() { - short[] data = new short[RANGE]; - init(data); - testShortP32(data); - verify("testShortP32", data, goldShortP32); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM63(short[] data) { - for (int j = 63; j < RANGE; j++) { - data[j + -63] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM63") - @Warmup(0) - public static void runShortM63() { - short[] data = new short[RANGE]; - init(data); - testShortM63(data); - verify("testShortM63", data, goldShortM63); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 126 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 126"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 126"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP63(short[] data) { - for (int j = 0; j < RANGE - 63; j++) { - data[j + 63] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP63") - @Warmup(0) - public static void runShortP63() { - short[] data = new short[RANGE]; - init(data); - testShortP63(data); - verify("testShortP63", data, goldShortP63); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM64(short[] data) { - for (int j = 64; j < RANGE; j++) { - data[j + -64] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM64") - @Warmup(0) - public static void runShortM64() { - short[] data = new short[RANGE]; - init(data); - testShortM64(data); - verify("testShortM64", data, goldShortM64); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 128 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP64(short[] data) { - for (int j = 0; j < RANGE - 64; j++) { - data[j + 64] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP64") - @Warmup(0) - public static void runShortP64() { - short[] data = new short[RANGE]; - init(data); - testShortP64(data); - verify("testShortP64", data, goldShortP64); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM65(short[] data) { - for (int j = 65; j < RANGE; j++) { - data[j + -65] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM65") - @Warmup(0) - public static void runShortM65() { - short[] data = new short[RANGE]; - init(data); - testShortM65(data); - verify("testShortM65", data, goldShortM65); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 130 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 130"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 130"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP65(short[] data) { - for (int j = 0; j < RANGE - 65; j++) { - data[j + 65] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP65") - @Warmup(0) - public static void runShortP65() { - short[] data = new short[RANGE]; - init(data); - testShortP65(data); - verify("testShortP65", data, goldShortP65); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM128(short[] data) { - for (int j = 128; j < RANGE; j++) { - data[j + -128] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM128") - @Warmup(0) - public static void runShortM128() { - short[] data = new short[RANGE]; - init(data); - testShortM128(data); - verify("testShortM128", data, goldShortM128); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP128(short[] data) { - for (int j = 0; j < RANGE - 128; j++) { - data[j + 128] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP128") - @Warmup(0) - public static void runShortP128() { - short[] data = new short[RANGE]; - init(data); - testShortP128(data); - verify("testShortP128", data, goldShortP128); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM129(short[] data) { - for (int j = 129; j < RANGE; j++) { - data[j + -129] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM129") - @Warmup(0) - public static void runShortM129() { - short[] data = new short[RANGE]; - init(data); - testShortM129(data); - verify("testShortM129", data, goldShortM129); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP129(short[] data) { - for (int j = 0; j < RANGE - 129; j++) { - data[j + 129] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP129") - @Warmup(0) - public static void runShortP129() { - short[] data = new short[RANGE]; - init(data); - testShortP129(data); - verify("testShortP129", data, goldShortP129); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortM192(short[] data) { - for (int j = 192; j < RANGE; j++) { - data[j + -192] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortM192") - @Warmup(0) - public static void runShortM192() { - short[] data = new short[RANGE]; - init(data); - testShortM192(data); - verify("testShortM192", data, goldShortM192); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testShortP192(short[] data) { - for (int j = 0; j < RANGE - 192; j++) { - data[j + 192] = (short)(data[j] * (short)-11); - } - } - - @Run(test = "testShortP192") - @Warmup(0) - public static void runShortP192() { - short[] data = new short[RANGE]; - init(data); - testShortP192(data); - verify("testShortP192", data, goldShortP192); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP0(char[] data) { - for (int j = 0; j < RANGE; j++) { - data[j + 0] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP0") - @Warmup(0) - public static void runCharP0() { - char[] data = new char[RANGE]; - init(data); - testCharP0(data); - verify("testCharP0", data, goldCharP0); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM1(char[] data) { - for (int j = 1; j < RANGE; j++) { - data[j + -1] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM1") - @Warmup(0) - public static void runCharM1() { - char[] data = new char[RANGE]; - init(data); - testCharM1(data); - verify("testCharM1", data, goldCharM1); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP1(char[] data) { - for (int j = 0; j < RANGE - 1; j++) { - data[j + 1] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP1") - @Warmup(0) - public static void runCharP1() { - char[] data = new char[RANGE]; - init(data); - testCharP1(data); - verify("testCharP1", data, goldCharP1); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testCharM2(char[] data) { - for (int j = 2; j < RANGE; j++) { - data[j + -2] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM2") - @Warmup(0) - public static void runCharM2() { - char[] data = new char[RANGE]; - init(data); - testCharM2(data); - verify("testCharM2", data, goldCharM2); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testCharP2(char[] data) { - for (int j = 0; j < RANGE - 2; j++) { - data[j + 2] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP2") - @Warmup(0) - public static void runCharP2() { - char[] data = new char[RANGE]; - init(data); - testCharP2(data); - verify("testCharP2", data, goldCharP2); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM3(char[] data) { - for (int j = 3; j < RANGE; j++) { - data[j + -3] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM3") - @Warmup(0) - public static void runCharM3() { - char[] data = new char[RANGE]; - init(data); - testCharM3(data); - verify("testCharM3", data, goldCharM3); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 6 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 6 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 6 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 6 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 6 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP3(char[] data) { - for (int j = 0; j < RANGE - 3; j++) { - data[j + 3] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP3") - @Warmup(0) - public static void runCharP3() { - char[] data = new char[RANGE]; - init(data); - testCharP3(data); - verify("testCharP3", data, goldCharP3); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM4(char[] data) { - for (int j = 4; j < RANGE; j++) { - data[j + -4] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM4") - @Warmup(0) - public static void runCharM4() { - char[] data = new char[RANGE]; - init(data); - testCharM4(data); - verify("testCharM4", data, goldCharM4); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP4(char[] data) { - for (int j = 0; j < RANGE - 4; j++) { - data[j + 4] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP4") - @Warmup(0) - public static void runCharP4() { - char[] data = new char[RANGE]; - init(data); - testCharP4(data); - verify("testCharP4", data, goldCharP4); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM7(char[] data) { - for (int j = 7; j < RANGE; j++) { - data[j + -7] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM7") - @Warmup(0) - public static void runCharM7() { - char[] data = new char[RANGE]; - init(data); - testCharM7(data); - verify("testCharM7", data, goldCharM7); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP7(char[] data) { - for (int j = 0; j < RANGE - 7; j++) { - data[j + 7] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP7") - @Warmup(0) - public static void runCharP7() { - char[] data = new char[RANGE]; - init(data); - testCharP7(data); - verify("testCharP7", data, goldCharP7); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM8(char[] data) { - for (int j = 8; j < RANGE; j++) { - data[j + -8] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM8") - @Warmup(0) - public static void runCharM8() { - char[] data = new char[RANGE]; - init(data); - testCharM8(data); - verify("testCharM8", data, goldCharM8); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP8(char[] data) { - for (int j = 0; j < RANGE - 8; j++) { - data[j + 8] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP8") - @Warmup(0) - public static void runCharP8() { - char[] data = new char[RANGE]; - init(data); - testCharP8(data); - verify("testCharP8", data, goldCharP8); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testCharM14(char[] data) { - for (int j = 14; j < RANGE; j++) { - data[j + -14] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM14") - @Warmup(0) - public static void runCharM14() { - char[] data = new char[RANGE]; - init(data); - testCharM14(data); - verify("testCharM14", data, goldCharM14); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testCharP14(char[] data) { - for (int j = 0; j < RANGE - 14; j++) { - data[j + 14] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP14") - @Warmup(0) - public static void runCharP14() { - char[] data = new char[RANGE]; - init(data); - testCharP14(data); - verify("testCharP14", data, goldCharP14); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM16(char[] data) { - for (int j = 16; j < RANGE; j++) { - data[j + -16] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM16") - @Warmup(0) - public static void runCharM16() { - char[] data = new char[RANGE]; - init(data); - testCharM16(data); - verify("testCharM16", data, goldCharM16); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP16(char[] data) { - for (int j = 0; j < RANGE - 16; j++) { - data[j + 16] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP16") - @Warmup(0) - public static void runCharP16() { - char[] data = new char[RANGE]; - init(data); - testCharP16(data); - verify("testCharP16", data, goldCharP16); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testCharM18(char[] data) { - for (int j = 18; j < RANGE; j++) { - data[j + -18] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM18") - @Warmup(0) - public static void runCharM18() { - char[] data = new char[RANGE]; - init(data); - testCharM18(data); - verify("testCharM18", data, goldCharM18); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 36 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 36"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 36 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 36"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testCharP18(char[] data) { - for (int j = 0; j < RANGE - 18; j++) { - data[j + 18] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP18") - @Warmup(0) - public static void runCharP18() { - char[] data = new char[RANGE]; - init(data); - testCharP18(data); - verify("testCharP18", data, goldCharP18); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM20(char[] data) { - for (int j = 20; j < RANGE; j++) { - data[j + -20] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM20") - @Warmup(0) - public static void runCharM20() { - char[] data = new char[RANGE]; - init(data); - testCharM20(data); - verify("testCharM20", data, goldCharM20); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 40 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 40 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP20(char[] data) { - for (int j = 0; j < RANGE - 20; j++) { - data[j + 20] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP20") - @Warmup(0) - public static void runCharP20() { - char[] data = new char[RANGE]; - init(data); - testCharP20(data); - verify("testCharP20", data, goldCharP20); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM31(char[] data) { - for (int j = 31; j < RANGE; j++) { - data[j + -31] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM31") - @Warmup(0) - public static void runCharM31() { - char[] data = new char[RANGE]; - init(data); - testCharM31(data); - verify("testCharM31", data, goldCharM31); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - // positive byte_offset 62 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 62"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 62"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 62 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 62"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 62"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP31(char[] data) { - for (int j = 0; j < RANGE - 31; j++) { - data[j + 31] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP31") - @Warmup(0) - public static void runCharP31() { - char[] data = new char[RANGE]; - init(data); - testCharP31(data); - verify("testCharP31", data, goldCharP31); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM32(char[] data) { - for (int j = 32; j < RANGE; j++) { - data[j + -32] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM32") - @Warmup(0) - public static void runCharM32() { - char[] data = new char[RANGE]; - init(data); - testCharM32(data); - verify("testCharM32", data, goldCharM32); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 64 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP32(char[] data) { - for (int j = 0; j < RANGE - 32; j++) { - data[j + 32] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP32") - @Warmup(0) - public static void runCharP32() { - char[] data = new char[RANGE]; - init(data); - testCharP32(data); - verify("testCharP32", data, goldCharP32); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM63(char[] data) { - for (int j = 63; j < RANGE; j++) { - data[j + -63] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM63") - @Warmup(0) - public static void runCharM63() { - char[] data = new char[RANGE]; - init(data); - testCharM63(data); - verify("testCharM63", data, goldCharM63); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 126 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 126"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 126"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP63(char[] data) { - for (int j = 0; j < RANGE - 63; j++) { - data[j + 63] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP63") - @Warmup(0) - public static void runCharP63() { - char[] data = new char[RANGE]; - init(data); - testCharP63(data); - verify("testCharP63", data, goldCharP63); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM64(char[] data) { - for (int j = 64; j < RANGE; j++) { - data[j + -64] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM64") - @Warmup(0) - public static void runCharM64() { - char[] data = new char[RANGE]; - init(data); - testCharM64(data); - verify("testCharM64", data, goldCharM64); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 128 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP64(char[] data) { - for (int j = 0; j < RANGE - 64; j++) { - data[j + 64] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP64") - @Warmup(0) - public static void runCharP64() { - char[] data = new char[RANGE]; - init(data); - testCharP64(data); - verify("testCharP64", data, goldCharP64); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM65(char[] data) { - for (int j = 65; j < RANGE; j++) { - data[j + -65] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM65") - @Warmup(0) - public static void runCharM65() { - char[] data = new char[RANGE]; - init(data); - testCharM65(data); - verify("testCharM65", data, goldCharM65); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - // positive byte_offset 130 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 130"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 130"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP65(char[] data) { - for (int j = 0; j < RANGE - 65; j++) { - data[j + 65] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP65") - @Warmup(0) - public static void runCharP65() { - char[] data = new char[RANGE]; - init(data); - testCharP65(data); - verify("testCharP65", data, goldCharP65); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM128(char[] data) { - for (int j = 128; j < RANGE; j++) { - data[j + -128] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM128") - @Warmup(0) - public static void runCharM128() { - char[] data = new char[RANGE]; - init(data); - testCharM128(data); - verify("testCharM128", data, goldCharM128); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP128(char[] data) { - for (int j = 0; j < RANGE - 128; j++) { - data[j + 128] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP128") - @Warmup(0) - public static void runCharP128() { - char[] data = new char[RANGE]; - init(data); - testCharP128(data); - verify("testCharP128", data, goldCharP128); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM129(char[] data) { - for (int j = 129; j < RANGE; j++) { - data[j + -129] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM129") - @Warmup(0) - public static void runCharM129() { - char[] data = new char[RANGE]; - init(data); - testCharM129(data); - verify("testCharM129", data, goldCharM129); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP129(char[] data) { - for (int j = 0; j < RANGE - 129; j++) { - data[j + 129] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP129") - @Warmup(0) - public static void runCharP129() { - char[] data = new char[RANGE]; - init(data); - testCharP129(data); - verify("testCharP129", data, goldCharP129); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharM192(char[] data) { - for (int j = 192; j < RANGE; j++) { - data[j + -192] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharM192") - @Warmup(0) - public static void runCharM192() { - char[] data = new char[RANGE]; - init(data); - testCharM192(data); - verify("testCharM192", data, goldCharM192); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testCharP192(char[] data) { - for (int j = 0; j < RANGE - 192; j++) { - data[j + 192] = (char)(data[j] * (char)-11); - } - } - - @Run(test = "testCharP192") - @Warmup(0) - public static void runCharP192() { - char[] data = new char[RANGE]; - init(data); - testCharP192(data); - verify("testCharP192", data, goldCharP192); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP0(byte[] data) { - for (int j = 0; j < RANGE; j++) { - data[j + 0] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP0") - @Warmup(0) - public static void runByteP0() { - byte[] data = new byte[RANGE]; - init(data); - testByteP0(data); - verify("testByteP0", data, goldByteP0); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM1(byte[] data) { - for (int j = 1; j < RANGE; j++) { - data[j + -1] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM1") - @Warmup(0) - public static void runByteM1() { - byte[] data = new byte[RANGE]; - init(data); - testByteM1(data); - verify("testByteM1", data, goldByteM1); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 1 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 1"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 1 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 1"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 1 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 1"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 1 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 1"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 1 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 1"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP1(byte[] data) { - for (int j = 0; j < RANGE - 1; j++) { - data[j + 1] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP1") - @Warmup(0) - public static void runByteP1() { - byte[] data = new byte[RANGE]; - init(data); - testByteP1(data); - verify("testByteP1", data, goldByteP1); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM2(byte[] data) { - for (int j = 2; j < RANGE; j++) { - data[j + -2] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM2") - @Warmup(0) - public static void runByteM2() { - byte[] data = new byte[RANGE]; - init(data); - testByteM2(data); - verify("testByteM2", data, goldByteM2); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 2 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP2(byte[] data) { - for (int j = 0; j < RANGE - 2; j++) { - data[j + 2] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP2") - @Warmup(0) - public static void runByteP2() { - byte[] data = new byte[RANGE]; - init(data); - testByteP2(data); - verify("testByteP2", data, goldByteP2); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM3(byte[] data) { - for (int j = 3; j < RANGE; j++) { - data[j + -3] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM3") - @Warmup(0) - public static void runByteM3() { - byte[] data = new byte[RANGE]; - init(data); - testByteM3(data); - verify("testByteM3", data, goldByteM3); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 3 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 3"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 3 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 3"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 3 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 3"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 3 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 3"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 3 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 3"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP3(byte[] data) { - for (int j = 0; j < RANGE - 3; j++) { - data[j + 3] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP3") - @Warmup(0) - public static void runByteP3() { - byte[] data = new byte[RANGE]; - init(data); - testByteP3(data); - verify("testByteP3", data, goldByteP3); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testByteM4(byte[] data) { - for (int j = 4; j < RANGE; j++) { - data[j + -4] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM4") - @Warmup(0) - public static void runByteM4() { - byte[] data = new byte[RANGE]; - init(data); - testByteM4(data); - verify("testByteM4", data, goldByteM4); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 4 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testByteP4(byte[] data) { - for (int j = 0; j < RANGE - 4; j++) { - data[j + 4] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP4") - @Warmup(0) - public static void runByteP4() { - byte[] data = new byte[RANGE]; - init(data); - testByteP4(data); - verify("testByteP4", data, goldByteP4); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM7(byte[] data) { - for (int j = 7; j < RANGE; j++) { - data[j + -7] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM7") - @Warmup(0) - public static void runByteM7() { - byte[] data = new byte[RANGE]; - init(data); - testByteM7(data); - verify("testByteM7", data, goldByteM7); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 7 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 7"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 7"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 7 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 7"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 7"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 7 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 7"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 7"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 7 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 7"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 7"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 7 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 7"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 7"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP7(byte[] data) { - for (int j = 0; j < RANGE - 7; j++) { - data[j + 7] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP7") - @Warmup(0) - public static void runByteP7() { - byte[] data = new byte[RANGE]; - init(data); - testByteP7(data); - verify("testByteP7", data, goldByteP7); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM8(byte[] data) { - for (int j = 8; j < RANGE; j++) { - data[j + -8] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM8") - @Warmup(0) - public static void runByteM8() { - byte[] data = new byte[RANGE]; - init(data); - testByteM8(data); - verify("testByteM8", data, goldByteM8); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP8(byte[] data) { - for (int j = 0; j < RANGE - 8; j++) { - data[j + 8] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP8") - @Warmup(0) - public static void runByteP8() { - byte[] data = new byte[RANGE]; - init(data); - testByteP8(data); - verify("testByteP8", data, goldByteP8); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM14(byte[] data) { - for (int j = 14; j < RANGE; j++) { - data[j + -14] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM14") - @Warmup(0) - public static void runByteM14() { - byte[] data = new byte[RANGE]; - init(data); - testByteM14(data); - verify("testByteM14", data, goldByteM14); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 14 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP14(byte[] data) { - for (int j = 0; j < RANGE - 14; j++) { - data[j + 14] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP14") - @Warmup(0) - public static void runByteP14() { - byte[] data = new byte[RANGE]; - init(data); - testByteP14(data); - verify("testByteP14", data, goldByteP14); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM16(byte[] data) { - for (int j = 16; j < RANGE; j++) { - data[j + -16] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM16") - @Warmup(0) - public static void runByteM16() { - byte[] data = new byte[RANGE]; - init(data); - testByteM16(data); - verify("testByteM16", data, goldByteM16); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP16(byte[] data) { - for (int j = 0; j < RANGE - 16; j++) { - data[j + 16] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP16") - @Warmup(0) - public static void runByteP16() { - byte[] data = new byte[RANGE]; - init(data); - testByteP16(data); - verify("testByteP16", data, goldByteP16); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM18(byte[] data) { - for (int j = 18; j < RANGE; j++) { - data[j + -18] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM18") - @Warmup(0) - public static void runByteM18() { - byte[] data = new byte[RANGE]; - init(data); - testByteM18(data); - verify("testByteM18", data, goldByteM18); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 18 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 18"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 18"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 18 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 18"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 18"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 18 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 18"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 18"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP18(byte[] data) { - for (int j = 0; j < RANGE - 18; j++) { - data[j + 18] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP18") - @Warmup(0) - public static void runByteP18() { - byte[] data = new byte[RANGE]; - init(data); - testByteP18(data); - verify("testByteP18", data, goldByteP18); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testByteM20(byte[] data) { - for (int j = 20; j < RANGE; j++) { - data[j + -20] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM20") - @Warmup(0) - public static void runByteM20() { - byte[] data = new byte[RANGE]; - init(data); - testByteM20(data); - verify("testByteM20", data, goldByteM20); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 20 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 20"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 20 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 20"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 20 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 20"}, - applyIfCPUFeature = {"sve", "true"}) - // Alignment unclear -> no IR rule for -XX:+AlignVector. - public static void testByteP20(byte[] data) { - for (int j = 0; j < RANGE - 20; j++) { - data[j + 20] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP20") - @Warmup(0) - public static void runByteP20() { - byte[] data = new byte[RANGE]; - init(data); - testByteP20(data); - verify("testByteP20", data, goldByteP20); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM31(byte[] data) { - for (int j = 31; j < RANGE; j++) { - data[j + -31] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM31") - @Warmup(0) - public static void runByteM31() { - byte[] data = new byte[RANGE]; - init(data); - testByteM31(data); - verify("testByteM31", data, goldByteM31); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - // positive byte_offset 31 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 31"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 31"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 31 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 31"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 31"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 31 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 31"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 31"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP31(byte[] data) { - for (int j = 0; j < RANGE - 31; j++) { - data[j + 31] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP31") - @Warmup(0) - public static void runByteP31() { - byte[] data = new byte[RANGE]; - init(data); - testByteP31(data); - verify("testByteP31", data, goldByteP31); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM32(byte[] data) { - for (int j = 32; j < RANGE; j++) { - data[j + -32] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM32") - @Warmup(0) - public static void runByteM32() { - byte[] data = new byte[RANGE]; - init(data); - testByteM32(data); - verify("testByteM32", data, goldByteM32); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP32(byte[] data) { - for (int j = 0; j < RANGE - 32; j++) { - data[j + 32] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP32") - @Warmup(0) - public static void runByteP32() { - byte[] data = new byte[RANGE]; - init(data); - testByteP32(data); - verify("testByteP32", data, goldByteP32); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM63(byte[] data) { - for (int j = 63; j < RANGE; j++) { - data[j + -63] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM63") - @Warmup(0) - public static void runByteM63() { - byte[] data = new byte[RANGE]; - init(data); - testByteM63(data); - verify("testByteM63", data, goldByteM63); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - // positive byte_offset 63 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 63"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 63"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 63 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 63"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 63"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP63(byte[] data) { - for (int j = 0; j < RANGE - 63; j++) { - data[j + 63] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP63") - @Warmup(0) - public static void runByteP63() { - byte[] data = new byte[RANGE]; - init(data); - testByteP63(data); - verify("testByteP63", data, goldByteP63); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM64(byte[] data) { - for (int j = 64; j < RANGE; j++) { - data[j + -64] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM64") - @Warmup(0) - public static void runByteM64() { - byte[] data = new byte[RANGE]; - init(data); - testByteM64(data); - verify("testByteM64", data, goldByteM64); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 64 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP64(byte[] data) { - for (int j = 0; j < RANGE - 64; j++) { - data[j + 64] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP64") - @Warmup(0) - public static void runByteP64() { - byte[] data = new byte[RANGE]; - init(data); - testByteP64(data); - verify("testByteP64", data, goldByteP64); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM65(byte[] data) { - for (int j = 65; j < RANGE; j++) { - data[j + -65] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM65") - @Warmup(0) - public static void runByteM65() { - byte[] data = new byte[RANGE]; - init(data); - testByteM65(data); - verify("testByteM65", data, goldByteM65); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 65 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 65"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 65"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP65(byte[] data) { - for (int j = 0; j < RANGE - 65; j++) { - data[j + 65] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP65") - @Warmup(0) - public static void runByteP65() { - byte[] data = new byte[RANGE]; - init(data); - testByteP65(data); - verify("testByteP65", data, goldByteP65); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM128(byte[] data) { - for (int j = 128; j < RANGE; j++) { - data[j + -128] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM128") - @Warmup(0) - public static void runByteM128() { - byte[] data = new byte[RANGE]; - init(data); - testByteM128(data); - verify("testByteM128", data, goldByteM128); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 128 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP128(byte[] data) { - for (int j = 0; j < RANGE - 128; j++) { - data[j + 128] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP128") - @Warmup(0) - public static void runByteP128() { - byte[] data = new byte[RANGE]; - init(data); - testByteP128(data); - verify("testByteP128", data, goldByteP128); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM129(byte[] data) { - for (int j = 129; j < RANGE; j++) { - data[j + -129] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM129") - @Warmup(0) - public static void runByteM129() { - byte[] data = new byte[RANGE]; - init(data); - testByteM129(data); - verify("testByteM129", data, goldByteM129); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 129 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 129"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 129"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP129(byte[] data) { - for (int j = 0; j < RANGE - 129; j++) { - data[j + 129] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP129") - @Warmup(0) - public static void runByteP129() { - byte[] data = new byte[RANGE]; - init(data); - testByteP129(data); - verify("testByteP129", data, goldByteP129); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteM192(byte[] data) { - for (int j = 192; j < RANGE; j++) { - data[j + -192] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteM192") - @Warmup(0) - public static void runByteM192() { - byte[] data = new byte[RANGE]; - init(data); - testByteM192(data); - verify("testByteM192", data, goldByteM192); - } - - @Test - // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeature = {"avx512bw", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 - // positive byte_offset 192 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 192"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 192"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testByteP192(byte[] data) { - for (int j = 0; j < RANGE - 192; j++) { - data[j + 192] = (byte)(data[j] * (byte)11); - } - } - - @Run(test = "testByteP192") - @Warmup(0) - public static void runByteP192() { - byte[] data = new byte[RANGE]; - init(data); - testByteP192(data); - verify("testByteP192", data, goldByteP192); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP0(float[] data) { - for (int j = 0; j < RANGE; j++) { - data[j + 0] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP0") - @Warmup(0) - public static void runFloatP0() { - float[] data = new float[RANGE]; - init(data); - testFloatP0(data); - verify("testFloatP0", data, goldFloatP0); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM1(float[] data) { - for (int j = 1; j < RANGE; j++) { - data[j + -1] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM1") - @Warmup(0) - public static void runFloatM1() { - float[] data = new float[RANGE]; - init(data); - testFloatM1(data); - verify("testFloatM1", data, goldFloatM1); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 4 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - // positive byte_offset 4 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 4 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 4 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 4 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP1(float[] data) { - for (int j = 0; j < RANGE - 1; j++) { - data[j + 1] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP1") - @Warmup(0) - public static void runFloatP1() { - float[] data = new float[RANGE]; - init(data); - testFloatP1(data); - verify("testFloatP1", data, goldFloatP1); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM2(float[] data) { - for (int j = 2; j < RANGE; j++) { - data[j + -2] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM2") - @Warmup(0) - public static void runFloatM2() { - float[] data = new float[RANGE]; - init(data); - testFloatM2(data); - verify("testFloatM2", data, goldFloatM2); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 8 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP2(float[] data) { - for (int j = 0; j < RANGE - 2; j++) { - data[j + 2] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP2") - @Warmup(0) - public static void runFloatP2() { - float[] data = new float[RANGE]; - init(data); - testFloatP2(data); - verify("testFloatP2", data, goldFloatP2); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM3(float[] data) { - for (int j = 3; j < RANGE; j++) { - data[j + -3] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM3") - @Warmup(0) - public static void runFloatM3() { - float[] data = new float[RANGE]; - init(data); - testFloatM3(data); - verify("testFloatM3", data, goldFloatM3); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 12 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - // positive byte_offset 12 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 12 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - // positive byte_offset 12 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 12 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP3(float[] data) { - for (int j = 0; j < RANGE - 3; j++) { - data[j + 3] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP3") - @Warmup(0) - public static void runFloatP3() { - float[] data = new float[RANGE]; - init(data); - testFloatP3(data); - verify("testFloatP3", data, goldFloatP3); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM4(float[] data) { - for (int j = 4; j < RANGE; j++) { - data[j + -4] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM4") - @Warmup(0) - public static void runFloatM4() { - float[] data = new float[RANGE]; - init(data); - testFloatM4(data); - verify("testFloatM4", data, goldFloatM4); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP4(float[] data) { - for (int j = 0; j < RANGE - 4; j++) { - data[j + 4] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP4") - @Warmup(0) - public static void runFloatP4() { - float[] data = new float[RANGE]; - init(data); - testFloatP4(data); - verify("testFloatP4", data, goldFloatP4); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM7(float[] data) { - for (int j = 7; j < RANGE; j++) { - data[j + -7] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM7") - @Warmup(0) - public static void runFloatM7() { - float[] data = new float[RANGE]; - init(data); - testFloatM7(data); - verify("testFloatM7", data, goldFloatM7); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 28 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP7(float[] data) { - for (int j = 0; j < RANGE - 7; j++) { - data[j + 7] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP7") - @Warmup(0) - public static void runFloatP7() { - float[] data = new float[RANGE]; - init(data); - testFloatP7(data); - verify("testFloatP7", data, goldFloatP7); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM8(float[] data) { - for (int j = 8; j < RANGE; j++) { - data[j + -8] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM8") - @Warmup(0) - public static void runFloatM8() { - float[] data = new float[RANGE]; - init(data); - testFloatM8(data); - verify("testFloatM8", data, goldFloatM8); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP8(float[] data) { - for (int j = 0; j < RANGE - 8; j++) { - data[j + 8] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP8") - @Warmup(0) - public static void runFloatP8() { - float[] data = new float[RANGE]; - init(data); - testFloatP8(data); - verify("testFloatP8", data, goldFloatP8); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM14(float[] data) { - for (int j = 14; j < RANGE; j++) { - data[j + -14] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM14") - @Warmup(0) - public static void runFloatM14() { - float[] data = new float[RANGE]; - init(data); - testFloatM14(data); - verify("testFloatM14", data, goldFloatM14); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - // positive byte_offset 56 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 56 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP14(float[] data) { - for (int j = 0; j < RANGE - 14; j++) { - data[j + 14] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP14") - @Warmup(0) - public static void runFloatP14() { - float[] data = new float[RANGE]; - init(data); - testFloatP14(data); - verify("testFloatP14", data, goldFloatP14); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM16(float[] data) { - for (int j = 16; j < RANGE; j++) { - data[j + -16] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM16") - @Warmup(0) - public static void runFloatM16() { - float[] data = new float[RANGE]; - init(data); - testFloatM16(data); - verify("testFloatM16", data, goldFloatM16); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 64 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP16(float[] data) { - for (int j = 0; j < RANGE - 16; j++) { - data[j + 16] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP16") - @Warmup(0) - public static void runFloatP16() { - float[] data = new float[RANGE]; - init(data); - testFloatP16(data); - verify("testFloatP16", data, goldFloatP16); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM18(float[] data) { - for (int j = 18; j < RANGE; j++) { - data[j + -18] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM18") - @Warmup(0) - public static void runFloatM18() { - float[] data = new float[RANGE]; - init(data); - testFloatM18(data); - verify("testFloatM18", data, goldFloatM18); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 72 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 72"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 72"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP18(float[] data) { - for (int j = 0; j < RANGE - 18; j++) { - data[j + 18] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP18") - @Warmup(0) - public static void runFloatP18() { - float[] data = new float[RANGE]; - init(data); - testFloatP18(data); - verify("testFloatP18", data, goldFloatP18); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM20(float[] data) { - for (int j = 20; j < RANGE; j++) { - data[j + -20] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM20") - @Warmup(0) - public static void runFloatM20() { - float[] data = new float[RANGE]; - init(data); - testFloatM20(data); - verify("testFloatM20", data, goldFloatM20); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 80 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 80"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 80"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP20(float[] data) { - for (int j = 0; j < RANGE - 20; j++) { - data[j + 20] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP20") - @Warmup(0) - public static void runFloatP20() { - float[] data = new float[RANGE]; - init(data); - testFloatP20(data); - verify("testFloatP20", data, goldFloatP20); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM31(float[] data) { - for (int j = 31; j < RANGE; j++) { - data[j + -31] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM31") - @Warmup(0) - public static void runFloatM31() { - float[] data = new float[RANGE]; - init(data); - testFloatM31(data); - verify("testFloatM31", data, goldFloatM31); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 124 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 124"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 124"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP31(float[] data) { - for (int j = 0; j < RANGE - 31; j++) { - data[j + 31] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP31") - @Warmup(0) - public static void runFloatP31() { - float[] data = new float[RANGE]; - init(data); - testFloatP31(data); - verify("testFloatP31", data, goldFloatP31); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM32(float[] data) { - for (int j = 32; j < RANGE; j++) { - data[j + -32] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM32") - @Warmup(0) - public static void runFloatM32() { - float[] data = new float[RANGE]; - init(data); - testFloatM32(data); - verify("testFloatM32", data, goldFloatM32); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 128 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP32(float[] data) { - for (int j = 0; j < RANGE - 32; j++) { - data[j + 32] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP32") - @Warmup(0) - public static void runFloatP32() { - float[] data = new float[RANGE]; - init(data); - testFloatP32(data); - verify("testFloatP32", data, goldFloatP32); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM63(float[] data) { - for (int j = 63; j < RANGE; j++) { - data[j + -63] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM63") - @Warmup(0) - public static void runFloatM63() { - float[] data = new float[RANGE]; - init(data); - testFloatM63(data); - verify("testFloatM63", data, goldFloatM63); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 252 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 252"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 252"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP63(float[] data) { - for (int j = 0; j < RANGE - 63; j++) { - data[j + 63] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP63") - @Warmup(0) - public static void runFloatP63() { - float[] data = new float[RANGE]; - init(data); - testFloatP63(data); - verify("testFloatP63", data, goldFloatP63); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM64(float[] data) { - for (int j = 64; j < RANGE; j++) { - data[j + -64] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM64") - @Warmup(0) - public static void runFloatM64() { - float[] data = new float[RANGE]; - init(data); - testFloatM64(data); - verify("testFloatM64", data, goldFloatM64); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP64(float[] data) { - for (int j = 0; j < RANGE - 64; j++) { - data[j + 64] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP64") - @Warmup(0) - public static void runFloatP64() { - float[] data = new float[RANGE]; - init(data); - testFloatP64(data); - verify("testFloatP64", data, goldFloatP64); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM65(float[] data) { - for (int j = 65; j < RANGE; j++) { - data[j + -65] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM65") - @Warmup(0) - public static void runFloatM65() { - float[] data = new float[RANGE]; - init(data); - testFloatM65(data); - verify("testFloatM65", data, goldFloatM65); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP65(float[] data) { - for (int j = 0; j < RANGE - 65; j++) { - data[j + 65] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP65") - @Warmup(0) - public static void runFloatP65() { - float[] data = new float[RANGE]; - init(data); - testFloatP65(data); - verify("testFloatP65", data, goldFloatP65); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM128(float[] data) { - for (int j = 128; j < RANGE; j++) { - data[j + -128] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM128") - @Warmup(0) - public static void runFloatM128() { - float[] data = new float[RANGE]; - init(data); - testFloatM128(data); - verify("testFloatM128", data, goldFloatM128); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP128(float[] data) { - for (int j = 0; j < RANGE - 128; j++) { - data[j + 128] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP128") - @Warmup(0) - public static void runFloatP128() { - float[] data = new float[RANGE]; - init(data); - testFloatP128(data); - verify("testFloatP128", data, goldFloatP128); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM129(float[] data) { - for (int j = 129; j < RANGE; j++) { - data[j + -129] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM129") - @Warmup(0) - public static void runFloatM129() { - float[] data = new float[RANGE]; - init(data); - testFloatM129(data); - verify("testFloatM129", data, goldFloatM129); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect misalignment. - @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP129(float[] data) { - for (int j = 0; j < RANGE - 129; j++) { - data[j + 129] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP129") - @Warmup(0) - public static void runFloatP129() { - float[] data = new float[RANGE]; - init(data); - testFloatP129(data); - verify("testFloatP129", data, goldFloatP129); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatM192(float[] data) { - for (int j = 192; j < RANGE; j++) { - data[j + -192] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatM192") - @Warmup(0) - public static void runFloatM192() { - float[] data = new float[RANGE]; - init(data); - testFloatM192(data); - verify("testFloatM192", data, goldFloatM192); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testFloatP192(float[] data) { - for (int j = 0; j < RANGE - 192; j++) { - data[j + 192] = (float)(data[j] * (float)1.001f); - } - } - - @Run(test = "testFloatP192") - @Warmup(0) - public static void runFloatP192() { - float[] data = new float[RANGE]; - init(data); - testFloatP192(data); - verify("testFloatP192", data, goldFloatP192); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP0(double[] data) { - for (int j = 0; j < RANGE; j++) { - data[j + 0] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP0") - @Warmup(0) - public static void runDoubleP0() { - double[] data = new double[RANGE]; - init(data); - testDoubleP0(data); - verify("testDoubleP0", data, goldDoubleP0); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM1(double[] data) { - for (int j = 1; j < RANGE; j++) { - data[j + -1] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM1") - @Warmup(0) - public static void runDoubleM1() { - double[] data = new double[RANGE]; - init(data); - testDoubleM1(data); - verify("testDoubleM1", data, goldDoubleM1); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - // positive byte_offset 8 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect alignment. - // No positive IR rule: conditions impossible. - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - // positive byte_offset 8 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect alignment. - // No positive IR rule: conditions impossible. - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - // positive byte_offset 8 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect alignment. - // No positive IR rule: conditions impossible. - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - // positive byte_offset 8 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect alignment. - // No positive IR rule: conditions impossible. - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 8 can lead to cyclic dependency - // No positive IR rule: conditions impossible. - // Expect alignment. - // No positive IR rule: conditions impossible. - public static void testDoubleP1(double[] data) { - for (int j = 0; j < RANGE - 1; j++) { - data[j + 1] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP1") - @Warmup(0) - public static void runDoubleP1() { - double[] data = new double[RANGE]; - init(data); - testDoubleP1(data); - verify("testDoubleP1", data, goldDoubleP1); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM2(double[] data) { - for (int j = 2; j < RANGE; j++) { - data[j + -2] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM2") - @Warmup(0) - public static void runDoubleM2() { - double[] data = new double[RANGE]; - init(data); - testDoubleM2(data); - verify("testDoubleM2", data, goldDoubleM2); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 16 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP2(double[] data) { - for (int j = 0; j < RANGE - 2; j++) { - data[j + 2] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP2") - @Warmup(0) - public static void runDoubleP2() { - double[] data = new double[RANGE]; - init(data); - testDoubleP2(data); - verify("testDoubleP2", data, goldDoubleP2); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM3(double[] data) { - for (int j = 3; j < RANGE; j++) { - data[j + -3] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM3") - @Warmup(0) - public static void runDoubleM3() { - double[] data = new double[RANGE]; - init(data); - testDoubleM3(data); - verify("testDoubleM3", data, goldDoubleM3); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - // positive byte_offset 24 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - // positive byte_offset 24 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 24 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP3(double[] data) { - for (int j = 0; j < RANGE - 3; j++) { - data[j + 3] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP3") - @Warmup(0) - public static void runDoubleP3() { - double[] data = new double[RANGE]; - init(data); - testDoubleP3(data); - verify("testDoubleP3", data, goldDoubleP3); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM4(double[] data) { - for (int j = 4; j < RANGE; j++) { - data[j + -4] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM4") - @Warmup(0) - public static void runDoubleM4() { - double[] data = new double[RANGE]; - init(data); - testDoubleM4(data); - verify("testDoubleM4", data, goldDoubleM4); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 32 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP4(double[] data) { - for (int j = 0; j < RANGE - 4; j++) { - data[j + 4] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP4") - @Warmup(0) - public static void runDoubleP4() { - double[] data = new double[RANGE]; - init(data); - testDoubleP4(data); - verify("testDoubleP4", data, goldDoubleP4); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM7(double[] data) { - for (int j = 7; j < RANGE; j++) { - data[j + -7] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM7") - @Warmup(0) - public static void runDoubleM7() { - double[] data = new double[RANGE]; - init(data); - testDoubleM7(data); - verify("testDoubleM7", data, goldDoubleM7); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - // positive byte_offset 56 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 56 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP7(double[] data) { - for (int j = 0; j < RANGE - 7; j++) { - data[j + 7] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP7") - @Warmup(0) - public static void runDoubleP7() { - double[] data = new double[RANGE]; - init(data); - testDoubleP7(data); - verify("testDoubleP7", data, goldDoubleP7); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM8(double[] data) { - for (int j = 8; j < RANGE; j++) { - data[j + -8] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM8") - @Warmup(0) - public static void runDoubleM8() { - double[] data = new double[RANGE]; - init(data); - testDoubleM8(data); - verify("testDoubleM8", data, goldDoubleM8); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 64 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 64"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP8(double[] data) { - for (int j = 0; j < RANGE - 8; j++) { - data[j + 8] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP8") - @Warmup(0) - public static void runDoubleP8() { - double[] data = new double[RANGE]; - init(data); - testDoubleP8(data); - verify("testDoubleP8", data, goldDoubleP8); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM14(double[] data) { - for (int j = 14; j < RANGE; j++) { - data[j + -14] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM14") - @Warmup(0) - public static void runDoubleM14() { - double[] data = new double[RANGE]; - init(data); - testDoubleM14(data); - verify("testDoubleM14", data, goldDoubleM14); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 112 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 112"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 112"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP14(double[] data) { - for (int j = 0; j < RANGE - 14; j++) { - data[j + 14] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP14") - @Warmup(0) - public static void runDoubleP14() { - double[] data = new double[RANGE]; - init(data); - testDoubleP14(data); - verify("testDoubleP14", data, goldDoubleP14); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM16(double[] data) { - for (int j = 16; j < RANGE; j++) { - data[j + -16] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM16") - @Warmup(0) - public static void runDoubleM16() { - double[] data = new double[RANGE]; - init(data); - testDoubleM16(data); - verify("testDoubleM16", data, goldDoubleM16); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 128 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 128"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP16(double[] data) { - for (int j = 0; j < RANGE - 16; j++) { - data[j + 16] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP16") - @Warmup(0) - public static void runDoubleP16() { - double[] data = new double[RANGE]; - init(data); - testDoubleP16(data); - verify("testDoubleP16", data, goldDoubleP16); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM18(double[] data) { - for (int j = 18; j < RANGE; j++) { - data[j + -18] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM18") - @Warmup(0) - public static void runDoubleM18() { - double[] data = new double[RANGE]; - init(data); - testDoubleM18(data); - verify("testDoubleM18", data, goldDoubleM18); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 144 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 144"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 144"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP18(double[] data) { - for (int j = 0; j < RANGE - 18; j++) { - data[j + 18] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP18") - @Warmup(0) - public static void runDoubleP18() { - double[] data = new double[RANGE]; - init(data); - testDoubleP18(data); - verify("testDoubleP18", data, goldDoubleP18); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM20(double[] data) { - for (int j = 20; j < RANGE; j++) { - data[j + -20] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM20") - @Warmup(0) - public static void runDoubleM20() { - double[] data = new double[RANGE]; - init(data); - testDoubleM20(data); - verify("testDoubleM20", data, goldDoubleM20); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 160 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 160"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 160"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP20(double[] data) { - for (int j = 0; j < RANGE - 20; j++) { - data[j + 20] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP20") - @Warmup(0) - public static void runDoubleP20() { - double[] data = new double[RANGE]; - init(data); - testDoubleP20(data); - verify("testDoubleP20", data, goldDoubleP20); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM31(double[] data) { - for (int j = 31; j < RANGE; j++) { - data[j + -31] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM31") - @Warmup(0) - public static void runDoubleM31() { - double[] data = new double[RANGE]; - init(data); - testDoubleM31(data); - verify("testDoubleM31", data, goldDoubleM31); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - // positive byte_offset 248 can lead to cyclic dependency - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 248"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 248"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP31(double[] data) { - for (int j = 0; j < RANGE - 31; j++) { - data[j + 31] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP31") - @Warmup(0) - public static void runDoubleP31() { - double[] data = new double[RANGE]; - init(data); - testDoubleP31(data); - verify("testDoubleP31", data, goldDoubleP31); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM32(double[] data) { - for (int j = 32; j < RANGE; j++) { - data[j + -32] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM32") - @Warmup(0) - public static void runDoubleM32() { - double[] data = new double[RANGE]; - init(data); - testDoubleM32(data); - verify("testDoubleM32", data, goldDoubleM32); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP32(double[] data) { - for (int j = 0; j < RANGE - 32; j++) { - data[j + 32] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP32") - @Warmup(0) - public static void runDoubleP32() { - double[] data = new double[RANGE]; - init(data); - testDoubleP32(data); - verify("testDoubleP32", data, goldDoubleP32); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM63(double[] data) { - for (int j = 63; j < RANGE; j++) { - data[j + -63] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM63") - @Warmup(0) - public static void runDoubleM63() { - double[] data = new double[RANGE]; - init(data); - testDoubleM63(data); - verify("testDoubleM63", data, goldDoubleM63); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP63(double[] data) { - for (int j = 0; j < RANGE - 63; j++) { - data[j + 63] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP63") - @Warmup(0) - public static void runDoubleP63() { - double[] data = new double[RANGE]; - init(data); - testDoubleP63(data); - verify("testDoubleP63", data, goldDoubleP63); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM64(double[] data) { - for (int j = 64; j < RANGE; j++) { - data[j + -64] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM64") - @Warmup(0) - public static void runDoubleM64() { - double[] data = new double[RANGE]; - init(data); - testDoubleM64(data); - verify("testDoubleM64", data, goldDoubleM64); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP64(double[] data) { - for (int j = 0; j < RANGE - 64; j++) { - data[j + 64] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP64") - @Warmup(0) - public static void runDoubleP64() { - double[] data = new double[RANGE]; - init(data); - testDoubleP64(data); - verify("testDoubleP64", data, goldDoubleP64); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM65(double[] data) { - for (int j = 65; j < RANGE; j++) { - data[j + -65] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM65") - @Warmup(0) - public static void runDoubleM65() { - double[] data = new double[RANGE]; - init(data); - testDoubleM65(data); - verify("testDoubleM65", data, goldDoubleM65); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP65(double[] data) { - for (int j = 0; j < RANGE - 65; j++) { - data[j + 65] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP65") - @Warmup(0) - public static void runDoubleP65() { - double[] data = new double[RANGE]; - init(data); - testDoubleP65(data); - verify("testDoubleP65", data, goldDoubleP65); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM128(double[] data) { - for (int j = 128; j < RANGE; j++) { - data[j + -128] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM128") - @Warmup(0) - public static void runDoubleM128() { - double[] data = new double[RANGE]; - init(data); - testDoubleM128(data); - verify("testDoubleM128", data, goldDoubleM128); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP128(double[] data) { - for (int j = 0; j < RANGE - 128; j++) { - data[j + 128] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP128") - @Warmup(0) - public static void runDoubleP128() { - double[] data = new double[RANGE]; - init(data); - testDoubleP128(data); - verify("testDoubleP128", data, goldDoubleP128); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM129(double[] data) { - for (int j = 129; j < RANGE; j++) { - data[j + -129] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM129") - @Warmup(0) - public static void runDoubleM129() { - double[] data = new double[RANGE]; - init(data); - testDoubleM129(data); - verify("testDoubleM129", data, goldDoubleM129); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP129(double[] data) { - for (int j = 0; j < RANGE - 129; j++) { - data[j + 129] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP129") - @Warmup(0) - public static void runDoubleP129() { - double[] data = new double[RANGE]; - init(data); - testDoubleP129(data); - verify("testDoubleP129", data, goldDoubleP129); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleM192(double[] data) { - for (int j = 192; j < RANGE; j++) { - data[j + -192] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleM192") - @Warmup(0) - public static void runDoubleM192() { - double[] data = new double[RANGE]; - init(data); - testDoubleM192(data); - verify("testDoubleM192", data, goldDoubleM192); - } - - @Test - // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"avx512", "true"}) - // CPU: asimd -> vector_width: 16 -> elements in vector: 2 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - // Expect alignment. - @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, - applyIfCPUFeature = {"sve", "true"}) - public static void testDoubleP192(double[] data) { - for (int j = 0; j < RANGE - 192; j++) { - data[j + 192] = (double)(data[j] * (double)1.001); - } - } - - @Run(test = "testDoubleP192") - @Warmup(0) - public static void runDoubleP192() { - double[] data = new double[RANGE]; - init(data); - testDoubleP192(data); - verify("testDoubleP192", data, goldDoubleP192); - } - - // ------------------- Initialization ------------------- - - static void init(int[] data) { - for (int j = 0; j < RANGE; j++) { - data[j] = (int)j; - } - } - - static void init(long[] data) { - for (int j = 0; j < RANGE; j++) { - data[j] = (long)j; - } - } - - static void init(short[] data) { - for (int j = 0; j < RANGE; j++) { - data[j] = (short)j; - } - } - - static void init(char[] data) { - for (int j = 0; j < RANGE; j++) { - data[j] = (char)j; - } - } - - static void init(byte[] data) { - for (int j = 0; j < RANGE; j++) { - data[j] = (byte)j; - } - } - - static void init(float[] data) { - for (int j = 0; j < RANGE; j++) { - data[j] = (float)j; - } - } - - static void init(double[] data) { - for (int j = 0; j < RANGE; j++) { - data[j] = (double)j; - } - } - - // ------------------- Verification ------------------- - - static void verify(String context, int[] data, int[] gold) { - for (int i = 0; i < RANGE; i++) { - if (data[i] != gold[i]) { - throw new RuntimeException(" Invalid " + context + " result: data[" + i + "]: " + data[i] + " != " + gold[i]); - } - } - } - static void verify(String context, long[] data, long[] gold) { - for (int i = 0; i < RANGE; i++) { - if (data[i] != gold[i]) { - throw new RuntimeException(" Invalid " + context + " result: data[" + i + "]: " + data[i] + " != " + gold[i]); - } - } - } - static void verify(String context, short[] data, short[] gold) { - for (int i = 0; i < RANGE; i++) { - if (data[i] != gold[i]) { - throw new RuntimeException(" Invalid " + context + " result: data[" + i + "]: " + data[i] + " != " + gold[i]); - } - } - } - static void verify(String context, char[] data, char[] gold) { - for (int i = 0; i < RANGE; i++) { - if (data[i] != gold[i]) { - throw new RuntimeException(" Invalid " + context + " result: data[" + i + "]: " + data[i] + " != " + gold[i]); - } - } - } - static void verify(String context, byte[] data, byte[] gold) { - for (int i = 0; i < RANGE; i++) { - if (data[i] != gold[i]) { - throw new RuntimeException(" Invalid " + context + " result: data[" + i + "]: " + data[i] + " != " + gold[i]); - } - } - } - static void verify(String context, float[] data, float[] gold) { - for (int i = 0; i < RANGE; i++) { - if (data[i] != gold[i]) { - throw new RuntimeException(" Invalid " + context + " result: data[" + i + "]: " + data[i] + " != " + gold[i]); - } - } - } - static void verify(String context, double[] data, double[] gold) { - for (int i = 0; i < RANGE; i++) { - if (data[i] != gold[i]) { - throw new RuntimeException(" Invalid " + context + " result: data[" + i + "]: " + data[i] + " != " + gold[i]); + String counts() { + if (!isPositiveRule) { + return String.format(""" + @IR(failOn = {IRNode.LOAD_VECTOR_%s, + IRNode.%s, + IRNode.STORE_VECTOR}, + """, + type.letter(), + irNode); + } else if (size == null) { + return String.format(""" + @IR(counts = {IRNode.LOAD_VECTOR_%s, ">0", + IRNode.%s, ">0", + IRNode.STORE_VECTOR, ">0"}, + """, + type.letter(), + irNode); + } else { + return String.format(""" + @IR(counts = {IRNode.LOAD_VECTOR_%s, IRNode.VECTOR_SIZE + "%s", ">0", + IRNode.%s, IRNode.VECTOR_SIZE + "%s", ">0", + IRNode.STORE_VECTOR, ">0"}, + """, + type.letter(), size, + irNode, size); } } } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java index 65398e8adfd39..197ae08b6d882 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java @@ -172,10 +172,10 @@ public void runTest2() { static void test2(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) { for (int i = 0; i < RANGE; i+=2) { // int and float arrays are two slices. But we pretend both are of type int. - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1); - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] + 1); - dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0); - dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4); + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, dataIa[i+0] + 1); + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, dataIa[i+1] + 1); + dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0); + dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4); } } @@ -248,10 +248,10 @@ static void test5(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) { for (int i = 0; i < RANGE; i+=2) { // same as test2, except that reordering leads to different semantics // explanation analogue to test4 - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1); // A - dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0); // X - dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4); // Y - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] + 1); // B + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, dataIa[i+0] + 1); // A + dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0); // X + dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4); // Y + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, dataIa[i+1] + 1); // B } } @@ -275,18 +275,18 @@ static void test6(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, long[] dataLa, long[] dataLb) { for (int i = 0; i < RANGE; i+=2) { // Chain of parallelizable op and conversion - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45; - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45; + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); } } @@ -307,18 +307,18 @@ static void test7(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, long[] dataLa, long[] dataLb) { for (int i = 0; i < RANGE; i+=2) { // Cycle involving 3 memory slices - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45; - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // moved down - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45; + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; // moved down + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); } } @@ -340,19 +340,19 @@ static void test8(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, long[] dataLa, long[] dataLb) { for (int i = 0; i < RANGE; i+=2) { // 2-cycle, with more ops after - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45; - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45; + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); // more stuff after - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); } } @@ -373,19 +373,19 @@ static void test9(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, long[] dataLa, long[] dataLb) { for (int i = 0; i < RANGE; i+=2) { // 2-cycle, with more stuff before - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); // 2-cycle - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45; - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45; + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); } } @@ -423,18 +423,18 @@ static void test10(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, // // The cycle thus does not only go via packs, but also scalar ops. // - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; // A - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; // R: constant mismatch - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) + 43; // S - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; // U - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; // V - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // B: moved down - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; // A + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; // R: constant mismatch + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) + 43; // S + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; // U + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; // V + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; // B: moved down + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); } } @@ -463,8 +463,8 @@ static void verify(String name, int[] data, int[] gold) { static void verify(String name, float[] data, float[] gold) { for (int i = 0; i < RANGE; i++) { - int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i); - int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i); + int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i); + int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i); if (datav != goldv) { throw new RuntimeException(" Invalid " + name + " result: dataF[" + i + "]: " + datav + " != " + goldv); } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java index 32d69689a4269..2be7d52c78087 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java @@ -58,18 +58,18 @@ static void test(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, long[] dataLa, long[] dataLb) { for (int i = 0; i < RANGE; i+=2) { // For explanation, see test 10 in TestIndependentPacksWithCyclicDependency.java - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) + 43; - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // moved down - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) + 43; + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; // moved down + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); } } @@ -83,8 +83,8 @@ static void verify(String name, int[] data, int[] gold) { static void verify(String name, float[] data, float[] gold) { for (int i = 0; i < RANGE; i++) { - int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i); - int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i); + int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i); + int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i); if (datav != goldv) { throw new RuntimeException(" Invalid " + name + " result: dataF[" + i + "]: " + datav + " != " + goldv); } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java index f2ed8b6aec2b3..c54a684c6911d 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java @@ -124,10 +124,10 @@ static void test1(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) { for (int i = 0; i < RANGE; i+=2) { // Do the same as test0, but without int-float conversion. // This should reproduce on machines where conversion is not implemented. - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1); // A +1 - dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0); // X - dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4); // Y - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] * 11); // B *11 + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, dataIa[i+0] + 1); // A +1 + dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0); // X + dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4); // Y + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, dataIa[i+1] * 11); // B *11 } } diff --git a/test/hotspot/jtreg/compiler/loopstripmining/TestNoWarningLoopStripMiningIterSet.java b/test/hotspot/jtreg/compiler/loopstripmining/TestNoWarningLoopStripMiningIterSet.java index c356e4495c245..c7fedf8982e68 100644 --- a/test/hotspot/jtreg/compiler/loopstripmining/TestNoWarningLoopStripMiningIterSet.java +++ b/test/hotspot/jtreg/compiler/loopstripmining/TestNoWarningLoopStripMiningIterSet.java @@ -44,25 +44,14 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @bug 8241486 * @summary G1/Z give warning when using LoopStripMiningIter and turn off LoopStripMiningIter (0) * @requires vm.flagless * @requires vm.flavor == "server" & !vm.graal.enabled - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @library /test/lib - * @run driver TestNoWarningLoopStripMiningIterSet Z -XX:-ZGenerational - */ - -/* - * @test id=ZGenerational - * @bug 8241486 - * @summary G1/Z give warning when using LoopStripMiningIter and turn off LoopStripMiningIter (0) - * @requires vm.flagless - * @requires vm.flavor == "server" & !vm.graal.enabled - * @requires vm.gc.ZGenerational - * @library /test/lib - * @run driver TestNoWarningLoopStripMiningIterSet Z -XX:+ZGenerational + * @run driver TestNoWarningLoopStripMiningIterSet Z */ /* @@ -106,18 +95,9 @@ public static void testWith(Consumer check, String msg, boolean public static void main(String[] args) throws Exception { String gc = "-XX:+Use" + args[0] + "GC"; - if (args.length > 1) { - String extraVMArg = args[1]; - testWith(output -> output.shouldNotContain(CLSOffLSMGreaterZero), "should have CLS and LSM enabled", true, 100, "-XX:LoopStripMiningIter=100", gc, extraVMArg); - testWith(output -> output.shouldContain(CLSOffLSMGreaterZero), "should have CLS and LSM disabled", false, 0, "-XX:-UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=100", gc, extraVMArg); - testWith(output -> output.shouldContain(CLSOnLSMEqualZero), "should have CLS and LSM enabled", true, 1, "-XX:LoopStripMiningIter=0", gc, extraVMArg); - testWith(output -> output.shouldNotContain(CLSOnLSMEqualZero), "should have CLS and LSM disabled", false, 0, "-XX:-UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=0", gc, extraVMArg); - } else { - testWith(output -> output.shouldNotContain(CLSOffLSMGreaterZero), "should have CLS and LSM enabled", true, 100, "-XX:LoopStripMiningIter=100", gc); - testWith(output -> output.shouldContain(CLSOffLSMGreaterZero), "should have CLS and LSM disabled", false, 0, "-XX:-UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=100", gc); - testWith(output -> output.shouldContain(CLSOnLSMEqualZero), "should have CLS and LSM enabled", true, 1, "-XX:LoopStripMiningIter=0", gc); - testWith(output -> output.shouldNotContain(CLSOnLSMEqualZero), "should have CLS and LSM disabled", false, 0, "-XX:-UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=0", gc); - - } + testWith(output -> output.shouldNotContain(CLSOffLSMGreaterZero), "should have CLS and LSM enabled", true, 100, "-XX:LoopStripMiningIter=100", gc); + testWith(output -> output.shouldContain(CLSOffLSMGreaterZero), "should have CLS and LSM disabled", false, 0, "-XX:-UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=100", gc); + testWith(output -> output.shouldContain(CLSOnLSMEqualZero), "should have CLS and LSM enabled", true, 1, "-XX:LoopStripMiningIter=0", gc); + testWith(output -> output.shouldNotContain(CLSOnLSMEqualZero), "should have CLS and LSM disabled", false, 0, "-XX:-UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=0", gc); } } diff --git a/test/hotspot/jtreg/compiler/predicates/TestTopIntoIfTrue.java b/test/hotspot/jtreg/compiler/predicates/TestTopIntoIfTrue.java new file mode 100644 index 0000000000000..b0fa8b33c0556 --- /dev/null +++ b/test/hotspot/jtreg/compiler/predicates/TestTopIntoIfTrue.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. + * + */ + +/* + * @test + * @key stress randomness + * @bug 8342809 + * @summary Test that a top input into an IfTrue of an Assertion Predicate is properly handled during IGVN. + * @requires vm.compiler2.enabled + * @run main/othervm -XX:CompileCommand=compileonly,compiler.predicates.TestTopIntoIfTrue::test -XX:-TieredCompilation + * -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:StressSeed=1073486978 + * compiler.predicates.TestTopIntoIfTrue + * @run main/othervm -XX:CompileCommand=compileonly,compiler.predicates.TestTopIntoIfTrue::test -XX:-TieredCompilation + * -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN compiler.predicates.TestTopIntoIfTrue + */ + +package compiler.predicates; + +public class TestTopIntoIfTrue { + static int iFld; + + public static void main(String[] strArr) { + for (int i = 0; i < 100; i++) { + test(); + } + } + + static void test() { + int x = 10; + for (int i = 1; i < 326; ++i) { + x += 12; + if (x != 0) { + Unloaded.trap(); // unloaded trap + } + iFld += 34; + } + } +} + +class Unloaded { + static void trap() {} +} \ No newline at end of file diff --git a/test/hotspot/jtreg/compiler/predicates/TestAssertionPredicateDoesntConstantFold.java b/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicateDoesntConstantFold.java similarity index 100% rename from test/hotspot/jtreg/compiler/predicates/TestAssertionPredicateDoesntConstantFold.java rename to test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicateDoesntConstantFold.java diff --git a/test/hotspot/jtreg/compiler/predicates/assertion/TestMissingSetCtrlForTrueConstant.java b/test/hotspot/jtreg/compiler/predicates/assertion/TestMissingSetCtrlForTrueConstant.java new file mode 100644 index 0000000000000..565069ac75c42 --- /dev/null +++ b/test/hotspot/jtreg/compiler/predicates/assertion/TestMissingSetCtrlForTrueConstant.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 + * @bug 8343137 + * @requires vm.debug == true & vm.compiler2.enabled + * @summary Test that set_ctrl() is properly set for true constant when folding useless Template Assertion Predicate. + * @run main/othervm -Xcomp -XX:+VerifyLoopOptimizations + * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestMissingSetCtrlForTrueConstant::test + * compiler.predicates.assertion.TestMissingSetCtrlForTrueConstant + */ + +package compiler.predicates.assertion; + +public class TestMissingSetCtrlForTrueConstant { + static long iFld; + static int[] iArrFld = new int[100]; + static double[] dArrFld = new double[100]; + + public static void main(String[] strArr) { + test(); + } + + static void test() { + long l = 34; + for (int i = 78; i > 8; --i) { + switch (i) { + case 24: + l += iFld - 34; + case 25: + iFld = iArrFld[i] += i; + } + dArrFld[i + 1] += i; + } + } +} diff --git a/test/hotspot/jtreg/compiler/predicates/TestTemplateAssertionPredicateNotRemoved.java b/test/hotspot/jtreg/compiler/predicates/assertion/TestTemplateAssertionPredicateNotRemoved.java similarity index 88% rename from test/hotspot/jtreg/compiler/predicates/TestTemplateAssertionPredicateNotRemoved.java rename to test/hotspot/jtreg/compiler/predicates/assertion/TestTemplateAssertionPredicateNotRemoved.java index 557d9d461bfad..6d8588213b5d0 100644 --- a/test/hotspot/jtreg/compiler/predicates/TestTemplateAssertionPredicateNotRemoved.java +++ b/test/hotspot/jtreg/compiler/predicates/assertion/TestTemplateAssertionPredicateNotRemoved.java @@ -29,14 +29,14 @@ * completely with JDK-8288981 and 8314116 just mitigates the problem. * @requires vm.compiler2.enabled * @run main/othervm -Xbatch -XX:-TieredCompilation - * -XX:CompileCommand=compileonly,compiler.predicates.TestTemplateAssertionPredicateNotRemoved::* - * compiler.predicates.TestTemplateAssertionPredicateNotRemoved + * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestTemplateAssertionPredicateNotRemoved::* + * compiler.predicates.assertion.TestTemplateAssertionPredicateNotRemoved * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:LoopMaxUnroll=0 - * -XX:CompileCommand=compileonly,compiler.predicates.TestTemplateAssertionPredicateNotRemoved::* - * compiler.predicates.TestTemplateAssertionPredicateNotRemoved + * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestTemplateAssertionPredicateNotRemoved::* + * compiler.predicates.assertion.TestTemplateAssertionPredicateNotRemoved */ -package compiler.predicates; +package compiler.predicates.assertion; public class TestTemplateAssertionPredicateNotRemoved { static int[] iArrFld = new int[10]; diff --git a/test/hotspot/jtreg/compiler/predicates/assertion/TestTemplateAssertionPredicateWithTwoUCTs.java b/test/hotspot/jtreg/compiler/predicates/assertion/TestTemplateAssertionPredicateWithTwoUCTs.java new file mode 100644 index 0000000000000..7d21f6b5f2dab --- /dev/null +++ b/test/hotspot/jtreg/compiler/predicates/assertion/TestTemplateAssertionPredicateWithTwoUCTs.java @@ -0,0 +1,60 @@ +/* + * 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 8342287 + * @summary Test that a fail path projection of a Template Assertion Predicate is not treated as success path projection. + * @run main/othervm -XX:-TieredCompilation -Xbatch + * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestTemplateAssertionPredicateWithTwoUCTs::test + * compiler.predicates.assertion.TestTemplateAssertionPredicateWithTwoUCTs + */ + +package compiler.predicates.assertion; + +public class TestTemplateAssertionPredicateWithTwoUCTs { + static int iFld; + + public static void main(String[] strArr) { + for (int i = 0; i < 1000; i++) { + test(); + } + } + + static void test() { + int[][] lArr = new int[100][1]; + for (int i14 = 5; i14 < 273; ++i14) { + int i16 = 1; + while (++i16 < 94) { + lArr[i16][0] += 1; + switch (i14) { + case 11: + case 2: + case 13: + iFld = 34; + } + } + } + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPageTableEntry.java b/test/hotspot/jtreg/compiler/rangechecks/TestLimitControlWhenNoRCEliminated.java similarity index 53% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPageTableEntry.java rename to test/hotspot/jtreg/compiler/rangechecks/TestLimitControlWhenNoRCEliminated.java index 42a29878eccd9..1d8d947c98256 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XPageTableEntry.java +++ b/test/hotspot/jtreg/compiler/rangechecks/TestLimitControlWhenNoRCEliminated.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -19,34 +19,43 @@ * Please 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.jvm.hotspot.gc.x; - -import sun.jvm.hotspot.debugger.Address; -import sun.jvm.hotspot.runtime.VMObjectFactory; - -class XPageTableEntry { - Address entry; - - XPageTableEntry(Address address) { - entry = address; - } +/** + * @test + * @bug 8341407 + * @summary C2: assert(main_limit == cl->limit() || get_ctrl(main_limit) == new_limit_ctrl) failed: wrong control for added limit + * + * @run main/othervm -XX:CompileCommand=compileonly,TestLimitControlWhenNoRCEliminated::* -Xcomp TestLimitControlWhenNoRCEliminated + * + */ - XPage page() { - return VMObjectFactory.newObject(XPage.class, zPageBits()); - } +public class TestLimitControlWhenNoRCEliminated { + static long[] lArr; + static int iFld; - private Address zPageBits() { - return entry.andWithMask(~1L); + public static void main(String[] strArr) { + try { + test(); + } catch (NullPointerException npe) {} } - boolean relocating() { - return (entry.asLongValue() & 1) == 1; + static void test() { + int x = iFld; + int i = 1; + do { + lArr[i - 1] = 9; + x += 1; + iFld += x; + if (x != 0) { + A.foo(); + } + } while (++i < 23); } +} - boolean isEmpty() { - return entry == null || zPageBits() == null; +class A { + static void foo() { } } + diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestSunkRangeFromPreLoopRCE.java b/test/hotspot/jtreg/compiler/rangechecks/TestSunkRangeFromPreLoopRCE.java new file mode 100644 index 0000000000000..4e788df035ed6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestSunkRangeFromPreLoopRCE.java @@ -0,0 +1,81 @@ +/* + * 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 8342330 + * @summary C2: "node pinned on loop exit test?" assert failure + * @requires vm.flavor == "server" + * + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:-TieredCompilation + * -XX:-UseLoopPredicate -XX:LoopMaxUnroll=0 TestSunkRangeFromPreLoopRCE + * + */ + + +import java.util.Arrays; + +public class TestSunkRangeFromPreLoopRCE { + private static int[] array = new int[1000]; + private static A objectField = new A(42); + + public static void main(String[] args) { + boolean[] allTrue = new boolean[1000]; + Arrays.fill(allTrue, true); + boolean[] allFalse = new boolean[1000]; + for (int i = 0; i < 20_000; i++) { + test1(array.length/4, allTrue, 1, 0); + test1(array.length/4, allFalse, 1, 0); + } + } + + private static int test1(int stop, boolean[] flags, int otherScale, int x) { + int scale; + for (scale = 0; scale < 4; scale++) { + for (int i = 0; i < 10; i++) { + + } + } + if (array == null) { + } + int v = 0; + for (int i = 0; i < stop; i++) { + v += array[i]; + v += array[scale * i]; + if (i * scale + (objectField.intField + 1) == x) { + } + v += (scale - 4) * (x-objectField.intField); + if (flags[i]) { + return (x-objectField.intField); + } + } + return v; + } + + private static class A { + A(int field) { + intField = field; + } + public int intField; + } +} diff --git a/test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java b/test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java new file mode 100644 index 0000000000000..ecd8f58c5ed82 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java @@ -0,0 +1,98 @@ +/* + * 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.runtime.safepoints; + +import compiler.lib.ir_framework.*; +import java.lang.ref.SoftReference; + +/** + * @test + * @summary Test that undefined values generated by MachTemp nodes (in this + * case, derived from G1 barriers) are not included in OopMaps. + * Extracted from java.lang.invoke.LambdaFormEditor::getInCache. + * @key randomness + * @library /test/lib / + * @requires vm.gc.G1 & vm.bits == 64 & vm.opt.final.UseCompressedOops == true + * @run driver compiler.runtime.safepoints.TestMachTempsAcrossSafepoints + */ + +public class TestMachTempsAcrossSafepoints { + + static class RefWithKey extends SoftReference { + final int key; + + public RefWithKey(int key) { + super(new Object()); + this.key = key; + } + + @DontInline + @Override + public boolean equals(Object obj) { + return obj instanceof RefWithKey that && this.key == that.key; + } + } + + public static void main(String[] args) throws Exception { + String inlineCmd = "-XX:CompileCommand=inline,java.lang.ref.SoftReference::get"; + TestFramework.runWithFlags(inlineCmd, "-XX:+StressGCM", "-XX:+StressLCM", "-XX:StressSeed=1"); + TestFramework.runWithFlags(inlineCmd, "-XX:+StressGCM", "-XX:+StressLCM"); + } + + @Test + @IR(counts = {IRNode.G1_LOAD_N, "1"}, phase = CompilePhase.FINAL_CODE) + @IR(counts = {IRNode.MACH_TEMP, ">= 1"}, phase = CompilePhase.FINAL_CODE) + @IR(counts = {IRNode.STATIC_CALL_OF_METHOD, "equals", "2"}) + @IR(failOn = {IRNode.OOPMAP_WITH, "NarrowOop"}) + static private Object test(RefWithKey key, RefWithKey[] refs) { + RefWithKey k = null; + // This loop causes the register allocator to not "rematerialize" all + // MachTemp nodes generated for the reference g1LoadN instruction below. + for (int i = 0; i < refs.length; i++) { + RefWithKey k0 = refs[0]; + if (k0.equals(key)) { + k = k0; + } + } + if (k != null && !key.equals(k)) { + return null; + } + // The MachTemp node implementing the dst TEMP operand in the g1LoadN + // instruction corresponding to k.get() can be scheduled across the + // above call to RefWithKey::equals(), due to an unfortunate interaction + // of inaccurate basic block frequency estimation (emulated in this test + // by randomizing the GCM and LCM heuristics) and call-catch cleanup. + // Since narrow pointer MachTemp nodes are typed as narrow OOPs, this + // causes the oopmap builder to include the MachTemp node definition in + // the RefWithKey::equals() return oopmap. + return (k != null) ? k.get() : null; + } + + @Run(test = "test") + @Warmup(0) + public void run() { + RefWithKey ref = new RefWithKey(42); + test(ref, new RefWithKey[]{ref}); + } +} diff --git a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java index 27fe9989247b9..0c53c36af1dde 100644 --- a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java +++ b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.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 @@ -104,8 +104,10 @@ public class IntrinsicPredicates { new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null)))))))))); public static final BooleanSupplier SHA3_INSTRUCTION_AVAILABLE - // sha3 is only implemented on aarch64 for now - = new CPUSpecificPredicate("aarch64.*", new String[] {"sha3" }, null); + // sha3 is only implemented on aarch64 and avx512 for now + = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] {"sha3" }, null), + new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] {"avx512f", "avx512bw"}, null), + new CPUSpecificPredicate("x86_64", new String[] {"avx512f", "avx512bw"}, null))); public static final BooleanSupplier ANY_SHA_INSTRUCTION_AVAILABLE = new OrPredicate(IntrinsicPredicates.SHA1_INSTRUCTION_AVAILABLE, diff --git a/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java b/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java new file mode 100644 index 0000000000000..5090c2dd6cf97 --- /dev/null +++ b/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java @@ -0,0 +1,101 @@ +/* + * 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 8340214 + * @summary C2 compilation asserts with "no node with a side effect" in PhaseIdealLoop::try_sink_out_of_loop + * + * @run main/othervm -XX:-BackgroundCompilation TestBadMemSliceWithInterfaces + * + */ + +public class TestBadMemSliceWithInterfaces { + public static void main(String[] args) { + B b = new B(); + C c = new C(); + for (int i = 0; i < 20_000; i++) { + test1(b, c, true); + test1(b, c, false); + b.field = 0; + c.field = 0; + int res = test2(b, c, true); + if (res != 42) { + throw new RuntimeException("incorrect result " + res); + } + res = test2(b, c, false); + if (res != 42) { + throw new RuntimeException("incorrect result " + res); + } + } + } + + private static void test1(B b, C c, boolean flag) { + A a; + if (flag) { + a = b; + } else { + a = c; + } + for (int i = 0; i < 1000; i++) { + a.field = 42; + } + } + + private static int test2(B b, C c, boolean flag) { + A a; + if (flag) { + a = b; + } else { + a = c; + } + int v = 0; + for (int i = 0; i < 2; i++) { + v += a.field; + a.field = 42; + } + return v; + } + + interface I { + void m(); + } + + static class A { + int field; + } + + static class B extends A implements I { + @Override + public void m() { + + } + } + + static class C extends A implements I { + @Override + public void m() { + + } + } +} diff --git a/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java b/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java index 6f1f4138435f7..a0a2aacde3f4a 100644 --- a/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java +++ b/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java @@ -34,28 +34,15 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @bug 8273456 * @summary Test that ttyLock is ranked above StackWatermark_lock - * @requires !vm.graal.enabled & vm.gc.ZSinglegen + * @requires !vm.graal.enabled & vm.gc.Z * @run main/othervm -XX:-BackgroundCompilation -Xmx128M -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::main * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::m9_1 * -XX:+UnlockDiagnosticVMOptions - * -XX:+UseZGC -XX:-ZGenerational -XX:+LogCompilation -XX:+PrintDeoptimizationDetails -XX:+TraceDeoptimization -XX:+Verbose - * compiler.uncommontrap.TestDeoptOOM - */ - -/* - * @test id=ZGenerational - * @bug 8273456 - * @summary Test that ttyLock is ranked above StackWatermark_lock - * @requires !vm.graal.enabled & vm.gc.ZGenerational - * @run main/othervm -XX:-BackgroundCompilation -Xmx128M -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack - * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::main - * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::m9_1 - * -XX:+UnlockDiagnosticVMOptions - * -XX:+UseZGC -XX:+ZGenerational -XX:+LogCompilation -XX:+PrintDeoptimizationDetails -XX:+TraceDeoptimization -XX:+Verbose + * -XX:+UseZGC -XX:+LogCompilation -XX:+PrintDeoptimizationDetails -XX:+TraceDeoptimization -XX:+Verbose * compiler.uncommontrap.TestDeoptOOM */ diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithImmTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithImmTest.java index b7c192778bd55..833ef2b614cda 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithImmTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithImmTest.java @@ -143,7 +143,7 @@ public static void testByteGTInRange_runner() { @IR(counts = { IRNode.VMASK_CMPU_IMM_I_SVE, ">= 1" }) public static void testByteUnsignedGTInRange() { ByteVector av = ByteVector.fromArray(B_SPECIES, ba, 0); - av.compare(VectorOperators.UNSIGNED_GT, 64).intoArray(br, 0); + av.compare(VectorOperators.UGT, 64).intoArray(br, 0); } @Run(test = "testByteUnsignedGTInRange") @@ -163,7 +163,7 @@ public static void testByteGTOutOfRange() { @IR(failOn = { IRNode.VMASK_CMPU_IMM_I_SVE }) public static void testByteUnsignedGTOutOfRange() { ByteVector av = ByteVector.fromArray(B_SPECIES, ba, 0); - av.compare(VectorOperators.UNSIGNED_GT, -91).intoArray(br, 0); + av.compare(VectorOperators.UGT, -91).intoArray(br, 0); } @Test @@ -183,7 +183,7 @@ public static void testShortGEInRange_runner() { @IR(counts = { IRNode.VMASK_CMPU_IMM_I_SVE, ">= 1" }) public static void testShortUnsignedGEInRange() { ShortVector av = ShortVector.fromArray(S_SPECIES, sa, 0); - av.compare(VectorOperators.UNSIGNED_GE, 56).intoArray(sr, 0); + av.compare(VectorOperators.UGE, 56).intoArray(sr, 0); } @Run(test = "testShortUnsignedGEInRange") @@ -203,7 +203,7 @@ public static void testShortGEOutOfRange() { @IR(failOn = { IRNode.VMASK_CMPU_IMM_I_SVE }) public static void testShortUnsignedGEOutOfRange() { ShortVector av = ShortVector.fromArray(S_SPECIES, sa, 0); - av.compare(VectorOperators.UNSIGNED_GE, -85).intoArray(sr, 0); + av.compare(VectorOperators.UGE, -85).intoArray(sr, 0); } @Test @@ -223,7 +223,7 @@ public static void testIntLTInRange_runner() { @IR(counts = { IRNode.VMASK_CMPU_IMM_I_SVE, ">= 1" }) public static void testIntUnsignedLTInRange() { IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); - av.compare(VectorOperators.UNSIGNED_LT, 101).intoArray(ir, 0); + av.compare(VectorOperators.ULT, 101).intoArray(ir, 0); } @Run(test = "testIntUnsignedLTInRange") @@ -243,7 +243,7 @@ public static void testIntLTOutOfRange() { @IR(failOn = { IRNode.VMASK_CMPU_IMM_I_SVE }) public static void testIntUnsignedLTOutOfRange() { IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); - av.compare(VectorOperators.UNSIGNED_LT, -110).intoArray(ir, 0); + av.compare(VectorOperators.ULT, -110).intoArray(ir, 0); } @Test @@ -263,7 +263,7 @@ public static void testLongLEInRange_runner() { @IR(counts = { IRNode.VMASK_CMPU_IMM_L_SVE, ">= 1" }) public static void testLongUnsignedLEInRange() { LongVector av = LongVector.fromArray(L_SPECIES, la, 0); - av.compare(VectorOperators.UNSIGNED_LE, 95).intoArray(lr, 0); + av.compare(VectorOperators.ULE, 95).intoArray(lr, 0); } @Run(test = "testLongUnsignedLEInRange") @@ -283,7 +283,7 @@ public static void testLongLEOutOfRange() { @IR(failOn = { IRNode.VMASK_CMPU_IMM_L_SVE }) public static void testLongUnsignedLEOutOfRange() { LongVector av = LongVector.fromArray(L_SPECIES, la, 0); - av.compare(VectorOperators.UNSIGNED_LE, -99).intoArray(lr, 0); + av.compare(VectorOperators.ULE, -99).intoArray(lr, 0); } @Test diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java index 21ad4a524d26b..26e159fb768d0 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java @@ -240,14 +240,14 @@ public static void testDoubleVectorLessThanZero_runner() { @IR(failOn = { IRNode.VMASK_CMP_ZERO_I_NEON }) public static void testIntVectorUnsignedCondition() { IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); - av.compare(VectorOperators.UNSIGNED_GT, 0).intoArray(ir, 0); + av.compare(VectorOperators.UGT, 0).intoArray(ir, 0); } @Test @IR(failOn = { IRNode.VMASK_CMP_ZERO_L_NEON }) public static void testLongVectorUnsignedCondition() { LongVector av = LongVector.fromArray(L_SPECIES, la, 0); - av.compare(VectorOperators.UNSIGNED_GE, 0).intoArray(lr, 0); + av.compare(VectorOperators.UGE, 0).intoArray(lr, 0); } public static void main(String[] args) { @@ -257,4 +257,4 @@ public static void main(String[] args) { .addFlags("-XX:UseSVE=0") .start(); } -} \ No newline at end of file +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorRebracket128Test.java b/test/hotspot/jtreg/compiler/vectorapi/VectorRebracket128Test.java index 239f525640509..4f7f03590dda3 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorRebracket128Test.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorRebracket128Test.java @@ -35,23 +35,13 @@ import jdk.internal.vm.annotation.ForceInline; /* - * @test id=ZSinglegen + * @test id=Z * @bug 8260473 - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @modules jdk.incubator.vector * @modules java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:CompileCommand=compileonly,jdk/incubator/vector/ByteVector.fromMemorySegment - * -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:+UseZGC -XX:-ZGenerational -Xbatch -Xmx256m VectorRebracket128Test - */ - -/* - * @test id=ZGenerational - * @bug 8260473 - * @requires vm.gc.ZGenerational - * @modules jdk.incubator.vector - * @modules java.base/jdk.internal.vm.annotation - * @run testng/othervm -XX:CompileCommand=compileonly,jdk/incubator/vector/ByteVector.fromMemorySegment - * -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:+UseZGC -XX:+ZGenerational -Xbatch -Xmx256m VectorRebracket128Test + * -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:+UseZGC -Xbatch -Xmx256m VectorRebracket128Test */ @Test diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java index 384cc411d3eb8..a2ff267f937ae 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java @@ -25,7 +25,7 @@ * @test * @summary Test Float16 vector conversion chain. * @requires (vm.cpu.features ~= ".*avx512vl.*" | vm.cpu.features ~= ".*f16c.*") | os.arch == "aarch64" -* | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh.*") +* | (os.arch == "riscv64" & vm.cpu.features ~= ".*zvfh.*") * @library /test/lib / * @run driver compiler.vectorization.TestFloat16VectorConvChain */ @@ -40,7 +40,7 @@ public class TestFloat16VectorConvChain { @Test - @IR(applyIfCPUFeatureOr = {"f16c", "true", "avx512vl", "true"}, counts = {IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE_ANY, ">= 1", IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE_ANY, " >= 1"}) + @IR(applyIfCPUFeatureOr = {"f16c", "true", "avx512vl", "true", "zvfh", "true"}, counts = {IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE_ANY, ">= 1", IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE_ANY, " >= 1"}) public static void test(short [] res, short [] src1, short [] src2) { for (int i = 0; i < res.length; i++) { res[i] = (short)Float.float16ToFloat(Float.floatToFloat16(Float.float16ToFloat(src1[i]) + Float.float16ToFloat(src2[i]))); diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java index 96324c62c3249..2fd5364a78b17 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java @@ -26,9 +26,6 @@ * @bug 8294588 * @summary Auto-vectorize Float.floatToFloat16, Float.float16ToFloat APIs * @requires vm.compiler2.enabled - * @requires (os.simpleArch == "x64" & (vm.cpu.features ~= ".*avx512f.*" | vm.cpu.features ~= ".*f16c.*")) | - * os.arch == "aarch64" | - * (os.arch == "riscv64" & vm.cpu.features ~= ".*zvfh.*") * @library /test/lib / * @run driver compiler.vectorization.TestFloatConversionsVector */ @@ -53,7 +50,9 @@ public static void main(String args[]) { } @Test - @IR(counts = {IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"}) + @IR(counts = {IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"}, + applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, + applyIfCPUFeatureOr = {"f16c", "true", "avx512f", "true", "zvfh", "true", "asimd", "true", "sve", "true"}) public void test_float_float16(short[] sout, float[] finp) { for (int i = 0; i < finp.length; i++) { sout[i] = Float.floatToFloat16(finp[i]); @@ -67,7 +66,16 @@ public void test_float_float16_strided(short[] sout, float[] finp) { } } - @Run(test = {"test_float_float16", "test_float_float16_strided"}, mode = RunMode.STANDALONE) + @Test + public void test_float_float16_short_vector(short[] sout, float[] finp) { + for (int i = 0; i < finp.length; i+= 4) { + sout[i+0] = Float.floatToFloat16(finp[i+0]); + sout[i+1] = Float.floatToFloat16(finp[i+1]); + } + } + + @Run(test = {"test_float_float16", "test_float_float16_strided", + "test_float_float16_short_vector"}, mode = RunMode.STANDALONE) public void kernel_test_float_float16() { finp = new float[ARRLEN]; sout = new short[ARRLEN]; @@ -93,10 +101,21 @@ public void kernel_test_float_float16() { for (int i = 0; i < ARRLEN/2; i++) { Asserts.assertEquals(Float.floatToFloat16(finp[i*2]), sout[i*2]); } + + for (int i = 0; i < ITERS; i++) { + test_float_float16_short_vector(sout, finp); + } + + // Verifying the result + for (int i = 0; i < ARRLEN; i++) { + Asserts.assertEquals(Float.floatToFloat16(finp[i]), sout[i]); + } } @Test - @IR(counts = {IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"}) + @IR(counts = {IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"}, + applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, + applyIfCPUFeatureOr = {"f16c", "true", "avx512f", "true", "zvfh", "true", "asimd", "true", "sve", "true"}) public void test_float16_float(float[] fout, short[] sinp) { for (int i = 0; i < sinp.length; i++) { fout[i] = Float.float16ToFloat(sinp[i]); diff --git a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java index 357eb3db49727..9233b199532bf 100644 --- a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java +++ b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, 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,7 +25,7 @@ /* * @test * @summary Basic (sanity) test for JDK-under-test inside a docker image. - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java index 08493a7539805..43cd6ec515208 100644 --- a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java +++ b/test/hotspot/jtreg/containers/docker/ShareTmpDir.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 @@ -27,7 +27,7 @@ * @bug 8286030 * @key cgroups * @summary Test for hsperfdata file name conflict when two containers share the same /tmp directory - * @requires docker.support + * @requires container.support * @library /test/lib * @build WaitForFlagFile * @run driver ShareTmpDir diff --git a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java index a41dc9c39392b..c51bfa1abbb18 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.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 @@ -26,7 +26,7 @@ * @test * @key cgroups * @summary Test JVM's CPU resource awareness when running inside docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.base/jdk.internal.platform diff --git a/test/hotspot/jtreg/containers/docker/TestCPUSets.java b/test/hotspot/jtreg/containers/docker/TestCPUSets.java index de35388f5a843..aabe82e131fe9 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUSets.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUSets.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 @@ -26,7 +26,7 @@ * @test * @key cgroups * @summary Test JVM's awareness of cpu sets (cpus and mems) - * @requires docker.support + * @requires container.support * @requires (os.arch != "s390x") * @library /test/lib * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java index 6bcb706fa7a6a..5db3c2af09850 100644 --- a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java +++ b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java @@ -27,7 +27,7 @@ * @test * @summary Test container info for cgroup v2 * @key cgroups - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestJFREvents.java b/test/hotspot/jtreg/containers/docker/TestJFREvents.java index abc9de45db842..77c735cde00f1 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFREvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFREvents.java @@ -29,7 +29,7 @@ * when run inside Docker container, such as available CPU and memory. * Also make sure that PIDs are based on value provided by container, * not by the host system. - * @requires (docker.support & os.maxMemory >= 2g) + * @requires (container.support & os.maxMemory >= 2g) * @modules java.base/jdk.internal.platform * @library /test/lib * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java index 54ffff4e60ef3..9f9497d9c635f 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.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 @@ -27,7 +27,7 @@ * @summary Test JFR network related events inside a container; make sure * the reported host ip and host name are correctly reported within * the container. - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java b/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java index 61fad4f86be28..b751725428162 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java +++ b/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ /* * @test * @summary Test JFR recording controlled via JMX across container boundary. - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestJcmd.java b/test/hotspot/jtreg/containers/docker/TestJcmd.java index 60d4f4a9e5b46..ca8f1659fe9ef 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmd.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @test * @summary Test JCMD across container boundary. The JCMD runs on a host system, * while sending commands to a JVM that runs inside a container. - * @requires docker.support + * @requires container.support * @requires vm.flagless * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java index 2088398834702..de27f4d24e207 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -29,7 +29,7 @@ * and other uses. In side car pattern the main application/service container * is paired with a sidecar container by sharing certain aspects of container * namespace such as PID namespace, specific sub-directories, IPC and more. - * @requires docker.support + * @requires container.support * @requires vm.flagless * @modules java.base/jdk.internal.misc * java.management @@ -42,8 +42,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Paths; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; @@ -52,7 +52,9 @@ import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.Collectors; + import jdk.test.lib.Container; +import jdk.test.lib.Platform; import jdk.test.lib.Utils; import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; @@ -108,6 +110,11 @@ public static void main(String[] args) throws Exception { mainContainer.waitForMainMethodStart(TIME_TO_WAIT_FOR_MAIN_METHOD_START); for (AttachStrategy attachStrategy : EnumSet.allOf(AttachStrategy.class)) { + if (attachStrategy == AttachStrategy.ACCESS_TMP_VIA_PROC_ROOT && + elevated && !Platform.isRoot()) { + // Elevated attach via proc/root not yet supported. + continue; + } long mainProcPid = testCase01(attachStrategy, elevated); // Excluding the test case below until JDK-8228850 is fixed diff --git a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java index e15ab9b2b81fa..14227a7106804 100644 --- a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java +++ b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,7 +29,7 @@ * @bug 8308090 * @key cgroups * @summary Test container limits updating as they get updated at runtime without restart - * @requires docker.support + * @requires container.support * @library /test/lib * @build jdk.test.whitebox.WhiteBox LimitUpdateChecker * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java index 20354cf934d96..06a874e008ae5 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, 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 @@ -27,7 +27,7 @@ * @bug 8146115 8292083 * @key cgroups * @summary Test JVM's memory resource awareness when running inside docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.base/jdk.internal.platform diff --git a/test/hotspot/jtreg/containers/docker/TestMisc.java b/test/hotspot/jtreg/containers/docker/TestMisc.java index 5b7f96112b901..a811666999bdc 100644 --- a/test/hotspot/jtreg/containers/docker/TestMisc.java +++ b/test/hotspot/jtreg/containers/docker/TestMisc.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 @@ -25,7 +25,7 @@ /* * @test * @summary Test miscellanous functionality related to JVM running in docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestPids.java b/test/hotspot/jtreg/containers/docker/TestPids.java index 2b3b2594cfa93..9b65a1b1ee880 100644 --- a/test/hotspot/jtreg/containers/docker/TestPids.java +++ b/test/hotspot/jtreg/containers/docker/TestPids.java @@ -27,7 +27,7 @@ * @test * @key cgroups * @summary Test JVM's awareness of pids controller - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java b/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java index c282c2876eaee..9f6c915d1c00d 100644 --- a/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java +++ b/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java @@ -73,27 +73,15 @@ */ /** - * @test id=ZGenerational + * @test id=Z * @summary tests AlwaysPreTouch - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @requires os.maxMemory > 2G * @requires os.family != "aix" * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:+ZGenerational -Xmx512m -Xms512m -XX:+AlwaysPreTouch gc.TestAlwaysPreTouchBehavior - */ - -/** - * @test id=ZSinglegen - * @summary tests AlwaysPreTouch - * @requires vm.gc.ZSinglegen - * @requires os.maxMemory > 2G - * @requires os.family != "aix" - * @library /test/lib - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-ZGenerational -Xmx512m -Xms512m -XX:+AlwaysPreTouch gc.TestAlwaysPreTouchBehavior + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -Xmx512m -Xms512m -XX:+AlwaysPreTouch gc.TestAlwaysPreTouchBehavior */ /** diff --git a/test/hotspot/jtreg/gc/TestObjectAlignmentCardSize.java b/test/hotspot/jtreg/gc/TestObjectAlignmentCardSize.java new file mode 100644 index 0000000000000..5fb46a87b5104 --- /dev/null +++ b/test/hotspot/jtreg/gc/TestObjectAlignmentCardSize.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 gc; + +/* @test TestObjectAlignmentCardSize.java + * @summary Test to check correct handling of ObjectAlignmentInBytes and GCCardSizeInBytes combinations + * @requires vm.gc != "Z" + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver gc.TestObjectAlignmentCardSize + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestObjectAlignmentCardSize { + private static void runTest(int objectAlignment, int cardSize, boolean shouldSucceed) throws Exception { + OutputAnalyzer output = ProcessTools.executeTestJava( + "-XX:ObjectAlignmentInBytes=" + objectAlignment, + "-XX:GCCardSizeInBytes=" + cardSize, + "-Xmx32m", + "-Xms32m", + "-version"); + + System.out.println("Output:\n" + output.getOutput()); + + if (shouldSucceed) { + output.shouldHaveExitValue(0); + } else { + output.shouldContain("Invalid combination of GCCardSizeInBytes and ObjectAlignmentInBytes"); + output.shouldNotHaveExitValue(0); + } + } + + public static void main(String[] args) throws Exception { + runTest(8, 512, true); + runTest(128, 128, true); + runTest(256, 128, false); + runTest(256, 256, true); + runTest(256, 512, true); + } +} diff --git a/test/hotspot/jtreg/gc/TestReferenceClearDuringReferenceProcessing.java b/test/hotspot/jtreg/gc/TestReferenceClearDuringReferenceProcessing.java index f66387b4cd70d..3be7ba241e77d 100644 --- a/test/hotspot/jtreg/gc/TestReferenceClearDuringReferenceProcessing.java +++ b/test/hotspot/jtreg/gc/TestReferenceClearDuringReferenceProcessing.java @@ -36,27 +36,15 @@ * gc.TestReferenceClearDuringReferenceProcessing */ -/* @test id=ZSinglegen +/* @test id=Z * @bug 8256517 - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm * -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-ZGenerational - * gc.TestReferenceClearDuringReferenceProcessing - */ - -/* @test id=ZGenerational - * @bug 8256517 - * @requires vm.gc.ZGenerational - * @library /test/lib - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm - * -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:+ZGenerational + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC * gc.TestReferenceClearDuringReferenceProcessing */ diff --git a/test/hotspot/jtreg/gc/TestSystemGC.java b/test/hotspot/jtreg/gc/TestSystemGC.java index c81b98a562f8c..6d37dc3d44b0a 100644 --- a/test/hotspot/jtreg/gc/TestSystemGC.java +++ b/test/hotspot/jtreg/gc/TestSystemGC.java @@ -58,21 +58,12 @@ */ /* - * @test id=ZSinglegen - * @requires vm.gc.ZSinglegen + * @test id=Z + * @requires vm.gc.Z * @comment ZGC will not start when LargePages cannot be allocated, therefore * we do not run such configuration. * @summary Runs System.gc() with different flags. - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational gc.TestSystemGC - */ - -/* - * @test id=ZGenerational - * @requires vm.gc.ZGenerational - * @comment ZGC will not start when LargePages cannot be allocated, therefore - * we do not run such configuration. - * @summary Runs System.gc() with different flags. - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational gc.TestSystemGC + * @run main/othervm -XX:+UseZGC gc.TestSystemGC */ public class TestSystemGC { diff --git a/test/hotspot/jtreg/gc/TestVerifySubSet.java b/test/hotspot/jtreg/gc/TestVerifySubSet.java index 08cddc74a00be..3dc28549b56cf 100644 --- a/test/hotspot/jtreg/gc/TestVerifySubSet.java +++ b/test/hotspot/jtreg/gc/TestVerifySubSet.java @@ -26,9 +26,9 @@ /* @test TestVerifySubSet.java * @bug 8072725 * @summary Test VerifySubSet option - * @comment Generational ZGC can't use the generic Universe::verify - * because there's no guarantee that we will ever have - * a stable snapshot where all roots can be verified. + * @comment ZGC can't use the generic Universe::verify because + * there's no guarantee that we will ever have a stable + * snapshot where all roots can be verified. * @requires vm.gc != "Z" * @library /test/lib * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java index 24e542881c0c3..4b69421e6e336 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java @@ -29,6 +29,7 @@ * @summary Tests argument processing for initial and maximum heap size for the G1 collector * @key flag-sensitive * @requires vm.gc.G1 & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null + * @requires vm.compMode != "Xcomp" * @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 544064953dfb2..ca8d1e74895b3 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java @@ -30,6 +30,7 @@ * parallel collectors. * @key flag-sensitive * @requires vm.gc.Parallel & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null + * @requires vm.compMode != "Xcomp" * @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 c580245a2a39e..b9cc0f231f2e6 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java @@ -29,6 +29,7 @@ * @summary Tests argument processing for initial and maximum heap size for the Serial collector * @key flag-sensitive * @requires vm.gc.Serial & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null + * @requires vm.compMode != "Xcomp" * @library /test/lib * @library / * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java b/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java index 2a6e3a1bfd045..bd5b6e28aa810 100644 --- a/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java +++ b/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java @@ -33,11 +33,11 @@ * @summary completely in JNI CS, while other is trying to allocate memory * @summary provoking GC. OOM means FAIL, deadlock means PASS. * - * @comment This test assumes that no allocation happens during the sleep loop, \ - * which is something that we can't guarantee. With Generational ZGC we \ - * see test timeouts because the main thread allocates and waits for the \ - * GC, which waits for the CSLocker, which waits for the main thread. \ - * @requires !vm.opt.final.ZGenerational + * @comment This test assumes that no allocation happens during the sleep loop, + * which is something that we can't guarantee. With ZGC we see test + * timeouts because the main thread allocates and waits for the GC, + * which waits for the CSLocker, which waits for the main thread. + * @requires vm.gc != "Z" * * @run main/native/othervm -Xmx256m gc.cslocker.TestCSLocker */ diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestLoadBypassesNullCheck.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestLoadBypassesNullCheck.java new file mode 100644 index 0000000000000..c93e8cc13d0dc --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestLoadBypassesNullCheck.java @@ -0,0 +1,73 @@ +/* + * 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 8342496 + * @summary C2/Shenandoah: SEGV in compiled code when running jcstress + * @requires vm.flavor == "server" + * @requires vm.gc.Shenandoah + * + * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation + * -XX:+UseShenandoahGC -XX:LoopMaxUnroll=0 + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+StressLCM -XX:StressSeed=270847015 + * TestLoadBypassesNullCheck + * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation + * -XX:+UseShenandoahGC -XX:LoopMaxUnroll=0 + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+StressLCM + * TestLoadBypassesNullCheck + * + */ + +public class TestLoadBypassesNullCheck { + private static A fieldA = new A(); + private static Object fieldO = new Object(); + private static volatile int volatileField; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test1(); + } + fieldA = null; + try { + test1(); + } catch (NullPointerException npe) { + } + } + + private static boolean test1() { + for (int i = 0; i < 1000; i++) { + volatileField = 42; + A a = fieldA; + Object o = a.fieldO; + if (o == fieldO) { + return true; + } + } + return false; + } + + private static class A { + public Object fieldO; + } +} diff --git a/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java b/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java index 1a3d07bf80d06..00e32a4136e68 100644 --- a/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java +++ b/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java @@ -27,7 +27,7 @@ * @summary Test OOME in due to classloader leak * @requires vm.gc.Shenandoah * @library /test/lib - * @run driver TestClassLoaderLeak + * @run driver/timeout=600 TestClassLoaderLeak */ import java.util.*; diff --git a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithZ.java b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithZ.java index dd54556697dd4..fb58d5784d44c 100644 --- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithZ.java +++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithZ.java @@ -27,47 +27,27 @@ import java.io.IOException; /* - * @test TestGCBasherWithZGenerational + * @test TestGCBasherWithZ * @key stress * @library / - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Stress ZGC - * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx384m -server -XX:+UseZGC -XX:+ZGenerational gc.stress.gcbasher.TestGCBasherWithZ 120000 - */ -/* - * @test TestGCBasherWithZSinglegen - * @key stress - * @library / - * @requires vm.gc.ZSinglegen - * @requires vm.flavor == "server" & !vm.emulatedClient - * @summary Stress ZGC - * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx384m -server -XX:+UseZGC -XX:-ZGenerational gc.stress.gcbasher.TestGCBasherWithZ 120000 + * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx384m -server -XX:+UseZGC gc.stress.gcbasher.TestGCBasherWithZ 120000 */ /* - * @test TestGCBasherDeoptWithZGenerational + * @test TestGCBasherDeoptWithZ * @key stress * @library / - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @requires vm.flavor == "server" & !vm.emulatedClient & vm.opt.ClassUnloading != false * @summary Stress ZGC with nmethod barrier forced deoptimization enabled. - * @run main/othervm/timeout=200 -Xlog:gc*=info,nmethod+barrier=trace -Xmx384m -server -XX:+UseZGC -XX:+ZGenerational + * @run main/othervm/timeout=200 -Xlog:gc*=info,nmethod+barrier=trace -Xmx384m -server -XX:+UseZGC * -XX:+UnlockDiagnosticVMOptions -XX:+DeoptimizeNMethodBarriersALot -XX:-Inline * gc.stress.gcbasher.TestGCBasherWithZ 120000 */ -/* - * @test TestGCBasherDeoptWithZSinglegen - * @key stress - * @library / - * @requires vm.gc.ZSinglegen - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.opt.ClassUnloading != false - * @summary Stress ZGC with nmethod barrier forced deoptimization enabled. - * @run main/othervm/timeout=200 -Xlog:gc*=info,nmethod+barrier=trace -Xmx384m -server -XX:+UseZGC -XX:-ZGenerational - * -XX:+UnlockDiagnosticVMOptions -XX:+DeoptimizeNMethodBarriersALot -XX:-Inline - * gc.stress.gcbasher.TestGCBasherWithZ 120000 - */ public class TestGCBasherWithZ { public static void main(String[] args) throws IOException { TestGCBasher.main(args); diff --git a/test/hotspot/jtreg/gc/stress/gcold/TestGCOldWithZ.java b/test/hotspot/jtreg/gc/stress/gcold/TestGCOldWithZ.java index 0f77a6c286ab3..0741cf1fba310 100644 --- a/test/hotspot/jtreg/gc/stress/gcold/TestGCOldWithZ.java +++ b/test/hotspot/jtreg/gc/stress/gcold/TestGCOldWithZ.java @@ -25,24 +25,15 @@ package gc.stress.gcold; /* - * @test TestGCOldWithZGenerational + * @test TestGCOldWithZ * @key randomness * @library / /test/lib - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @summary Stress the Z - * @run main/othervm -Xmx384M -XX:+UseZGC -XX:+ZGenerational gc.stress.gcold.TestGCOldWithZ 50 1 20 10 10000 - * @run main/othervm -Xmx256m -XX:+UseZGC -XX:+ZGenerational gc.stress.gcold.TestGCOldWithZ 50 5 20 1 5000 + * @run main/othervm -Xmx384M -XX:+UseZGC gc.stress.gcold.TestGCOldWithZ 50 1 20 10 10000 + * @run main/othervm -Xmx256m -XX:+UseZGC gc.stress.gcold.TestGCOldWithZ 50 5 20 1 5000 */ -/* - * @test TestGCOldWithZSinglegen - * @key randomness - * @library / /test/lib - * @requires vm.gc.ZSinglegen - * @summary Stress the Z - * @run main/othervm -Xmx384M -XX:+UseZGC -XX:-ZGenerational gc.stress.gcold.TestGCOldWithZ 50 1 20 10 10000 - * @run main/othervm -Xmx256m -XX:+UseZGC -XX:-ZGenerational gc.stress.gcold.TestGCOldWithZ 50 5 20 1 5000 - */ public class TestGCOldWithZ { public static void main(String[] args) { TestGCOld.main(args); diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationAgeThreshold.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationAgeThreshold.java index e70d63cf39718..090a49aa80b2f 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationAgeThreshold.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationAgeThreshold.java @@ -76,29 +76,16 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @summary Test string deduplication age threshold * @bug 8029075 - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @library /test/lib * @library / * @modules java.base/jdk.internal.misc:open * @modules java.base/java.lang:open * java.management - * @run driver gc.stringdedup.TestStringDeduplicationAgeThreshold Z -XX:-ZGenerational - */ - -/* - * @test id=ZGenerational - * @summary Test string deduplication age threshold - * @bug 8029075 - * @requires vm.gc.ZGenerational - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc:open - * @modules java.base/java.lang:open - * java.management - * @run driver gc.stringdedup.TestStringDeduplicationAgeThreshold Z -XX:+ZGenerational + * @run driver gc.stringdedup.TestStringDeduplicationAgeThreshold Z */ public class TestStringDeduplicationAgeThreshold { diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationFullGC.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationFullGC.java index 03793f03b1bc1..7105be7d47830 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationFullGC.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationFullGC.java @@ -76,29 +76,16 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @summary Test string deduplication during full GC * @bug 8029075 - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @library /test/lib * @library / * @modules java.base/jdk.internal.misc:open * @modules java.base/java.lang:open * java.management - * @run driver gc.stringdedup.TestStringDeduplicationFullGC Z -XX:-ZGenerational - */ - -/* - * @test id=ZGenerational - * @summary Test string deduplication during full GC - * @bug 8029075 - * @requires vm.gc.ZGenerational - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc:open - * @modules java.base/java.lang:open - * java.management - * @run driver gc.stringdedup.TestStringDeduplicationFullGC Z -XX:+ZGenerational + * @run driver gc.stringdedup.TestStringDeduplicationFullGC Z */ public class TestStringDeduplicationFullGC { diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationInterned.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationInterned.java index 0981be49aecb4..124bf9d5cf94b 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationInterned.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationInterned.java @@ -76,29 +76,16 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @summary Test string deduplication of interned strings * @bug 8029075 - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @library /test/lib * @library / * @modules java.base/jdk.internal.misc:open * @modules java.base/java.lang:open * java.management - * @run driver gc.stringdedup.TestStringDeduplicationInterned Z -XX:-ZGenerational - */ - -/* - * @test id=ZGenerational - * @summary Test string deduplication of interned strings - * @bug 8029075 - * @requires vm.gc.ZGenerational - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc:open - * @modules java.base/java.lang:open - * java.management - * @run driver gc.stringdedup.TestStringDeduplicationInterned Z -XX:+ZGenerational + * @run driver gc.stringdedup.TestStringDeduplicationInterned Z */ public class TestStringDeduplicationInterned { diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationPrintOptions.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationPrintOptions.java index 265cb1b9dd378..0659bc5aea378 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationPrintOptions.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationPrintOptions.java @@ -76,29 +76,16 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @summary Test string deduplication print options * @bug 8029075 - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @library /test/lib * @library / * @modules java.base/jdk.internal.misc:open * @modules java.base/java.lang:open * java.management - * @run driver gc.stringdedup.TestStringDeduplicationPrintOptions Z -XX:-ZGenerational - */ - -/* - * @test id=ZGenerational - * @summary Test string deduplication print options - * @bug 8029075 - * @requires vm.gc.ZGenerational - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc:open - * @modules java.base/java.lang:open - * java.management - * @run driver gc.stringdedup.TestStringDeduplicationPrintOptions Z -XX:+ZGenerational + * @run driver gc.stringdedup.TestStringDeduplicationPrintOptions Z */ public class TestStringDeduplicationPrintOptions { diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTableResize.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTableResize.java index 2c16e9c4c4a65..d82244ef07a18 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTableResize.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTableResize.java @@ -76,29 +76,16 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @summary Test string deduplication table resize * @bug 8029075 - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @library /test/lib * @library / * @modules java.base/jdk.internal.misc:open * @modules java.base/java.lang:open * java.management - * @run driver gc.stringdedup.TestStringDeduplicationTableResize Z -XX:-ZGenerational - */ - -/* - * @test id=ZGenerational - * @summary Test string deduplication table resize - * @bug 8029075 - * @requires vm.gc.ZGenerational - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc:open - * @modules java.base/java.lang:open - * java.management - * @run driver gc.stringdedup.TestStringDeduplicationTableResize Z -XX:+ZGenerational + * @run driver gc.stringdedup.TestStringDeduplicationTableResize Z */ public class TestStringDeduplicationTableResize { diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java index 2a6652eb06ef4..3dbedd61d124f 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java @@ -57,7 +57,6 @@ class TestStringDeduplicationTools { private static byte[] dummy; private static String selectedGC = null; - private static String selectedGCMode = null; static { try { @@ -74,9 +73,6 @@ class TestStringDeduplicationTools { public static void selectGC(String[] args) { selectedGC = args[0]; - if (args.length > 1) { - selectedGCMode = args[1]; - } } private static Object getValue(String string) { @@ -137,16 +133,10 @@ public void handleNotification(Notification n, Object o) { gcCount++; } } else if (info.getGcName().startsWith("ZGC")) { - // Generational ZGC only triggers string deduplications from major collections + // ZGC only triggers string deduplications from major collections if (info.getGcName().startsWith("ZGC Major") && "end of GC cycle".equals(info.getGcAction())) { gcCount++; } - - // Single-gen ZGC - if (!info.getGcName().startsWith("ZGC Major") && !info.getGcName().startsWith("ZGC Minor") && - "end of GC cycle".equals(info.getGcAction())) { - gcCount++; - } } else if (info.getGcName().startsWith("G1")) { if ("end of minor GC".equals(info.getGcAction())) { gcCount++; @@ -325,9 +315,6 @@ private static OutputAnalyzer runTest(String... extraArgs) throws Exception { ArrayList args = new ArrayList(); args.add("-XX:+Use" + selectedGC + "GC"); - if (selectedGCMode != null) { - args.add(selectedGCMode); - } args.addAll(Arrays.asList(defaultArgs)); args.addAll(Arrays.asList(extraArgs)); diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationYoungGC.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationYoungGC.java index d8787cc70bac2..053dc0a28621a 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationYoungGC.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationYoungGC.java @@ -76,29 +76,16 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @summary Test string deduplication during young GC * @bug 8029075 - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @library /test/lib * @library / * @modules java.base/jdk.internal.misc:open * @modules java.base/java.lang:open * java.management - * @run driver gc.stringdedup.TestStringDeduplicationYoungGC Z -XX:-ZGenerational - */ - -/* - * @test id=ZGenerational - * @summary Test string deduplication during young GC - * @bug 8029075 - * @requires vm.gc.ZGenerational - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc:open - * @modules java.base/java.lang:open - * java.management - * @run driver gc.stringdedup.TestStringDeduplicationYoungGC Z -XX:+ZGenerational + * @run driver gc.stringdedup.TestStringDeduplicationYoungGC Z */ public class TestStringDeduplicationYoungGC { diff --git a/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java b/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java deleted file mode 100644 index 6a9768de7e6e2..0000000000000 --- a/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 - * 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 gc.x; - -/* - * @test TestAllocateHeapAt - * @requires vm.gc.ZSinglegen & os.family == "linux" - * @requires !vm.opt.final.UseLargePages - * @summary Test ZGC with -XX:AllocateHeapAt - * @library /test/lib - * @run main/othervm gc.x.TestAllocateHeapAt . true - * @run main/othervm gc.x.TestAllocateHeapAt non-existing-directory false - */ - -import jdk.test.lib.process.ProcessTools; - -public class TestAllocateHeapAt { - public static void main(String[] args) throws Exception { - final String directory = args[0]; - final boolean exists = Boolean.parseBoolean(args[1]); - final String heapBackingFile = "Heap Backing File: " + directory; - final String failedToCreateFile = "Failed to create file " + directory; - - ProcessTools.executeTestJava( - "-XX:+UseZGC", - "-XX:-ZGenerational", - "-Xlog:gc*", - "-Xms32M", - "-Xmx32M", - "-XX:AllocateHeapAt=" + directory, - "-version") - .shouldContain(exists ? heapBackingFile : failedToCreateFile) - .shouldNotContain(exists ? failedToCreateFile : heapBackingFile) - .shouldHaveExitValue(exists ? 0 : 1); - } -} diff --git a/test/hotspot/jtreg/gc/x/TestGarbageCollectorMXBean.java b/test/hotspot/jtreg/gc/x/TestGarbageCollectorMXBean.java deleted file mode 100644 index 193b93ee2d051..0000000000000 --- a/test/hotspot/jtreg/gc/x/TestGarbageCollectorMXBean.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 gc.x; - -/** - * @test TestGarbageCollectorMXBean - * @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 - */ - -import java.lang.management.ManagementFactory; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import javax.management.Notification; -import javax.management.NotificationEmitter; -import javax.management.NotificationListener; -import javax.management.openmbean.CompositeData; - -import com.sun.management.GarbageCollectionNotificationInfo; - -public class TestGarbageCollectorMXBean { - private static final long startTime = System.nanoTime(); - - private static void log(String msg) { - final String elapsedSeconds = String.format("%.3fs", (System.nanoTime() - startTime) / 1_000_000_000.0); - System.out.println("[" + elapsedSeconds + "] (" + Thread.currentThread().getName() + ") " + msg); - } - - public static void main(String[] args) throws Exception { - final long M = 1024 * 1024; - final long initialCapacity = Long.parseLong(args[0]) * M; - final long maxCapacity = Long.parseLong(args[1]) * M; - final AtomicInteger cycles = new AtomicInteger(); - final AtomicInteger pauses = new AtomicInteger(); - final AtomicInteger errors = new AtomicInteger(); - - final NotificationListener listener = (Notification notification, Object ignored) -> { - final var type = notification.getType(); - if (!type.equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { - // Ignore - return; - } - - final var data = (CompositeData)notification.getUserData(); - final var info = GarbageCollectionNotificationInfo.from(data); - final var name = info.getGcName(); - final var id = info.getGcInfo().getId(); - final var action = info.getGcAction(); - final var cause = info.getGcCause(); - final var startTime = info.getGcInfo().getStartTime(); - final var endTime = info.getGcInfo().getEndTime(); - final var duration = info.getGcInfo().getDuration(); - final var memoryUsageBeforeGC = info.getGcInfo().getMemoryUsageBeforeGc().get("ZHeap"); - final var memoryUsageAfterGC = info.getGcInfo().getMemoryUsageAfterGc().get("ZHeap"); - - log(name + " (" + type + ")"); - log(" Id: " + id); - log(" Action: " + action); - log(" Cause: " + cause); - log(" StartTime: " + startTime); - log(" EndTime: " + endTime); - log(" Duration: " + duration); - log(" MemoryUsageBeforeGC: " + memoryUsageBeforeGC); - log(" MemoryUsageAfterGC: " + memoryUsageAfterGC); - log(""); - - if (name.equals("ZGC Cycles")) { - cycles.incrementAndGet(); - - if (!action.equals("end of GC cycle")) { - log("ERROR: Action"); - errors.incrementAndGet(); - } - - if (memoryUsageBeforeGC.getInit() != initialCapacity) { - log("ERROR: MemoryUsageBeforeGC.init"); - errors.incrementAndGet(); - } - - if (memoryUsageBeforeGC.getUsed() > initialCapacity) { - log("ERROR: MemoryUsageBeforeGC.used"); - errors.incrementAndGet(); - } - - if (memoryUsageBeforeGC.getCommitted() != initialCapacity) { - log("ERROR: MemoryUsageBeforeGC.committed"); - errors.incrementAndGet(); - } - - if (memoryUsageBeforeGC.getMax() != maxCapacity) { - log("ERROR: MemoryUsageBeforeGC.max"); - errors.incrementAndGet(); - } - } else if (name.equals("ZGC Pauses")) { - pauses.incrementAndGet(); - - if (!action.equals("end of GC pause")) { - log("ERROR: Action"); - errors.incrementAndGet(); - } - - if (memoryUsageBeforeGC.getInit() != 0) { - log("ERROR: MemoryUsageBeforeGC.init"); - errors.incrementAndGet(); - } - - if (memoryUsageBeforeGC.getUsed() != 0) { - log("ERROR: MemoryUsageBeforeGC.used"); - errors.incrementAndGet(); - } - - if (memoryUsageBeforeGC.getCommitted() != 0) { - log("ERROR: MemoryUsageBeforeGC.committed"); - errors.incrementAndGet(); - } - - if (memoryUsageBeforeGC.getMax() != 0) { - log("ERROR: MemoryUsageBeforeGC.max"); - errors.incrementAndGet(); - } - } else { - log("ERROR: Name"); - errors.incrementAndGet(); - } - - if (!cause.equals("System.gc()")) { - log("ERROR: Cause"); - errors.incrementAndGet(); - } - - if (startTime > endTime) { - log("ERROR: StartTime"); - errors.incrementAndGet(); - } - - if (endTime - startTime != duration) { - log("ERROR: Duration"); - errors.incrementAndGet(); - } - }; - - // Collect garbage created at startup - System.gc(); - - // Register GC event listener - for (final var collector : ManagementFactory.getGarbageCollectorMXBeans()) { - final NotificationEmitter emitter = (NotificationEmitter)collector; - emitter.addNotificationListener(listener, null, null); - } - - final int minCycles = 5; - final int minPauses = minCycles * 3; - - // Run GCs - for (int i = 0; i < minCycles; i++) { - log("Starting GC " + i); - System.gc(); - } - - // Wait at most 90 seconds - for (int i = 0; i < 90; i++) { - log("Waiting..."); - Thread.sleep(1000); - - if (cycles.get() >= minCycles) { - log("All events received!"); - break; - } - } - - final int actualCycles = cycles.get(); - final int actualPauses = pauses.get(); - final int actualErrors = errors.get(); - - log(" minCycles: " + minCycles); - log(" minPauses: " + minPauses); - log("actualCycles: " + actualCycles); - log("actualPauses: " + actualPauses); - log("actualErrors: " + actualErrors); - - // Verify number of cycle events - if (actualCycles < minCycles) { - throw new Exception("Unexpected cycles"); - } - - // Verify number of pause events - if (actualPauses < minPauses) { - throw new Exception("Unexpected pauses"); - } - - // Verify number of errors - if (actualErrors != 0) { - throw new Exception("Unexpected errors"); - } - } -} diff --git a/test/hotspot/jtreg/gc/x/TestHighUsage.java b/test/hotspot/jtreg/gc/x/TestHighUsage.java deleted file mode 100644 index 32b0af19e4b79..0000000000000 --- a/test/hotspot/jtreg/gc/x/TestHighUsage.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2019, 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 gc.x; - -/* - * @test TestHighUsage - * @requires vm.gc.ZSinglegen - * @summary Test ZGC "High Usage" rule - * @library /test/lib - * @run main/othervm gc.x.TestHighUsage - */ - -import java.util.LinkedList; -import jdk.test.lib.process.ProcessTools; - -public class TestHighUsage { - static class Test { - private static final int K = 1024; - private static final int M = K * K; - private static final long maxCapacity = Runtime.getRuntime().maxMemory(); - private static final long slowAllocationThreshold = 16 * M; - private static final long highUsageThreshold = maxCapacity / 20; // 5% - private static volatile LinkedList keepAlive; - private static volatile Object dummy; - - public static void main(String[] args) throws Exception { - System.out.println("Max capacity: " + (maxCapacity / M) + "M"); - System.out.println("High usage threshold: " + (highUsageThreshold / M) + "M"); - System.out.println("Allocating live-set"); - - // Allocate live-set - keepAlive = new LinkedList<>(); - while (Runtime.getRuntime().freeMemory() > slowAllocationThreshold) { - while (Runtime.getRuntime().freeMemory() > slowAllocationThreshold) { - keepAlive.add(new byte[128 * K]); - } - - // Compact live-set and let allocation rate settle down - System.gc(); - Thread.sleep(2000); - } - - System.out.println("Allocating garbage slowly"); - - // Allocate garbage slowly, so that the sampled allocation rate on average - // becomes zero MB/s for the last 1 second windows. Once we reach the high - // usage threshold we idle to allow for a "High Usage" GC cycle to happen. - // We need to allocate slowly to avoid an "Allocation Rate" GC cycle. - for (int i = 0; i < 300; i++) { - if (Runtime.getRuntime().freeMemory() > highUsageThreshold) { - // Allocate - dummy = new byte[128 * K]; - System.out.println("Free: " + (Runtime.getRuntime().freeMemory() / M) + "M (Allocating)"); - } else { - // Idle - System.out.println("Free: " + (Runtime.getRuntime().freeMemory() / M) + "M (Idling)"); - } - - Thread.sleep(250); - } - - System.out.println("Done"); - } - } - - public static void main(String[] args) throws Exception { - ProcessTools.executeTestJava("-XX:+UseZGC", - "-XX:-ZGenerational", - "-XX:-ZProactive", - "-Xms128M", - "-Xmx128M", - "-XX:ParallelGCThreads=1", - "-XX:ConcGCThreads=1", - "-Xlog:gc,gc+start", - Test.class.getName()) - .shouldNotContain("Allocation Stall") - .shouldContain("High Usage") - .shouldHaveExitValue(0); - } -} diff --git a/test/hotspot/jtreg/gc/x/TestMemoryMXBean.java b/test/hotspot/jtreg/gc/x/TestMemoryMXBean.java deleted file mode 100644 index fad1febe15807..0000000000000 --- a/test/hotspot/jtreg/gc/x/TestMemoryMXBean.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 gc.x; - -/** - * @test TestMemoryMXBean - * @requires vm.gc.ZSinglegen - * @summary Test ZGC heap memory MXBean - * @modules java.management - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xms128M -Xmx256M -Xlog:gc* gc.x.TestMemoryMXBean 128 256 - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xms256M -Xmx256M -Xlog:gc* gc.x.TestMemoryMXBean 256 256 - */ - -import java.lang.management.ManagementFactory; - -public class TestMemoryMXBean { - public static void main(String[] args) throws Exception { - final long M = 1024 * 1024; - final long expectedInitialCapacity = Long.parseLong(args[0]) * M; - final long expectedMaxCapacity = Long.parseLong(args[1]) * M; - final var memoryUsage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); - final long initialCapacity = memoryUsage.getInit(); - final long capacity = memoryUsage.getCommitted(); - final long maxCapacity = memoryUsage.getMax(); - - System.out.println("expectedInitialCapacity: " + expectedInitialCapacity); - System.out.println(" expectedMaxCapacity: " + expectedMaxCapacity); - System.out.println(" initialCapacity: " + initialCapacity); - System.out.println(" capacity: " + capacity); - System.out.println(" maxCapacity: " + maxCapacity); - - if (initialCapacity != expectedInitialCapacity) { - throw new Exception("Unexpected initial capacity"); - } - - if (maxCapacity != expectedMaxCapacity) { - throw new Exception("Unexpected max capacity"); - } - - if (capacity < initialCapacity || capacity > maxCapacity) { - throw new Exception("Unexpected capacity"); - } - } -} diff --git a/test/hotspot/jtreg/gc/x/TestMemoryManagerMXBean.java b/test/hotspot/jtreg/gc/x/TestMemoryManagerMXBean.java deleted file mode 100644 index 70ce6c23b2ee9..0000000000000 --- a/test/hotspot/jtreg/gc/x/TestMemoryManagerMXBean.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 gc.x; - -/** - * @test TestMemoryManagerMXBean - * @requires vm.gc.ZSinglegen - * @summary Test ZGC memory manager MXBean - * @modules java.management - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xmx128M gc.x.TestMemoryManagerMXBean - */ - -import java.lang.management.ManagementFactory; - -public class TestMemoryManagerMXBean { - private static void checkName(String name) throws Exception { - if (name == null || name.length() == 0) { - throw new Exception("Invalid name"); - } - } - - public static void main(String[] args) throws Exception { - int zgcCyclesMemoryManagers = 0; - int zgcPausesMemoryManagers = 0; - int zgcCyclesMemoryPools = 0; - int zgcPausesMemoryPools = 0; - - for (final var memoryManager : ManagementFactory.getMemoryManagerMXBeans()) { - final var memoryManagerName = memoryManager.getName(); - checkName(memoryManagerName); - - System.out.println("MemoryManager: " + memoryManagerName); - - if (memoryManagerName.equals("ZGC Cycles")) { - zgcCyclesMemoryManagers++; - } else if (memoryManagerName.equals("ZGC Pauses")) { - zgcPausesMemoryManagers++; - } - - for (final var memoryPoolName : memoryManager.getMemoryPoolNames()) { - checkName(memoryPoolName); - - System.out.println(" MemoryPool: " + memoryPoolName); - - if (memoryPoolName.equals("ZHeap")) { - if (memoryManagerName.equals("ZGC Cycles")) { - zgcCyclesMemoryPools++; - } else if (memoryManagerName.equals("ZGC Pauses")) { - zgcPausesMemoryPools++; - } - } - } - } - - if (zgcCyclesMemoryManagers != 1) { - throw new Exception("Unexpected number of cycle MemoryManagers"); - } - - if (zgcPausesMemoryManagers != 1) { - throw new Exception("Unexpected number of pause MemoryManagers"); - } - - if (zgcCyclesMemoryPools != 1) { - throw new Exception("Unexpected number of cycle MemoryPools"); - } - - if (zgcPausesMemoryPools != 1) { - throw new Exception("Unexpected number of pause MemoryPools"); - } - } -} diff --git a/test/hotspot/jtreg/gc/x/TestNoUncommit.java b/test/hotspot/jtreg/gc/x/TestNoUncommit.java deleted file mode 100644 index be5aa950509a9..0000000000000 --- a/test/hotspot/jtreg/gc/x/TestNoUncommit.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package gc.x; - -/* - * @test TestNoUncommit - * @requires vm.gc.ZSinglegen & !vm.graal.enabled - * @summary Test ZGC uncommit unused memory disabled - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms512M -Xmx512M -XX:ZUncommitDelay=1 gc.x.TestNoUncommit - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=1 -XX:-ZUncommit gc.x.TestNoUncommit - */ - -public class TestNoUncommit { - private static final int allocSize = 200 * 1024 * 1024; // 200M - private static volatile Object keepAlive = null; - - private static long capacity() { - return Runtime.getRuntime().totalMemory(); - } - - public static void main(String[] args) throws Exception { - System.out.println("Allocating"); - keepAlive = new byte[allocSize]; - final var afterAlloc = capacity(); - - System.out.println("Reclaiming"); - keepAlive = null; - System.gc(); - - // Wait longer than the uncommit delay (which is 1 second) - Thread.sleep(5 * 1000); - - final var afterDelay = capacity(); - - // Verify - if (afterAlloc > afterDelay) { - throw new Exception("Should not uncommit"); - } - - System.out.println("Success"); - } -} diff --git a/test/hotspot/jtreg/gc/x/TestPageCacheFlush.java b/test/hotspot/jtreg/gc/x/TestPageCacheFlush.java deleted file mode 100644 index a48b6f77e17ef..0000000000000 --- a/test/hotspot/jtreg/gc/x/TestPageCacheFlush.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2020, 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 gc.x; - -/* - * @test TestPageCacheFlush - * @requires vm.gc.ZSinglegen - * @summary Test ZGC page cache flushing - * @library /test/lib - * @run driver gc.x.TestPageCacheFlush - */ - -import java.util.LinkedList; -import jdk.test.lib.process.ProcessTools; - -public class TestPageCacheFlush { - static class Test { - private static final int K = 1024; - private static final int M = K * K; - private static volatile LinkedList keepAlive; - - public static void fillPageCache(int size) { - System.out.println("Begin allocate (" + size + ")"); - - keepAlive = new LinkedList<>(); - - try { - for (;;) { - keepAlive.add(new byte[size]); - } - } catch (OutOfMemoryError e) { - keepAlive = null; - System.gc(); - } - - System.out.println("End allocate (" + size + ")"); - } - - public static void main(String[] args) throws Exception { - // Allocate small objects to fill the page cache with small pages - fillPageCache(10 * K); - - // Allocate large objects to provoke page cache flushing to rebuild - // cached small pages into large pages - fillPageCache(10 * M); - } - } - - public static void main(String[] args) throws Exception { - ProcessTools.executeTestJava( - "-XX:+UseZGC", - "-XX:-ZGenerational", - "-Xms128M", - "-Xmx128M", - "-Xlog:gc,gc+init,gc+heap=debug", - Test.class.getName()) - .outputTo(System.out) - .errorTo(System.out) - .shouldContain("Page Cache Flushed:") - .shouldHaveExitValue(0); - } -} diff --git a/test/hotspot/jtreg/gc/x/TestRelocateInPlace.java b/test/hotspot/jtreg/gc/x/TestRelocateInPlace.java deleted file mode 100644 index dba08b23a5d34..0000000000000 --- a/test/hotspot/jtreg/gc/x/TestRelocateInPlace.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package gc.x; - -/* - * @test TestRelocateInPlace - * @requires vm.gc.ZSinglegen - * @summary Test ZGC in-place relocateion - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xlog:gc*,gc+stats=off -Xmx256M -XX:+UnlockDiagnosticVMOptions -XX:+ZStressRelocateInPlace gc.x.TestRelocateInPlace - */ - -import java.util.ArrayList; - -public class TestRelocateInPlace { - private static final int allocSize = 100 * 1024 * 1024; // 100M - private static final int smallObjectSize = 4 * 1024; // 4K - private static final int mediumObjectSize = 2 * 1024 * 1024; // 2M - - private static volatile ArrayList keepAlive; - - private static void allocate(int objectSize) { - keepAlive = new ArrayList<>(); - for (int i = 0; i < allocSize; i+= objectSize) { - keepAlive.add(new byte[objectSize]); - } - } - - private static void fragment() { - // Release every other reference to cause lots of fragmentation - for (int i = 0; i < keepAlive.size(); i += 2) { - keepAlive.set(i, null); - } - } - - private static void test(int objectSize) throws Exception { - System.out.println("Allocating"); - allocate(objectSize); - - System.out.println("Fragmenting"); - fragment(); - - System.out.println("Reclaiming"); - System.gc(); - } - - public static void main(String[] args) throws Exception { - for (int i = 0; i < 10; i++) { - System.out.println("Iteration " + i); - test(smallObjectSize); - test(mediumObjectSize); - } - } -} diff --git a/test/hotspot/jtreg/gc/x/TestSmallHeap.java b/test/hotspot/jtreg/gc/x/TestSmallHeap.java deleted file mode 100644 index a7e8042f92474..0000000000000 --- a/test/hotspot/jtreg/gc/x/TestSmallHeap.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 - * 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 gc.x; - -/* - * @test TestSmallHeap - * @requires vm.gc.ZSinglegen - * @summary Test ZGC with small heaps - * @library / /test/lib - * @run driver gc.x.TestSmallHeap 8M 16M 32M 64M 128M 256M 512M 1024M - */ - -import jdk.test.lib.process.ProcessTools; -import static gc.testlibrary.Allocation.blackHole; - -public class TestSmallHeap { - public static class Test { - public static void main(String[] args) throws Exception { - final long maxCapacity = Runtime.getRuntime().maxMemory(); - System.out.println("Max Capacity " + maxCapacity + " bytes"); - - // Allocate byte arrays of increasing length, so that - // all allocation paths (small/medium/large) are tested. - for (int length = 16; length <= maxCapacity / 16; length *= 2) { - System.out.println("Allocating " + length + " bytes"); - blackHole(new byte[length]); - } - - System.out.println("Success"); - } - } - - public static void main(String[] args) throws Exception { - for (var maxCapacity: args) { - ProcessTools.executeTestJava( - "-XX:+UseZGC", - "-XX:-ZGenerational", - "-Xlog:gc,gc+init,gc+reloc,gc+heap", - "-Xmx" + maxCapacity, - Test.class.getName()) - .outputTo(System.out) - .errorTo(System.out) - .shouldContain("Success") - .shouldHaveExitValue(0); - } - } -} diff --git a/test/hotspot/jtreg/gc/x/TestUncommit.java b/test/hotspot/jtreg/gc/x/TestUncommit.java deleted file mode 100644 index febd6b9958851..0000000000000 --- a/test/hotspot/jtreg/gc/x/TestUncommit.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2019, 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 gc.x; - -/* - * @test TestUncommit - * @requires vm.gc.ZSinglegen - * @summary Test ZGC uncommit unused memory - * @library /test/lib - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=10 gc.x.TestUncommit - */ - -import java.util.ArrayList; -import jdk.test.lib.Utils; - -public class TestUncommit { - private static final int delay = 10 * 1000; // milliseconds - private static final int allocSize = 200 * 1024 * 1024; // 200M - private static final int smallObjectSize = 4 * 1024; // 4K - private static final int mediumObjectSize = 2 * 1024 * 1024; // 2M - private static final int largeObjectSize = allocSize; - - private static volatile ArrayList keepAlive; - - private static final long startTime = System.nanoTime(); - - private static void log(String msg) { - final String elapsedSeconds = String.format("%.3fs", (System.nanoTime() - startTime) / 1_000_000_000.0); - System.out.println("[" + elapsedSeconds + "] (" + Thread.currentThread().getName() + ") " + msg); - } - - private static long capacity() { - return Runtime.getRuntime().totalMemory(); - } - - private static void allocate(int objectSize) { - keepAlive = new ArrayList<>(); - for (int i = 0; i < allocSize; i+= objectSize) { - keepAlive.add(new byte[objectSize]); - } - } - - private static void reclaim() { - keepAlive = null; - System.gc(); - } - - private static void test(int objectSize) throws Exception { - final var beforeAlloc = capacity(); - final var timeBeforeAlloc = System.nanoTime(); - - // Allocate memory - log("Allocating"); - allocate(objectSize); - - final var afterAlloc = capacity(); - - // Reclaim memory - log("Reclaiming"); - reclaim(); - - log("Waiting for uncommit to start"); - while (capacity() >= afterAlloc) { - Thread.sleep(1000); - } - - log("Uncommit started"); - final var timeUncommitStart = System.nanoTime(); - final var actualDelay = (timeUncommitStart - timeBeforeAlloc) / 1_000_000; - - log("Waiting for uncommit to complete"); - while (capacity() > beforeAlloc) { - Thread.sleep(1000); - } - - log("Uncommit completed"); - final var afterUncommit = capacity(); - - log(" Uncommit Delay: " + delay); - log(" Object Size: " + objectSize); - log(" Alloc Size: " + allocSize); - log(" Before Alloc: " + beforeAlloc); - log(" After Alloc: " + afterAlloc); - log(" After Uncommit: " + afterUncommit); - log(" Actual Uncommit Delay: " + actualDelay); - - // Verify - if (actualDelay < delay) { - throw new Exception("Uncommitted too fast"); - } - - if (actualDelay > delay * 2 * Utils.TIMEOUT_FACTOR) { - throw new Exception("Uncommitted too slow"); - } - - if (afterUncommit < beforeAlloc) { - throw new Exception("Uncommitted too much"); - } - - if (afterUncommit > beforeAlloc) { - throw new Exception("Uncommitted too little"); - } - - log("Success"); - } - - public static void main(String[] args) throws Exception { - for (int i = 0; i < 2; i++) { - log("Iteration " + i); - test(smallObjectSize); - test(mediumObjectSize); - test(largeObjectSize); - } - } -} diff --git a/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java b/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java index 2fb040840b4da..dbcca704fab4f 100644 --- a/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java +++ b/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java @@ -25,7 +25,7 @@ /* * @test TestAllocateHeapAt - * @requires vm.gc.ZGenerational & os.family == "linux" + * @requires vm.gc.Z & os.family == "linux" * @requires !vm.opt.final.UseLargePages * @summary Test ZGC with -XX:AllocateHeapAt * @library /test/lib @@ -44,7 +44,6 @@ public static void main(String[] args) throws Exception { ProcessTools.executeTestJava( "-XX:+UseZGC", - "-XX:+ZGenerational", "-Xlog:gc*", "-Xms32M", "-Xmx32M", diff --git a/test/hotspot/jtreg/gc/z/TestAllocateHeapAtWithHugeTLBFS.java b/test/hotspot/jtreg/gc/z/TestAllocateHeapAtWithHugeTLBFS.java index ac647bbd013fd..4134ce838d4f5 100644 --- a/test/hotspot/jtreg/gc/z/TestAllocateHeapAtWithHugeTLBFS.java +++ b/test/hotspot/jtreg/gc/z/TestAllocateHeapAtWithHugeTLBFS.java @@ -25,7 +25,7 @@ /* * @test TestAllocateHeapAtWithHugeTLBFS - * @requires vm.gc.ZGenerational & os.family == "linux" + * @requires vm.gc.Z & os.family == "linux" * @summary Test ZGC with -XX:AllocateHeapAt and -XX:+UseLargePages * @library /test/lib * @run driver gc.z.TestAllocateHeapAtWithHugeTLBFS true @@ -77,7 +77,6 @@ public static void main(String[] args) throws Exception { ProcessTools.executeTestJava( "-XX:+UseZGC", - "-XX:+ZGenerational", "-Xlog:gc*", "-Xms32M", "-Xmx32M", diff --git a/test/hotspot/jtreg/gc/z/TestAlwaysPreTouch.java b/test/hotspot/jtreg/gc/z/TestAlwaysPreTouch.java index 8020c82c4fd3f..db0471431d1aa 100644 --- a/test/hotspot/jtreg/gc/z/TestAlwaysPreTouch.java +++ b/test/hotspot/jtreg/gc/z/TestAlwaysPreTouch.java @@ -25,13 +25,13 @@ /* * @test TestAlwaysPreTouch - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @summary Test ZGC parallel pre-touch - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xlog:gc* -XX:-AlwaysPreTouch -Xms128M -Xmx128M gc.z.TestAlwaysPreTouch - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=1 -Xms2M -Xmx128M gc.z.TestAlwaysPreTouch - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=8 -Xms2M -Xmx128M gc.z.TestAlwaysPreTouch - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=1 -Xms128M -Xmx128M gc.z.TestAlwaysPreTouch - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=8 -Xms128M -Xmx128M gc.z.TestAlwaysPreTouch + * @run main/othervm -XX:+UseZGC -Xlog:gc* -XX:-AlwaysPreTouch -Xms128M -Xmx128M gc.z.TestAlwaysPreTouch + * @run main/othervm -XX:+UseZGC -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=1 -Xms2M -Xmx128M gc.z.TestAlwaysPreTouch + * @run main/othervm -XX:+UseZGC -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=8 -Xms2M -Xmx128M gc.z.TestAlwaysPreTouch + * @run main/othervm -XX:+UseZGC -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=1 -Xms128M -Xmx128M gc.z.TestAlwaysPreTouch + * @run main/othervm -XX:+UseZGC -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=8 -Xms128M -Xmx128M gc.z.TestAlwaysPreTouch */ public class TestAlwaysPreTouch { diff --git a/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java b/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java index b3ecc28ff657e..d3cf46d51e853 100644 --- a/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java +++ b/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java @@ -25,12 +25,12 @@ /** * @test TestGarbageCollectorMXBean - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @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 + * @run main/othervm -XX:+UseZGC -Xms256M -Xmx512M -Xlog:gc gc.z.TestGarbageCollectorMXBean 256 512 + * @run main/othervm -XX:+UseZGC -Xms512M -Xmx512M -Xlog:gc gc.z.TestGarbageCollectorMXBean 512 512 */ import java.lang.management.ManagementFactory; diff --git a/test/hotspot/jtreg/gc/z/TestMemoryMXBean.java b/test/hotspot/jtreg/gc/z/TestMemoryMXBean.java index 6f4505a64bf14..ec1daaa00fbd6 100644 --- a/test/hotspot/jtreg/gc/z/TestMemoryMXBean.java +++ b/test/hotspot/jtreg/gc/z/TestMemoryMXBean.java @@ -25,11 +25,11 @@ /** * @test TestMemoryMXBean - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @summary Test ZGC heap memory MXBean * @modules java.management - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xms128M -Xmx256M -Xlog:gc* gc.z.TestMemoryMXBean 128 256 - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xms256M -Xmx256M -Xlog:gc* gc.z.TestMemoryMXBean 256 256 + * @run main/othervm -XX:+UseZGC -Xms128M -Xmx256M -Xlog:gc* gc.z.TestMemoryMXBean 128 256 + * @run main/othervm -XX:+UseZGC -Xms256M -Xmx256M -Xlog:gc* gc.z.TestMemoryMXBean 256 256 */ import java.lang.management.ManagementFactory; diff --git a/test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java b/test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java index 5a0c481a42fed..6540d67e855c2 100644 --- a/test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java +++ b/test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java @@ -25,10 +25,10 @@ /** * @test TestMemoryManagerMXBean - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @summary Test ZGC memory manager MXBean * @modules java.management - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xmx128M gc.z.TestMemoryManagerMXBean + * @run main/othervm -XX:+UseZGC -Xmx128M gc.z.TestMemoryManagerMXBean */ import java.lang.management.ManagementFactory; diff --git a/test/hotspot/jtreg/gc/z/TestNoUncommit.java b/test/hotspot/jtreg/gc/z/TestNoUncommit.java index 6115681552e73..cd5833f308fe0 100644 --- a/test/hotspot/jtreg/gc/z/TestNoUncommit.java +++ b/test/hotspot/jtreg/gc/z/TestNoUncommit.java @@ -25,10 +25,10 @@ /* * @test TestNoUncommit - * @requires vm.gc.ZGenerational & !vm.graal.enabled + * @requires vm.gc.Z & !vm.graal.enabled * @summary Test ZGC uncommit unused memory disabled - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms512M -Xmx512M -XX:ZUncommitDelay=1 gc.z.TestNoUncommit - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=1 -XX:-ZUncommit gc.z.TestNoUncommit + * @run main/othervm -XX:+UseZGC -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms512M -Xmx512M -XX:ZUncommitDelay=1 gc.z.TestNoUncommit + * @run main/othervm -XX:+UseZGC -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=1 -XX:-ZUncommit gc.z.TestNoUncommit */ public class TestNoUncommit { diff --git a/test/hotspot/jtreg/gc/z/TestPageCacheFlush.java b/test/hotspot/jtreg/gc/z/TestPageCacheFlush.java index 3b666ddc2c8a6..847c7b2d1171e 100644 --- a/test/hotspot/jtreg/gc/z/TestPageCacheFlush.java +++ b/test/hotspot/jtreg/gc/z/TestPageCacheFlush.java @@ -25,7 +25,7 @@ /* * @test TestPageCacheFlush - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @summary Test ZGC page cache flushing * @library /test/lib * @run driver gc.z.TestPageCacheFlush @@ -70,7 +70,6 @@ public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception { ProcessTools.executeTestJava( "-XX:+UseZGC", - "-XX:+ZGenerational", "-Xms128M", "-Xmx128M", "-Xlog:gc,gc+init,gc+heap=debug", diff --git a/test/hotspot/jtreg/gc/z/TestRegistersPushPopAtZGCLoadBarrierStub.java b/test/hotspot/jtreg/gc/z/TestRegistersPushPopAtZGCLoadBarrierStub.java index 71aa634c761d3..9730fdaafd8e4 100644 --- a/test/hotspot/jtreg/gc/z/TestRegistersPushPopAtZGCLoadBarrierStub.java +++ b/test/hotspot/jtreg/gc/z/TestRegistersPushPopAtZGCLoadBarrierStub.java @@ -31,7 +31,7 @@ * @library /test/lib / * @modules jdk.incubator.vector * - * @requires vm.gc.ZGenerational & vm.debug + * @requires vm.gc.Z & vm.debug * @requires os.arch=="aarch64" * * @run driver gc.z.TestRegistersPushPopAtZGCLoadBarrierStub @@ -316,7 +316,6 @@ static String launchJavaTestProcess(String test_name) throws Exception { command.add("-XX:-UseOnStackReplacement"); command.add("-XX:-TieredCompilation"); command.add("-XX:+UseZGC"); - command.add("-XX:+ZGenerational"); command.add("--add-modules=jdk.incubator.vector"); command.add("-XX:CompileCommand=print," + Launcher.class.getName() + "::" + test_name); command.add(Launcher.class.getName()); diff --git a/test/hotspot/jtreg/gc/z/TestRelocateInPlace.java b/test/hotspot/jtreg/gc/z/TestRelocateInPlace.java index 5115fe3c96545..723a6504c6acf 100644 --- a/test/hotspot/jtreg/gc/z/TestRelocateInPlace.java +++ b/test/hotspot/jtreg/gc/z/TestRelocateInPlace.java @@ -25,9 +25,9 @@ /* * @test TestRelocateInPlace - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @summary Test ZGC in-place relocateion - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xlog:gc*,gc+stats=off -Xmx256M -XX:+UnlockDiagnosticVMOptions -XX:+ZStressRelocateInPlace gc.z.TestRelocateInPlace + * @run main/othervm -XX:+UseZGC -Xlog:gc*,gc+stats=off -Xmx256M -XX:+UnlockDiagnosticVMOptions -XX:+ZStressRelocateInPlace gc.z.TestRelocateInPlace */ import java.util.ArrayList; diff --git a/test/hotspot/jtreg/gc/z/TestSmallHeap.java b/test/hotspot/jtreg/gc/z/TestSmallHeap.java index 67d9d33d2815e..9ac65d05108ca 100644 --- a/test/hotspot/jtreg/gc/z/TestSmallHeap.java +++ b/test/hotspot/jtreg/gc/z/TestSmallHeap.java @@ -25,7 +25,7 @@ /* * @test TestSmallHeap - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @summary Test ZGC with small heaps * @library / /test/lib * @run driver gc.z.TestSmallHeap 16M 32M 64M 128M 256M 512M 1024M @@ -55,7 +55,6 @@ public static void main(String[] args) throws Exception { for (var maxCapacity: args) { ProcessTools.executeTestJava( "-XX:+UseZGC", - "-XX:+ZGenerational", "-Xlog:gc,gc+init,gc+reloc,gc+heap", "-Xmx" + maxCapacity, Test.class.getName()) diff --git a/test/hotspot/jtreg/gc/z/TestUncommit.java b/test/hotspot/jtreg/gc/z/TestUncommit.java index fea0721cce311..e02773e868f60 100644 --- a/test/hotspot/jtreg/gc/z/TestUncommit.java +++ b/test/hotspot/jtreg/gc/z/TestUncommit.java @@ -25,10 +25,10 @@ /* * @test TestUncommit - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @summary Test ZGC uncommit unused memory * @library /test/lib - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=10 gc.z.TestUncommit + * @run main/othervm -XX:+UseZGC -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=10 gc.z.TestUncommit */ import java.util.ArrayList; diff --git a/test/hotspot/jtreg/gc/z/TestZForceDiscontiguousHeapReservations.java b/test/hotspot/jtreg/gc/z/TestZForceDiscontiguousHeapReservations.java index f1a14f0cf902b..fa2485073dda5 100644 --- a/test/hotspot/jtreg/gc/z/TestZForceDiscontiguousHeapReservations.java +++ b/test/hotspot/jtreg/gc/z/TestZForceDiscontiguousHeapReservations.java @@ -25,7 +25,7 @@ /** * @test TestZForceDiscontiguousHeapReservations - * @requires vm.gc.ZGenerational & vm.debug + * @requires vm.gc.Z & vm.debug * @summary Test the ZForceDiscontiguousHeapReservations development flag * @library /test/lib * @run driver gc.z.TestZForceDiscontiguousHeapReservations @@ -47,7 +47,6 @@ private static void testValue(int n) throws Exception { final int XmsInM = Math.min(16 * XmxInM / (n + 1), XmxInM); OutputAnalyzer oa = ProcessTools.executeTestJava( "-XX:+UseZGC", - "-XX:+ZGenerational", "-Xms" + XmsInM + "M", "-Xmx" + XmxInM + "M", "-Xlog:gc,gc+init", diff --git a/test/hotspot/jtreg/gc/z/TestZNMT.java b/test/hotspot/jtreg/gc/z/TestZNMT.java index 889cc77b0e4b7..b536f3eab8e96 100644 --- a/test/hotspot/jtreg/gc/z/TestZNMT.java +++ b/test/hotspot/jtreg/gc/z/TestZNMT.java @@ -26,8 +26,8 @@ /** * @test TestZNMT * @bug 8310743 - * @requires vm.gc.ZGenerational & vm.debug - * @summary Test NMT and ZGenerational heap reservation / commits interactions. + * @requires vm.gc.Z & vm.debug + * @summary Test NMT and ZGC heap reservation / commits interactions. * @library / /test/lib * @run driver gc.z.TestZNMT */ @@ -70,7 +70,6 @@ private static void testValue(int zForceDiscontiguousHeapReservations) throws Ex final int XmsInM = Math.min(16 * XmxInM / (zForceDiscontiguousHeapReservations + 1), XmxInM); OutputAnalyzer oa = ProcessTools.executeTestJava( "-XX:+UseZGC", - "-XX:+ZGenerational", "-Xms" + XmsInM + "M", "-Xmx" + XmxInM + "M", "-Xlog:gc,gc+init", diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java index 96bc22dfb1d05..0ecfbe2c8dbc3 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java +++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java @@ -57,7 +57,6 @@ public class VMDeprecatedOptions { Arrays.asList(new String[][] { // deprecated non-alias flags: {"AllowRedefinitionToAddDeleteMethods", "true"}, - {"ZGenerational", "false"}, {"LockingMode", "1"}, // deprecated alias flags (see also aliased_jvm_flags): diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java b/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java index aaee80169eb06..90b309069ac4f 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java +++ b/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java @@ -22,14 +22,37 @@ */ /* - * @test + * @test VMOptionWarningExperimental * @bug 8027314 - * @summary Warn if diagnostic or experimental vm option is used and -XX:+UnlockDiagnosticVMOptions or -XX:+UnlockExperimentalVMOptions, respectively, isn't specified. Warn if develop vm option is used with product version of VM. + * @summary Warn if experimental vm option is used and -XX:+UnlockExperimentalVMOptions isn't specified. * @requires vm.flagless + * @requires ! vm.opt.final.UnlockExperimentalVMOptions * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @run driver VMOptionWarning + * @run driver VMOptionWarning Experimental + */ + +/* @test VMOptionWarningDiagnostic + * @bug 8027314 + * @summary Warn if diagnostic vm option is used and -XX:+UnlockDiagnosticVMOptions isn't specified. + * @requires vm.flagless + * @requires ! vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver VMOptionWarning Diagnostic + */ + +/* @test VMOptionWarningDevelop + * @bug 8027314 + * @summary Warn if develop vm option is used with product version of VM. + * @requires vm.flagless + * @requires ! vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver VMOptionWarning Develop */ import jdk.test.lib.process.ProcessTools; @@ -38,24 +61,37 @@ public class VMOptionWarning { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+AlwaysSafeConstructors", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotHaveExitValue(0); - output.shouldContain("Error: VM option 'AlwaysSafeConstructors' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions."); - - if (Platform.isDebugBuild()) { - System.out.println("Skip the rest of the tests on debug builds since diagnostic, and develop options are available on debug builds."); - return; + if (args.length != 1) { + throw new RuntimeException("wrong number of args: " + args.length); } - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+PrintInlining", "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldNotHaveExitValue(0); - output.shouldContain("Error: VM option 'PrintInlining' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions."); - - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+VerifyStack", "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldNotHaveExitValue(0); - output.shouldContain("Error: VM option 'VerifyStack' is develop and is available only in debug version of VM."); + ProcessBuilder pb; + OutputAnalyzer output; + switch (args[0]) { + case "Experimental": { + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+AlwaysSafeConstructors", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); + output.shouldContain("Error: VM option 'AlwaysSafeConstructors' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions."); + break; + } + case "Diagnostic": { + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+PrintInlining", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); + output.shouldContain("Error: VM option 'PrintInlining' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions."); + break; + } + case "Develop": { + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+VerifyStack", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); + output.shouldContain("Error: VM option 'VerifyStack' is develop and is available only in debug version of VM."); + break; + } + default: { + throw new RuntimeException("Invalid argument: " + args[0]); + } + } } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java index 73efc0e5e4605..76ea10d77cbbe 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor * @run driver CreateCoredumpOnCrash + * @requires vm.flagless */ import jdk.test.lib.process.ProcessTools; @@ -43,24 +44,61 @@ public static void main(String[] args) { } } + private static String ulimitString(int limit) { + String string = "ulimit -c "; + if (limit != Integer.MAX_VALUE) { + string += limit; + } else { + string += "unlimited"; + } + return string+";"; + } + public static void main(String[] args) throws Exception { runTest("-XX:-CreateCoredumpOnCrash").shouldContain("CreateCoredumpOnCrash turned off, no core file dumped") - .shouldNotHaveExitValue(0); + .shouldNotHaveExitValue(0); if (Platform.isWindows()) { // The old CreateMinidumpOnCrash option should still work runTest("-XX:-CreateMinidumpOnCrash").shouldContain("CreateCoredumpOnCrash turned off, no core file dumped") - .shouldNotHaveExitValue(0); + .shouldNotHaveExitValue(0); } else { - runTest("-XX:+CreateCoredumpOnCrash").shouldNotContain("CreateCoredumpOnCrash turned off, no core file dumped") - .shouldNotHaveExitValue(0); - } + String exec_cmd[] = {"sh", "-c", "ulimit -c"}; + OutputAnalyzer oa = new OutputAnalyzer(Runtime.getRuntime().exec(exec_cmd)); + oa.shouldHaveExitValue(0); + if (!oa.contains("0\n")) { + oa = runTest("-XX:+CreateCoredumpOnCrash"); + oa.shouldContain("Core dump will be written."); + oa.shouldNotHaveExitValue(0); + oa = runTest("-XX:+CreateCoredumpOnCrash", ulimitString(1024)); + oa.shouldContain("warning: CreateCoredumpOnCrash specified, but"); + oa.shouldNotHaveExitValue(0); + + oa = runTest("-XX:+CreateCoredumpOnCrash", ulimitString(0)); + oa.shouldContain("warning: CreateCoredumpOnCrash specified, but"); + oa.shouldNotHaveExitValue(0); + } else { + throw new Exception("ulimit is not set correctly, try 'ulimit -c unlimited' and re-run."); + } + } } + public static OutputAnalyzer runTest(String option) throws Exception { - return new OutputAnalyzer( - ProcessTools.createLimitedTestJavaProcessBuilder( - "-Xmx128m", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", option, Crasher.class.getName()) - .start()); + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xmx128m", + "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + option, Crasher.class.getName()); + return new OutputAnalyzer(pb.start()); + } + public static OutputAnalyzer runTest(String option, String limit) throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xmx128m", + "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + option, new String("'"+Crasher.class.getName()+"'")); + String args = ""; + for (String s:pb.command()) { + args += s+" "; + } + String exec_cmd[] = {"sh", "-c", limit+args}; + return new OutputAnalyzer(Runtime.getRuntime().exec(exec_cmd)); } } diff --git a/test/hotspot/jtreg/runtime/FieldLayout/TestFieldLayout.java b/test/hotspot/jtreg/runtime/FieldLayout/TestFieldLayout.java new file mode 100644 index 0000000000000..4066d6dd743d5 --- /dev/null +++ b/test/hotspot/jtreg/runtime/FieldLayout/TestFieldLayout.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024, 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 + * 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.lang.reflect.Field; +import jdk.internal.misc.Unsafe; + +/* + * @test + * @bug 8341471 + * @summary Reversed field layout caused by unstable sorting + * @modules java.base/jdk.internal.misc + * @run main/othervm TestFieldLayout + */ + +public class TestFieldLayout { + + private static final Unsafe U = Unsafe.getUnsafe(); + + public static void main(String[] args) throws Exception { + + boolean endResult = true; + long previous = 0; + + for (Field f : Test.class.getDeclaredFields()) { + long current = U.objectFieldOffset(f); + if (current < previous) { + System.out.printf("FAILED: field %s offset %d previous %d\n", + f.getName(), current, previous); + endResult = false; + } + previous = current; + } + + System.out.println(endResult ? "Test PASSES" : "Test FAILS"); + if (!endResult) { + throw new Error("Test failed"); + } + } + + public class Test { + char a000; + char a001; + char a002; + char a003; + char a004; + char a005; + char a006; + char a007; + char a008; + char a009; + char a00a; + char a00b; + } + +} + diff --git a/test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java b/test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java new file mode 100644 index 0000000000000..c31d96b1c824d --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java @@ -0,0 +1,68 @@ +/* + * 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 + * @summary Classes used by CDS at runtime should be in the archived + * @bug 8324259 + * @requires vm.cds + * @requires vm.compMode != "Xcomp" + * @comment Running this test with -Xcomp may load other classes which + * are not used in other modes + * @library /test/lib + * @compile test-classes/Hello.java + * @run driver DumpRuntimeClassesTest + */ + +import jdk.test.lib.cds.CDSOptions; +import jdk.test.lib.cds.CDSTestUtils; + +public class DumpRuntimeClassesTest { + public static void main(String[] args) throws Exception { + // build The app + String appClass = "Hello"; + String classList = "hello.classlist"; + String archiveName = "hello.jsa"; + JarBuilder.build("hello", appClass); + String appJar = TestCommon.getTestJar("hello.jar"); + + // Dump class list + CDSTestUtils.dumpClassList(classList, "-cp", appJar, appClass); + + // Dump archive + CDSOptions opts = (new CDSOptions()) + .addPrefix("-cp", appJar, "-XX:SharedClassListFile=" + classList) + .setArchiveName(archiveName); + CDSTestUtils.createArchive(opts); + + // Run with archive and ensure all the classes used were in the archive + CDSOptions runOpts = (new CDSOptions()) + .addPrefix("-cp", appJar, "-Xlog:class+load,cds=debug") + .setArchiveName(archiveName) + .setUseVersion(false) + .addSuffix(appClass); + CDSTestUtils.runWithArchive(runOpts) + .shouldNotContain("source: jrt:/java.base"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestEpsilonGCWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestEpsilonGCWithCDS.java index fe7c5a4ae3153..132f63ba850d4 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestEpsilonGCWithCDS.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestEpsilonGCWithCDS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,16 +37,41 @@ * @run driver TestEpsilonGCWithCDS */ +// Below is exactly the same as above, except: +// - requires vm.bits == "64" +// - extra argument "false" + +/* + * @test Loading CDS archived heap objects into EpsilonGC + * @bug 8234679 8341371 + * @requires vm.cds + * @requires vm.gc.Epsilon + * @requires vm.gc.G1 + * @requires vm.bits == "64" + * + * @comment don't run this test if any -XX::+Use???GC options are specified, since they will + * interfere with the test. + * @requires vm.gc == null + * + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile test-classes/Hello.java + * @run driver TestEpsilonGCWithCDS false + */ import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; public class TestEpsilonGCWithCDS { public final static String HELLO = "Hello World"; static String helloJar; + static boolean useCompressedOops = true; public static void main(String... args) throws Exception { helloJar = JarBuilder.build("hello", "Hello"); + if (args.length > 0 && args[0].equals("false")) { + useCompressedOops = false; + } + // Check if we can use EpsilonGC during dump time, or run time, or both. test(false, true); test(true, false); @@ -70,6 +95,8 @@ static void test(boolean dumpWithEpsilon, boolean execWithEpsilon, boolean useSm String execGC = execWithEpsilon ? Epsilon : G1; String small1 = useSmallRegions ? "-Xmx256m" : "-showversion"; String small2 = useSmallRegions ? "-XX:ObjectAlignmentInBytes=64" : "-showversion"; + String errMsg = "Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"; + String coops = useCompressedOops ? "-XX:+UseCompressedOops" : "-XX:-UseCompressedOops"; OutputAnalyzer out; System.out.println("0. Dump with " + dumpGC); @@ -79,6 +106,7 @@ static void test(boolean dumpWithEpsilon, boolean execWithEpsilon, boolean useSm dumpGC, small1, small2, + coops, "-Xlog:cds"); out.shouldContain("Dumping shared data to file:"); out.shouldHaveExitValue(0); @@ -89,9 +117,11 @@ static void test(boolean dumpWithEpsilon, boolean execWithEpsilon, boolean useSm execGC, small1, small2, + coops, "-Xlog:cds", "Hello"); out.shouldContain(HELLO); + out.shouldNotContain(errMsg); out.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java index 691c87fef360c..705df07f84132 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java @@ -37,16 +37,41 @@ * @run driver TestParallelGCWithCDS */ +// Below is exactly the same as above, except: +// - requires vm.bits == "64" +// - extra argument "false" + + /* + * @test Loading CDS archived heap objects into ParallelGC + * @bug 8274788 8341371 + * @requires vm.cds + * @requires vm.gc.Parallel + * @requires vm.gc.G1 + * @requires vm.bits == "64" + * + * @comment don't run this test if any -XX::+Use???GC options are specified, since they will + * interfere with the test. + * @requires vm.gc == null + * + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile test-classes/Hello.java + * @run driver TestParallelGCWithCDS false + */ import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; public class TestParallelGCWithCDS { public final static String HELLO = "Hello World"; static String helloJar; + static boolean useCompressedOops = true; public static void main(String... args) throws Exception { helloJar = JarBuilder.build("hello", "Hello"); + if (args.length > 0 && args[0].equals("false")) { + useCompressedOops = false; + } + // Check if we can use ParallelGC during dump time, or run time, or both. test(false, true); test(true, false); @@ -69,6 +94,8 @@ static void test(boolean dumpWithParallel, boolean execWithParallel, boolean use String execGC = execWithParallel ? Parallel : G1; String small1 = useSmallRegions ? "-Xmx256m" : "-showversion"; String small2 = useSmallRegions ? "-XX:ObjectAlignmentInBytes=64" : "-showversion"; + String errMsg = "Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"; + String coops = useCompressedOops ? "-XX:+UseCompressedOops" : "-XX:-UseCompressedOops"; OutputAnalyzer out; System.out.println("0. Dump with " + dumpGC); @@ -77,6 +104,7 @@ static void test(boolean dumpWithParallel, boolean execWithParallel, boolean use dumpGC, small1, small2, + coops, "-Xlog:cds"); out.shouldContain("Dumping shared data to file:"); out.shouldHaveExitValue(0); @@ -86,9 +114,11 @@ static void test(boolean dumpWithParallel, boolean execWithParallel, boolean use execGC, small1, small2, + coops, "-Xlog:cds", "Hello"); out.shouldContain(HELLO); + out.shouldNotContain(errMsg); out.shouldHaveExitValue(0); int n = 2; @@ -109,10 +139,12 @@ static void test(boolean dumpWithParallel, boolean execWithParallel, boolean use small1, small2, xmx, + coops, "-Xlog:cds", "Hello"); if (out.getExitValue() == 0) { out.shouldContain(HELLO); + out.shouldNotContain(errMsg); } else { String pattern = "((Too small maximum heap)" + "|(GC triggered before VM initialization completed)" + diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java index 8c8cb4d932a52..b191b5f395b53 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,6 +98,7 @@ static void test(boolean dumpWithSerial, boolean execWithSerial, boolean useSmal String execGC = execWithSerial ? Serial : G1; String small1 = useSmallRegions ? "-Xmx256m" : DUMMY; String small2 = useSmallRegions ? "-XX:ObjectAlignmentInBytes=64" : DUMMY; + String errMsg = "Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"; String coops; if (Platform.is64bit()) { coops = useCompressedOops ? "-XX:+UseCompressedOops" : "-XX:-UseCompressedOops"; @@ -125,7 +126,7 @@ static void test(boolean dumpWithSerial, boolean execWithSerial, boolean useSmal coops, "-Xlog:cds", "Hello"); - checkExecOutput(dumpWithSerial, execWithSerial, out); + out.shouldNotContain(errMsg); System.out.println("2. Exec with " + execGC + " and test ArchiveRelocationMode"); out = TestCommon.exec(helloJar, @@ -136,7 +137,7 @@ static void test(boolean dumpWithSerial, boolean execWithSerial, boolean useSmal "-Xlog:cds,cds+heap", "-XX:ArchiveRelocationMode=1", // always relocate shared metadata "Hello"); - checkExecOutput(dumpWithSerial, execWithSerial, out); + out.shouldNotContain(errMsg); int n = 2; if (dumpWithSerial == false && execWithSerial == true) { @@ -160,7 +161,7 @@ static void test(boolean dumpWithSerial, boolean execWithSerial, boolean useSmal "-Xlog:cds", "Hello"); if (out.getExitValue() == 0) { - checkExecOutput(dumpWithSerial, execWithSerial, out); + out.shouldNotContain(errMsg); } else { String output = out.getStdout() + out.getStderr(); String exp1 = "Too small maximum heap"; @@ -173,19 +174,4 @@ static void test(boolean dumpWithSerial, boolean execWithSerial, boolean useSmal } } } - - static void checkExecOutput(boolean dumpWithSerial, boolean execWithSerial, OutputAnalyzer out) { - String errMsg = "Cannot use CDS heap data. UseG1GC is required for -XX:-UseCompressedOops"; - if (Platform.is64bit() && - !Platform.isWindows() && // archive heap not supported on Windows. - !dumpWithSerial && // Dumped with G1, so we have an archived heap - execWithSerial && // Running with serial - !useCompressedOops) { // ArchiveHeapLoader::can_load() always returns false when COOP is disabled - out.shouldContain(errMsg); - } - if (!execWithSerial) { - // We should never see this message with G1 - out.shouldNotContain(errMsg); - } - } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java index 83442c1e159f7..d8bbfee504b7a 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java @@ -35,16 +35,38 @@ * @run driver TestShenandoahWithCDS */ +// Below is exactly the same as above, except: +// - requires vm.bits == "64" +// - extra argument "false" + +/* + * @test + * @bug 8293650 8341371 + * @requires vm.cds + * @requires vm.bits == 64 + * @requires vm.gc.Shenandoah + * @requires vm.gc.G1 + * @requires vm.gc == null + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile test-classes/Hello.java + * @run driver TestShenandoahWithCDS false + */ + import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; public class TestShenandoahWithCDS { public final static String HELLO = "Hello World"; static String helloJar; + static boolean useCompressedOops = true; public static void main(String... args) throws Exception { helloJar = JarBuilder.build("hello", "Hello"); + if (args.length > 0 && args[0].equals("false")) { + useCompressedOops = false; + } + // Run with the variety of region sizes, and combinations // of G1/Shenandoah at dump/exec times. "-1" means to use G1. final int[] regionSizes = { -1, 256, 512, 1024, 2048 }; @@ -62,6 +84,8 @@ static void test(int dumpRegionSize, int execRegionSize) throws Exception { String optExecGC = (execRegionSize != -1) ? "-XX:+UseShenandoahGC" : "-XX:+UseG1GC"; String optDumpRegionSize = (dumpRegionSize != -1) ? "-XX:ShenandoahRegionSize=" + dumpRegionSize + "K" : exp; String optExecRegionSize = (execRegionSize != -1) ? "-XX:ShenandoahRegionSize=" + execRegionSize + "K" : exp; + String errMsg = "Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"; + String coops = useCompressedOops ? "-XX:+UseCompressedOops" : "-XX:-UseCompressedOops"; OutputAnalyzer out; System.out.println("0. Dump with " + optDumpGC + " and " + optDumpRegionSize); @@ -71,6 +95,7 @@ static void test(int dumpRegionSize, int execRegionSize) throws Exception { "-Xmx1g", optDumpGC, optDumpRegionSize, + coops, "-Xlog:cds"); out.shouldContain("Dumping shared data to file:"); out.shouldHaveExitValue(0); @@ -81,9 +106,11 @@ static void test(int dumpRegionSize, int execRegionSize) throws Exception { "-Xmx1g", optExecGC, optExecRegionSize, + coops, "-Xlog:cds", "Hello"); out.shouldContain(HELLO); + out.shouldNotContain(errMsg); out.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestZGCWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestZGCWithCDS.java index ea51b198f5999..89fc346ffbb79 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestZGCWithCDS.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestZGCWithCDS.java @@ -22,29 +22,16 @@ */ /* - * @test id=ZSinglegen + * @test * @bug 8232069 * @requires vm.cds * @requires vm.bits == 64 - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @requires vm.gc.Serial * @requires vm.gc == null * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds * @compile test-classes/Hello.java - * @run driver TestZGCWithCDS -XX:-ZGenerational - */ - -/* - * @test id=ZGenerational - * @bug 8232069 - * @requires vm.cds - * @requires vm.bits == 64 - * @requires vm.gc.ZGenerational - * @requires vm.gc.Serial - * @requires vm.gc == null - * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds - * @compile test-classes/Hello.java - * @run driver TestZGCWithCDS -XX:+ZGenerational + * @run driver TestZGCWithCDS */ import jdk.test.lib.Platform; @@ -55,14 +42,12 @@ public class TestZGCWithCDS { public final static String UNABLE_TO_USE_ARCHIVE = "Unable to use shared archive."; public final static String ERR_MSG = "The saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime, CDS will be disabled."; public static void main(String... args) throws Exception { - String zGenerational = args[0]; String helloJar = JarBuilder.build("hello", "Hello"); System.out.println("0. Dump with ZGC"); OutputAnalyzer out = TestCommon .dump(helloJar, new String[] {"Hello"}, "-XX:+UseZGC", - zGenerational, "-Xlog:cds"); out.shouldContain("Dumping shared data to file:"); out.shouldHaveExitValue(0); @@ -71,7 +56,6 @@ public static void main(String... args) throws Exception { out = TestCommon .exec(helloJar, "-XX:+UseZGC", - zGenerational, "-Xlog:cds", "Hello"); out.shouldContain(HELLO); @@ -151,7 +135,6 @@ public static void main(String... args) throws Exception { out = TestCommon .exec(helloJar, "-XX:+UseZGC", - zGenerational, "-Xlog:cds", "Hello"); out.shouldContain(HELLO); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java index 43d8568fac51a..8bf3f9fcd2700 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java @@ -27,8 +27,9 @@ * @summary Test primitive box caches integrity in various scenarios (IntegerCache etc) * @requires vm.cds.write.archived.java.heap * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/cds/appcds - * @compile CheckIntegerCacheApp.java + * @compile --add-exports java.base/jdk.internal.misc=ALL-UNNAMED CheckIntegerCacheApp.java ArchivedIntegerHolder.java * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boxCache.jar CheckIntegerCacheApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boxCache-boot.jar ArchivedIntegerHolder * @run driver ArchivedIntegerCacheTest */ @@ -41,6 +42,19 @@ public class ArchivedIntegerCacheTest { + public static String[] mixArgs(String... args) { + String bootJar = ClassFileInstaller.getJarPath("boxCache-boot.jar"); + + String[] newArgs = new String[args.length + 5]; + newArgs[0] = "--add-exports"; + newArgs[1] = "java.base/jdk.internal.misc=ALL-UNNAMED"; + newArgs[2] = "-Xbootclasspath/a:" + bootJar; + newArgs[3] = "-XX:+IgnoreUnrecognizedVMOptions"; + newArgs[4] = "-XX:ArchiveHeapTestClass=ArchivedIntegerHolder"; + System.arraycopy(args, 0, newArgs, 5, args.length); + return newArgs; + } + public static void main(String[] args) throws Exception { String appJar = ClassFileInstaller.getJarPath("boxCache.jar"); @@ -51,15 +65,15 @@ public static void main(String[] args) throws Exception { // Dump default archive // OutputAnalyzer output = TestCommon.dump(appJar, - TestCommon.list("CheckIntegerCacheApp")); + TestCommon.list("CheckIntegerCacheApp"), + mixArgs()); TestCommon.checkDump(output); // Test case 1) // - Default options System.out.println("----------------------- Test case 1 ----------------------"); output = TestCommon.exec(appJar, - "CheckIntegerCacheApp", - "127"); + mixArgs("CheckIntegerCacheApp", "127")); TestCommon.checkExec(output); // Test case 2) @@ -67,9 +81,8 @@ public static void main(String[] args) throws Exception { // - Larger -XX:AutoBoxCacheMax System.out.println("----------------------- Test case 2 ----------------------"); output = TestCommon.exec(appJar, - "-XX:AutoBoxCacheMax=20000", - "CheckIntegerCacheApp", - "20000"); + mixArgs("-XX:AutoBoxCacheMax=20000", + "CheckIntegerCacheApp", "20000")); TestCommon.checkExec(output); // @@ -77,7 +90,7 @@ public static void main(String[] args) throws Exception { // output = TestCommon.dump(appJar, TestCommon.list("CheckIntegerCacheApp"), - "-XX:AutoBoxCacheMax=20000"); + mixArgs("-XX:AutoBoxCacheMax=20000")); TestCommon.checkDump(output); // Test case 3) @@ -85,10 +98,8 @@ public static void main(String[] args) throws Exception { // - Default options System.out.println("----------------------- Test case 3 ----------------------"); output = TestCommon.exec(appJar, - "--module-path", - moduleDir.toString(), - "CheckIntegerCacheApp", - "127"); + mixArgs("--module-path", moduleDir.toString(), + "CheckIntegerCacheApp", "127")); TestCommon.checkExec(output); @@ -97,11 +108,9 @@ public static void main(String[] args) throws Exception { // - Matching options System.out.println("----------------------- Test case 4 ----------------------"); output = TestCommon.exec(appJar, - "--module-path", - moduleDir.toString(), - "-XX:AutoBoxCacheMax=20000", - "CheckIntegerCacheApp", - "20000"); + mixArgs("--module-path", moduleDir.toString(), + "-XX:AutoBoxCacheMax=20000", + "CheckIntegerCacheApp", "20000")); TestCommon.checkExec(output); // Test case 5) @@ -109,23 +118,21 @@ public static void main(String[] args) throws Exception { // - Larger requested cache System.out.println("----------------------- Test case 5 ----------------------"); output = TestCommon.exec(appJar, - "--module-path", - moduleDir.toString(), - "-XX:AutoBoxCacheMax=30000", - "CheckIntegerCacheApp", - "30000"); + mixArgs("--module-path", moduleDir.toString(), + "-XX:AutoBoxCacheMax=30000", + "CheckIntegerCacheApp", "30000")); TestCommon.checkExec(output); // Test case 6) // - Cache is too large to archive output = TestCommon.dump(appJar, TestCommon.list("CheckIntegerCacheApp"), - "-XX:AutoBoxCacheMax=2000000", - "-Xmx1g", - "-XX:NewSize=1g", - "-Xlog:cds+heap=info", - "-Xlog:gc+region+cds", - "-Xlog:gc+region=trace"); + mixArgs("-XX:AutoBoxCacheMax=2000000", + "-Xmx1g", + "-XX:NewSize=1g", + "-Xlog:cds+heap=info", + "-Xlog:gc+region+cds", + "-Xlog:gc+region=trace")); TestCommon.checkDump(output, "Cannot archive the sub-graph referenced from [Ljava.lang.Integer; object"); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XUtils.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerHolder.java similarity index 67% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XUtils.java rename to test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerHolder.java index a5c9ffde371dd..c8ab0db7d34dc 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/x/XUtils.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, 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 @@ -22,19 +22,17 @@ * */ -package sun.jvm.hotspot.gc.x; +import jdk.internal.misc.CDS; -import sun.jvm.hotspot.debugger.Address; -import sun.jvm.hotspot.runtime.VM; - -class XUtils { - static Address longToAddress(long value) { - return VM.getVM().getDebugger().newAddress(value); - } - - static long alignUp(long size, long alignment) { - long mask = alignment - 1; - long adjusted = size + mask; - return adjusted & ~mask; +public class ArchivedIntegerHolder { + public static Object[] archivedObjects; + static { + CDS.initializeFromArchive(ArchivedIntegerHolder.class); + if (archivedObjects == null) { + archivedObjects = new Object[256]; + for (int i = -128; i <= 127; i++) { + archivedObjects[i + 128] = Integer.valueOf(i); + } + } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java index a1d1655b32f65..7f66b2339a271 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java @@ -62,6 +62,14 @@ public static void main(String[] args) throws Exception { } } + // Check that archived integer cache agrees with runtime integer cache. + for (int i = -128; i <= 127; i++) { + if (ArchivedIntegerHolder.archivedObjects[i + 128] != Integer.valueOf(i)) { + throw new RuntimeException( + "FAILED. Archived and runtime caches disagree for " + i); + } + } + int high = Integer.parseInt(args[0]); if (Integer.valueOf(high) != Integer.valueOf(high)) { throw new RuntimeException( diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaProxyCallerIsHidden.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaProxyCallerIsHidden.java index 583f6cf55e23c..0c8cad0b3a604 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaProxyCallerIsHidden.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaProxyCallerIsHidden.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 @@ -37,7 +37,8 @@ * jdk/test/lib/compiler/InMemoryJavaCompiler * jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper$1 * jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper - * jdk/test/lib/compiler/InMemoryJavaCompiler$MemoryJavaFileObject + * jdk/test/lib/compiler/InMemoryJavaCompiler$SourceFile + * jdk/test/lib/compiler/InMemoryJavaCompiler$ClassFile * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. LambdaProxyCallerIsHidden */ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/MainModuleOnly.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/MainModuleOnly.java index 0dd4af2e4509e..e74229869edce 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/MainModuleOnly.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/MainModuleOnly.java @@ -213,8 +213,10 @@ public static void doTest(String topArchiveName) throws Exception { "-cp", destJar.toString(), "--module-path", MODS_DIR.toString(), "-m", TEST_MODULE1 + "/" + MAIN_CLASS) - .assertAbnormalExit(output -> { - output.shouldMatch("Error: non-empty directory.*com.simple"); + // After JDK-8328313, non-empty module path directory won't be included + // in the shared paths table. + .assertNormalExit(output -> { + output.shouldNotMatch("Error: non-empty directory.*com.simple"); }); // test module path with very long length diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RedefineCallerClassTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RedefineCallerClassTest.java index 3d6813479690d..90d403bc38020 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RedefineCallerClassTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RedefineCallerClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,8 @@ public class RedefineCallerClassTest extends DynamicArchiveTestBase { "jdk/test/lib/compiler/InMemoryJavaCompiler", "jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper", "jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper$1", - "jdk/test/lib/compiler/InMemoryJavaCompiler$MemoryJavaFileObject" + "jdk/test/lib/compiler/InMemoryJavaCompiler$SourceFile", + "jdk/test/lib/compiler/InMemoryJavaCompiler$ClassFile" }; public static void main(String[] args) throws Exception { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java index 3ceec349f5d76..957e4cb647979 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,8 @@ * jdk/test/lib/compiler/InMemoryJavaCompiler * jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper$1 * jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper - * jdk/test/lib/compiler/InMemoryJavaCompiler$MemoryJavaFileObject + * jdk/test/lib/compiler/InMemoryJavaCompiler$SourceFile + * jdk/test/lib/compiler/InMemoryJavaCompiler$ClassFile * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. RegularHiddenClass */ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDumpTransformer.java b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDumpTransformer.java index f50be0cedb255..76a7ddd9e8e43 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDumpTransformer.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDumpTransformer.java @@ -34,7 +34,10 @@ public class GCDuringDumpTransformer implements ClassFileTransformer { static boolean TEST_WITH_CLEANER = Boolean.getBoolean("test.with.cleaner"); static boolean TEST_WITH_EXCEPTION = Boolean.getBoolean("test.with.exception"); static boolean TEST_WITH_OOM = Boolean.getBoolean("test.with.oom"); + + static final int WASTE_SIZE = 1024; static List waste = new ArrayList(); + static Object sink; static Cleaner cleaner; static Thread thread; @@ -59,10 +62,13 @@ public byte[] transform(ClassLoader loader, String name, Class classBeingRede return new byte[] {1, 2, 3, 4, 5, 6, 7, 8}; } if (TEST_WITH_OOM) { - // fill until OOM + // Fill until OOM and fail. This sets up heap for secondary OOM + // later on, which should be caught by CDS code. The size of waste + // array defines how much max free space would be left for later + // code to run with. System.out.println("Fill objects until OOM"); - for (;;) { - waste.add(new byte[64*1024]); + while (true) { + waste.add(new byte[WASTE_SIZE]); } } } @@ -104,8 +110,8 @@ public static void agentmain(String args, Instrumentation inst) throws Exception } public static void makeGarbage() { - for (int x=0; x<10; x++) { - Object[] a = new Object[10000]; + for (int x = 0; x < 10; x++) { + sink = new byte[WASTE_SIZE]; } } @@ -115,7 +121,7 @@ static class MyCleaner implements Runnable { public void run() { // Allocate something. This will cause G1 to allocate an EDEN region. // See JDK-8245925 - Object o = new Object(); + sink = new Object(); System.out.println("cleaning " + i); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java new file mode 100644 index 0000000000000..5bab21dea133d --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java @@ -0,0 +1,231 @@ +/* + * 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 8319343 + * @summary Test handling of the --add-modules option. + * @requires vm.cds.write.archived.java.heap + * @requires vm.flagless + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @run driver AddmodsOption + */ + +import jdk.test.lib.process.OutputAnalyzer; + +public class AddmodsOption { + public static void main(String[] args) throws Exception { + final String moduleOption = "jdk.httpserver/sun.net.httpserver.simpleserver.Main"; + final String incubatorModule = "jdk.incubator.vector"; + final String jconsoleModule = "jdk.jconsole"; + final String multiModules = ",,jdk.jconsole,jdk.compiler,,"; + final String allSystem = "ALL-SYSTEM"; + final String allModulePath = "ALL-MODULE-PATH"; + final String loggingOption = "-Xlog:cds=debug,cds+module=debug,cds+heap=info,module=trace"; + final String versionPattern = "java.[0-9][0-9][-].*"; + final String subgraphCannotBeUsed = "subgraph jdk.internal.module.ArchivedBootLayer cannot be used because full module graph is disabled"; + final String warningIncubator = "WARNING: Using incubator modules: jdk.incubator.vector"; + String archiveName = TestCommon.getNewArchiveName("addmods-option"); + TestCommon.setCurrentArchiveName(archiveName); + + // dump a base archive with --add-modules jdk.jconsole -m jdk.httpserver + OutputAnalyzer oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "--add-modules", jconsoleModule, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0); + + // same modules specified during runtime + oa = TestCommon.execCommon( + loggingOption, + "--add-modules", jconsoleModule, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + // version of the jdk.httpserver module, e.g. java 22-ea + .shouldMatch(versionPattern) + .shouldMatch("cds,module.*Restored from archive: entry.0x.*name jdk.jconsole") + .shouldMatch("cds,module.*Restored from archive: entry.0x.*name jdk.httpserver"); + + // different --add-modules specified during runtime + oa = TestCommon.execCommon( + loggingOption, + "--add-modules", incubatorModule, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldContain("Mismatched --add-modules module name(s).") + .shouldContain("dump time: jdk.jconsole runtime: jdk.incubator.vector") + .shouldContain(subgraphCannotBeUsed); + + // no module specified during runtime + oa = TestCommon.execCommon( + loggingOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldContain("Module jdk.httpserver specified during dump time but not during runtime") + .shouldContain(subgraphCannotBeUsed); + + // dump an archive without the --add-modules option + archiveName = TestCommon.getNewArchiveName("no-addmods-option"); + TestCommon.setCurrentArchiveName(archiveName); + oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0); + + // run with --add-modules option + oa = TestCommon.execCommon( + loggingOption, + "--add-modules", jconsoleModule, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldContain("--add-modules module name(s) specified during runtime but not found in archive: jdk.jconsole") + // version of the jdk.httpserver module, e.g. java 22-ea + .shouldMatch(versionPattern) + .shouldContain(subgraphCannotBeUsed); + + // dump an archive with an incubator module, -add-modules jdk.incubator.vector + archiveName = TestCommon.getNewArchiveName("incubator-module"); + TestCommon.setCurrentArchiveName(archiveName); + oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "--add-modules", incubatorModule, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + // module graph won't be archived with an incubator module + .shouldContain("archivedBootLayer not available, disabling full module graph"); + + // run with the same incubator module + oa = TestCommon.execCommon( + loggingOption, + "--add-modules", incubatorModule, + "-m", moduleOption, + "-version"); + oa.shouldContain("full module graph: disabled") + // module is not restored from archive + .shouldContain("define_module(): creation of module: jdk.incubator.vector") + .shouldContain("WARNING: Using incubator modules: jdk.incubator.vector") + .shouldContain("subgraph jdk.internal.module.ArchivedBootLayer is not recorde") + .shouldHaveExitValue(0); + + // dump an archive with JVMCI option which indirectly adds the + // jdk.internal.vm.ci module using the --add-modules option + archiveName = TestCommon.getNewArchiveName("jvmci-module"); + TestCommon.setCurrentArchiveName(archiveName); + oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "-XX:+UnlockExperimentalVMOptions", + "-XX:+EagerJVMCI", "-XX:+UseJVMCICompiler", + "-version"); + oa.shouldHaveExitValue(0); + + // run with the JVMCI option + oa = TestCommon.execCommon( + loggingOption, + "-XX:+UnlockExperimentalVMOptions", + "-XX:+EagerJVMCI", "-XX:+UseJVMCICompiler", + "-version"); + try { + oa.shouldHaveExitValue(0) + .shouldMatch("cds,module.*Restored from archive: entry.0x.*name jdk.internal.vm.ci"); + } catch (RuntimeException re) { + // JVMCI compile may not be available + oa.shouldHaveExitValue(1) + .shouldContain("Cannot use JVMCI compiler: No JVMCI compiler found"); + } + + // dump an archive with multiple modules in -add-modules + archiveName = TestCommon.getNewArchiveName("muti-modules"); + TestCommon.setCurrentArchiveName(archiveName); + oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "--add-modules", multiModules, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0); + + // run with the same multiple modules with a duplicate module in --add-modules + oa = TestCommon.execCommon( + loggingOption, + "--add-modules", multiModules, + "--add-modules", jconsoleModule, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldMatch("cds,module.*Restored from archive: entry.0x.*name jdk.compiler") + .shouldMatch("cds,module.*Restored from archive: entry.0x.*name jdk.jconsole"); + + // dump an archive with ALL-SYSTEM in -add-modules + archiveName = TestCommon.getNewArchiveName("muti-modules"); + TestCommon.setCurrentArchiveName(archiveName); + oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "--add-modules", allSystem, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldContain(warningIncubator); + + // run with the same ALL-SYSTEM in --add-modules + oa = TestCommon.execCommon( + loggingOption, + "--add-modules", allSystem, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + // the jdk.incubator.vector was specified indirectly via ALL-SYSTEM + .shouldContain(warningIncubator) + .shouldContain("full module graph cannot be loaded: archive was created without full module graph"); + + // dump an archive with ALL-MODULE-PATH in -add-modules + archiveName = TestCommon.getNewArchiveName("muti-modules"); + TestCommon.setCurrentArchiveName(archiveName); + oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "--add-modules", allModulePath, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0); + + // run with the same ALL-MODULE-PATH in --add-modules + oa = TestCommon.execCommon( + loggingOption, + "--add-modules", allModulePath, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldMatch("cds,module.*Restored from archive: entry.0x.*name jdk.httpserver"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/MainModuleOnly.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/MainModuleOnly.java index 50191b91e1ef5..ac9bb5adc006d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/MainModuleOnly.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/MainModuleOnly.java @@ -194,8 +194,10 @@ public static void main(String... args) throws Exception { output = TestCommon.createArchive(destJar.toString(), appClasses, "--module-path", MODS_DIR.toString(), "-m", mainModule); - output.shouldHaveExitValue(1) - .shouldMatch("Error: non-empty directory.*com.simple"); + // After JDK-8328313, non-empty module path directory won't be included + // in the shared paths table. + output.shouldHaveExitValue(0) + .shouldNotMatch("Error: non-empty directory.*com.simple"); // test module path with very long length // diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java new file mode 100644 index 0000000000000..fe77714204670 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java @@ -0,0 +1,385 @@ +/* + * 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 8328313 + * @requires vm.cds & !vm.graal.enabled & vm.cds.write.archived.java.heap + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @run driver ModulePathAndFMG + * @summary test module path changes for full module graph handling. + * + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class ModulePathAndFMG { + private static final String JAVA_HOME = System.getProperty("java.home"); + + private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir()); + + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MODS_DIR = Paths.get("mody"); + private static final Path JMOD_DIR = Paths.get("jmod_dir"); + + // the module name of the test module + private static final String MAIN_MODULE = "com.bars"; + private static final String TEST_MODULE = "com.foos"; + private static final String DUP_MODULE = "com.foos3"; + + // the module main class + private static final String MAIN_CLASS = "com.bars.Main"; + private static final String TEST_CLASS = "com.foos.Test"; + + private static String PATH_LIBS = "modylibs"; + private static String DUP_LIBS = "duplibs"; + private static Path libsDir = null; + private static Path dupDir = null; + private static Path jmodDir = null; + private static Path mainJar = null; + private static Path testJar = null; + private static Path dupJar = null; + private static Path badJar = null; + + private static String CLASS_FOUND_MESSAGE = "com.foos.Test found"; + private static String CLASS_NOT_FOUND_MESSAGE = "java.lang.ClassNotFoundException: com.foos.Test"; + private static String FIND_EXCEPTION_MESSAGE = "java.lang.module.FindException: Module com.foos not found, required by com.bars"; + private static String MODULE_NOT_RECOGNIZED = "Module format not recognized:.*modylibs.*com.bars.JAR"; + private static String OPTIMIZE_ENABLED = "] optimized module handling: enabled"; + private static String OPTIMIZE_DISABLED = "] optimized module handling: disabled"; + private static String FMG_ENABLED = "] full module graph: enabled"; + private static String FMG_DISABLED = "] full module graph: disabled"; + private static String MAIN_FROM_JAR = "class,load.*com.bars.Main.*[.]jar"; + private static String MAIN_FROM_CDS = "class,load.*com.bars.Main.*shared objects file"; + private static String MAIN_FROM_MODULE = "class,load.*com.bars.Main.*mody/com.bars"; + private static String TEST_FROM_JAR = "class,load.*com.foos.Test.*[.]jar"; + private static String TEST_FROM_CDS = "class,load.*com.foos.Test.*shared objects file"; + private static String MAP_FAILED = "Unable to use shared archive"; + private static String PATH_SEPARATOR = File.pathSeparator; + private static String appClasses[] = {MAIN_CLASS, TEST_CLASS}; + private static String prefix[] = {"-Djava.class.path=", "-Xlog:cds,class+load,class+path=info"}; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE), + null); + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE), + MODS_DIR.resolve(MAIN_MODULE), + MODS_DIR.toString()); + + libsDir = Files.createTempDirectory(USER_DIR, PATH_LIBS); + mainJar = libsDir.resolve(MAIN_MODULE + ".jar"); + testJar = libsDir.resolve(TEST_MODULE + ".jar"); + + // modylibs contains both modules com.foos.jar, com.bars.jar + // build com.foos.jar + String classes = MODS_DIR.resolve(TEST_MODULE).toString(); + JarBuilder.createModularJar(testJar.toString(), classes, TEST_CLASS); + + // build com.bars.jar + classes = MODS_DIR.resolve(MAIN_MODULE).toString(); + JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS); + + dupDir = Files.createTempDirectory(USER_DIR, DUP_LIBS); + dupJar = dupDir.resolve(DUP_MODULE + ".jar"); + Files.copy(testJar, dupJar, StandardCopyOption.REPLACE_EXISTING); + + badJar = libsDir.resolve(MAIN_MODULE + ".JAR"); + Files.copy(mainJar, badJar, StandardCopyOption.REPLACE_EXISTING); + } + + public static void buildJmod() throws Exception { + Path jmod = Paths.get(JAVA_HOME, "bin", "jmod"); + jmodDir = Files.createDirectory(Paths.get(USER_DIR.toString() + File.separator + JMOD_DIR.toString())); + OutputAnalyzer output = ProcessTools.executeProcess(jmod.toString(), + "create", + "--class-path", Paths.get(USER_DIR.toString(), MODS_DIR.toString(), TEST_MODULE).toString(), + "--module-version", "1.0", + "--main-class", TEST_CLASS, + jmodDir.toString() + File.separator + TEST_MODULE + ".jmod"); + output.shouldHaveExitValue(0); + } + + public static void main(String... args) throws Exception { + runWithModulePath(); + runWithExplodedModule(); + runWithJmodAndBadJar(); + } + + private static void tty(String... args) { + for (String s : args) { + System.out.print(s + " "); + } + System.out.print("\n"); + } + + public static void runWithModulePath() throws Exception { + // compile the modules and create the modular jar files + buildTestModule(); + // create an archive with the classes in the modules built in the + // previous step + OutputAnalyzer output = TestCommon.createArchive( + null, appClasses, + "--module-path", + libsDir.toString(), + "-m", MAIN_MODULE); + TestCommon.checkDump(output); + + tty("1. run with CDS on, with module path same as dump time"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + libsDir.toString(), // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(FMG_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + + tty("2. run with CDS on, with jar on path"); + TestCommon.run("-Xlog:cds", + "-Xlog:class+load", + "-cp", mainJar.toString() + PATH_SEPARATOR + testJar.toString(), + MAIN_CLASS) + .assertNormalExit(out -> { + out.shouldContain(CLASS_FOUND_MESSAGE) + .shouldMatch(MAIN_FROM_JAR) + .shouldMatch(TEST_FROM_JAR) + .shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldNotContain(FMG_ENABLED); + }); + + tty("3. run with CDS on, with --module-path, with jar should fail"); + TestCommon.run("-Xlog:cds", + "-Xlog:class+load", + "-p", libsDir.toString(), + "-cp", mainJar.toString(), + MAIN_CLASS) + .assertNormalExit(out -> { + out.shouldContain(CLASS_NOT_FOUND_MESSAGE) + .shouldMatch(MAIN_FROM_JAR) + .shouldNotContain(FMG_ENABLED) + .shouldNotContain(OPTIMIZE_ENABLED); + }); + + final String modularJarPath = mainJar.toString() + PATH_SEPARATOR + testJar.toString(); + + tty("4. run with CDS on, with modular jars specified --module-path, should pass"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + modularJarPath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(FMG_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldMatch(MAIN_FROM_CDS); // archived Main class is for module only + }); + + final String extraModulePath = libsDir.toString() + PATH_SEPARATOR + dupDir.toString(); + // create an archive with an extra module which is not referenced + output = TestCommon.createArchive( + null, appClasses, + "--module-path", + extraModulePath, + "-m", MAIN_MODULE); + TestCommon.checkDump(output); + + tty("5. run with CDS on, without the extra module specified in dump time, should pass"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + libsDir.toString(), // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(FMG_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + tty("6. run with CDS on, with the extra module specified in dump time"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + extraModulePath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(FMG_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + + final String extraJarPath = modularJarPath + PATH_SEPARATOR + dupJar.toString(); + + // create an archive by specifying modular jars in the --module-path with an extra module which is not referenced + output = TestCommon.createArchive( + null, appClasses, + "--module-path", + extraJarPath, + "-m", MAIN_MODULE); + TestCommon.checkDump(output); + tty("7. run with CDS on, without the extra module specified in dump time, should pass"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + modularJarPath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(FMG_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + + tty("8. run with CDS on, with the extra module specified in dump time"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + extraJarPath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(FMG_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + tty("9. same as test case 8 but with paths instead of modular jars in the --module-path"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + extraModulePath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(FMG_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + } + + public static void runWithExplodedModule() throws Exception { + // create an archive with an exploded module in the module path. + OutputAnalyzer output = TestCommon.createArchive( + null, appClasses, + "--module-path", + MODS_DIR.toString(), + "-m", MAIN_MODULE + "/" + MAIN_CLASS); + TestCommon.checkDump(output); + + tty("10. run with CDS on, with exploded module in the module path"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + MODS_DIR.toString(), // --module-path + MAIN_MODULE + "/" + MAIN_CLASS) // -m + .assertNormalExit(out -> { + out.shouldContain(FMG_DISABLED) + .shouldMatch(MAIN_FROM_MODULE) // Main class loaded from the exploded module + .shouldContain(CLASS_FOUND_MESSAGE); + }); + } + + public static void runWithJmodAndBadJar() throws Exception { + buildJmod(); + + final String modularJarPath = mainJar.toString() + PATH_SEPARATOR + testJar.toString(); + // create an archive with --module-path com.bars.jar:com.foos.jar + OutputAnalyzer output = TestCommon.createArchive( + null, appClasses, + "--module-path", + modularJarPath, + "-m", MAIN_MODULE); + TestCommon.checkDump(output); + + String runModulePath = mainJar.toString() + PATH_SEPARATOR + + jmodDir.toString() + TEST_MODULE + ".jmod"; + tty("11. run with CDS on, with module path com.bars.jar:com.foos.jmod"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + runModulePath, // --module-path + MAIN_MODULE) // -m + .assertAbnormalExit(out -> { + out.shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldNotContain(FMG_ENABLED) + .shouldContain(FIND_EXCEPTION_MESSAGE); + }); + + runModulePath += PATH_SEPARATOR + testJar.toString(); + tty("12. run with CDS on, with module path com.bars.jar:com.foos.jmod:com.foos.jar"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + runModulePath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(FMG_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldMatch(TEST_FROM_CDS) + .shouldMatch(MAIN_FROM_CDS) + .shouldContain(CLASS_FOUND_MESSAGE); + }); + + runModulePath = badJar.toString() + PATH_SEPARATOR + testJar.toString(); + tty("13. run with CDS on, with module path com.bars.JAR:com.foos.jar"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + runModulePath, // --module-path + TEST_MODULE) // -m + .assertAbnormalExit(out -> { + out.shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldNotContain(FMG_ENABLED) + .shouldMatch(MODULE_NOT_RECOGNIZED); + }); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java index aeb5696830df4..cf6f4cd7fd3d5 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java @@ -24,7 +24,7 @@ /** * @test - * @requires vm.cds & !vm.graal.enabled + * @requires vm.cds & !vm.graal.enabled & vm.cds.write.archived.java.heap * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds * @run driver OptimizeModuleHandlingTest * @summary test module path changes for optimization of @@ -64,8 +64,8 @@ public class OptimizeModuleHandlingTest { private static String CLASS_FOUND_MESSAGE = "com.foos.Test found"; private static String CLASS_NOT_FOUND_MESSAGE = "java.lang.ClassNotFoundException: com.foos.Test"; - private static String OPTIMIZE_ENABLED = "optimized module handling: enabled"; - private static String OPTIMIZE_DISABLED = "optimized module handling: disabled"; + private static String OPTIMIZE_ENABLED = "] optimized module handling: enabled"; + private static String OPTIMIZE_DISABLED = "] optimized module handling: disabled"; private static String MAIN_FROM_JAR = "class,load.*com.bars.Main.*[.]jar"; private static String MAIN_FROM_CDS = "class,load.*com.bars.Main.*shared objects file"; private static String TEST_FROM_JAR = "class,load.*com.foos.Test.*[.]jar"; @@ -154,14 +154,14 @@ public static void runWithModulePath(String... extraRuntimeArgs) throws Exceptio // Following 5 - 10 test with CDS on tty("5. run with CDS on, with module path"); - String prefix[] = {"-Djava.class.path=", "-Xlog:cds", "-Xlog:class+load"}; + String prefix[] = {"-Djava.class.path=", "-Xlog:cds,class+load,class+path=info"}; TestCommon.runWithModules(prefix, null, // --upgrade-module-path libsDir.toString(), // --module-path MAIN_MODULE) // -m .assertNormalExit(out -> { - out.shouldNotContain(OPTIMIZE_ENABLED) - .shouldContain(OPTIMIZE_DISABLED) + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) .shouldMatch(MAIN_FROM_CDS) // // archived Main class is for module only .shouldContain(CLASS_FOUND_MESSAGE); }); @@ -174,8 +174,8 @@ public static void runWithModulePath(String... extraRuntimeArgs) throws Exceptio out.shouldContain(CLASS_FOUND_MESSAGE) .shouldMatch(MAIN_FROM_CDS) .shouldMatch(TEST_FROM_CDS) - .shouldContain(OPTIMIZE_DISABLED) - .shouldNotContain(OPTIMIZE_ENABLED); + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(OPTIMIZE_DISABLED); }); tty("7. run with CDS on, with jar on path"); TestCommon.run("-Xlog:cds", @@ -231,7 +231,6 @@ public static void runWithModulePath(String... extraRuntimeArgs) throws Exceptio MAIN_CLASS) .assertAbnormalExit(out -> { out.shouldNotContain(CLASS_FOUND_MESSAGE) - .shouldContain(OPTIMIZE_DISABLED) // mapping info .shouldContain("shared class paths mismatch"); }); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java index 6de08da4673cb..004cc7bb5dbbd 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java @@ -53,9 +53,9 @@ */ /** - * @test id=custom-cl-zgc-singlegen + * @test id=custom-cl-zgc * @requires vm.cds.custom.loaders - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @summary Test dumptime_table entries are removed with zgc eager class unloading * @bug 8274935 * @library /test/lib @@ -69,23 +69,6 @@ * @run main/othervm/timeout=180 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicLoaderConstraintsTest custom-zgc */ -/** - * @test id=custom-cl-zgc-generational - * @requires vm.cds.custom.loaders - * @requires vm.gc.ZGenerational - * @summary Test dumptime_table entries are removed with zgc eager class unloading - * @bug 8274935 - * @library /test/lib - * /test/hotspot/jtreg/runtime/cds/appcds - * /test/hotspot/jtreg/runtime/cds/appcds/test-classes - * /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive - * @modules java.base/jdk.internal.misc - * jdk.httpserver - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=180 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicLoaderConstraintsTest custom-zgc-generational - */ - import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import jdk.test.lib.Asserts; @@ -118,12 +101,10 @@ public class DynamicLoaderConstraintsTest extends DynamicArchiveTestBase { */ static boolean useCustomLoader; static boolean useZGC; - static boolean useZGenerational; public static void main(String[] args) throws Exception { useCustomLoader = (args.length != 0); - useZGenerational = (args.length != 0 && args[0].equals("custom-zgc-generational")); - useZGC = useZGenerational || (args.length != 0 && args[0].equals("custom-zgc")); + useZGC = (args.length != 0 && args[0].equals("custom-zgc")); runTest(DynamicLoaderConstraintsTest::doTest); } @@ -150,7 +131,7 @@ static void doTest(boolean errorInDump) throws Exception { for (int i = 1; i <= 3; i++) { System.out.println("========================================"); System.out.println("errorInDump: " + errorInDump + ", useCustomLoader: " + useCustomLoader + - ", useZGC: " + useZGC + ", ZGenerational: " + useZGenerational + ", case: " + i); + ", useZGC: " + useZGC + ", case: " + i); System.out.println("========================================"); String topArchiveName = getNewArchiveName(); String testCase = Integer.toString(i); @@ -164,10 +145,9 @@ static void doTest(boolean errorInDump) throws Exception { if (useCustomLoader) { if (useZGC) { - String zGenerational = "-XX:" + (useZGenerational ? "+" : "-") + "ZGenerational"; // Add options to force eager class unloading. cmdLine = TestCommon.concat(cmdLine, "-cp", loaderJar, - "-XX:+UseZGC", zGenerational, "-XX:ZCollectionInterval=0.01", + "-XX:+UseZGC", "-XX:ZCollectionInterval=0.01", loaderMainClass, appJar); setBaseArchiveOptions("-XX:+UseZGC", "-Xlog:cds"); } else { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineBasicTest.java b/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineBasicTest.java index 81d6e20321ec0..acbd0c948bef2 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineBasicTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineBasicTest.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 @@ -47,7 +47,8 @@ public class RedefineBasicTest { "jdk/test/lib/compiler/InMemoryJavaCompiler", "jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper", "jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper$1", - "jdk/test/lib/compiler/InMemoryJavaCompiler$MemoryJavaFileObject" + "jdk/test/lib/compiler/InMemoryJavaCompiler$SourceFile", + "jdk/test/lib/compiler/InMemoryJavaCompiler$ClassFile" }; public static void main(String[] args) throws Exception { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineRunningMethods_Shared.java b/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineRunningMethods_Shared.java index d84593596043d..039aaef11cd13 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineRunningMethods_Shared.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineRunningMethods_Shared.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 @@ -48,7 +48,8 @@ public class RedefineRunningMethods_Shared { "jdk/test/lib/compiler/InMemoryJavaCompiler", "jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper", "jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper$1", - "jdk/test/lib/compiler/InMemoryJavaCompiler$MemoryJavaFileObject" + "jdk/test/lib/compiler/InMemoryJavaCompiler$SourceFile", + "jdk/test/lib/compiler/InMemoryJavaCompiler$ClassFile" }; public static void main(String[] args) throws Exception { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java index 2ad257476d0fb..36914b7de2536 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java @@ -108,9 +108,12 @@ public static void test(String[] args_ignored) throws Exception { testDump(1, "-XX:+UseZGC", "-XX:-UseCompressedOops", null, false); } - // Dump heap objects with ParallelGC and SerialGC + // Dump heap objects with Parallel, Serial, Shenandoah GC testDump(2, "-XX:+UseParallelGC", "", "", false); testDump(3, "-XX:+UseSerialGC", "", "", false); + if (GC.Shenandoah.isSupported()) { + testDump(4, "-XX:+UseShenandoahGC", "", "", false); + } // Explicitly archive with compressed oops, run without. testDump(5, "-XX:+UseG1GC", "-XX:+UseCompressedOops", null, false); diff --git a/test/hotspot/jtreg/runtime/logging/DefaultLogDecoratorsTest.java b/test/hotspot/jtreg/runtime/logging/DefaultLogDecoratorsTest.java new file mode 100644 index 0000000000000..c237414562226 --- /dev/null +++ b/test/hotspot/jtreg/runtime/logging/DefaultLogDecoratorsTest.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 + * @requires vm.flagless + * @summary Running -Xlog with tags which have disabled default decorators should not yield decorated logs + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver DefaultLogDecoratorsTest + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.Platform; +import jdk.test.lib.process.ProcessTools; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.regex.Pattern; +import java.util.List; +import java.util.Arrays; +import java.util.ArrayList; + +public class DefaultLogDecoratorsTest { + private static Pattern DECORATED_LINE = Pattern.compile("(\\[.+\\])+ .*"); + + private static void doTest(boolean shouldHave, String... xlog) throws Exception { + List argsList = new ArrayList(Arrays.asList(xlog)); + argsList.add(InnerClass.class.getName()); + String[] args = argsList.toArray(new String[0]); + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + List allLines = Files.readAllLines(Path.of("decorators.log")); + for (String line : allLines) { + if (DECORATED_LINE.matcher(line).find() == !shouldHave) { + throw new RuntimeException("Logging should " + (shouldHave ? "" : "not ") + "contain decorators!"); + } + } + } + + public static void main(String[] args) throws Exception { + // JIT inlining logging, as per defaults, shall have all decorators disabled + doTest(false, "-Xlog:jit+inlining*=trace:decorators.log"); + + // If decorators are specified, the defaults are not taken into account + doTest(true, "-Xlog:jit+inlining*=trace:decorators.log:time"); + + // Even if decorators are only supplied for another tag(s), the defaults are not taken into account + doTest(true, "-Xlog:jit+inlining*=trace:decorators.log", "-Xlog:gc*=info:decorators.log:time"); + + // Defaults are not taken into account also when another tag implicitly imposes the "standard" defaults + doTest(true, "-Xlog:jit+inlining*=trace:decorators.log", "-Xlog:gc*=info:decorators.log"); + + // Other logging shall not be affected by a tag with defaults + doTest(true, "-Xlog:gc*=trace:decorators.log"); + } + + public static class InnerClass { + public static void main(String[] args) throws Exception { + System.out.println("DefaultLogDecorators test"); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/attach/AttachAPIv2/CompatTest.java b/test/hotspot/jtreg/serviceability/attach/AttachAPIv2/CompatTest.java new file mode 100644 index 0000000000000..444b87bb6eaed --- /dev/null +++ b/test/hotspot/jtreg/serviceability/attach/AttachAPIv2/CompatTest.java @@ -0,0 +1,104 @@ +/* + * 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 + * @summary Basic compatibility test for Attach API v2 + * @bug 8219896 + * @library /test/lib + * @modules jdk.attach/sun.tools.attach + * + * @run main/othervm -Xlog:attach=trace CompatTest + * @run main/othervm -Xlog:attach=trace -Djdk.attach.compat=true CompatTest + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; + +import com.sun.tools.attach.VirtualMachine; +import sun.tools.attach.HotSpotVirtualMachine; + +import jdk.test.lib.apps.LingeredApp; + +public class CompatTest { + + public static void main(String[] args) throws Exception { + // if the test (client part) in the "compat" mode + boolean clientCompat = "true".equals(System.getProperty("jdk.attach.compat")); + System.out.println("Client is in compat mode: " + clientCompat); + LingeredApp app = null; + try { + app = LingeredApp.startApp("-Xlog:attach=trace"); + test(app, clientCompat); + } finally { + LingeredApp.stopApp(app); + } + + try { + app = LingeredApp.startApp("-Xlog:attach=trace", "-Djdk.attach.compat=true"); + // target VM in "compat" mode, always expect failure + test(app, true); + } finally { + LingeredApp.stopApp(app); + } + + } + + // The test uses HotSpotVirtualMachine.setFlag method with long flag value. + // For attach API v1 an exception is expected to be thrown (argument cannot be longer than 1024 characters). + private static String flagName = "HeapDumpPath"; + // long for v1 + private static String flagValue = "X" + "A".repeat(1024) + "X"; + + private static void test(LingeredApp app, boolean expectFailure) throws Exception { + System.out.println("======== Start ========"); + + HotSpotVirtualMachine vm = (HotSpotVirtualMachine)VirtualMachine.attach(String.valueOf(app.getPid())); + + BufferedReader replyReader = null; + try { + replyReader = new BufferedReader(new InputStreamReader( + vm.setFlag(flagName, flagValue))); + + if (expectFailure) { + throw new RuntimeException("No expected exception is thrown"); + } + + String line; + while ((line = replyReader.readLine()) != null) { + System.out.println("setFlag reply: " + line); + } + replyReader.close(); + + } catch (IOException ex) { + System.out.println("OK: setFlag thrown expected exception:"); + ex.printStackTrace(System.out); + } finally { + vm.detach(); + } + + System.out.println("======== End ========"); + System.out.println(); + } +} diff --git a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpCompressedTest.java b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpCompressedTest.java index 1e6d99a504866..3a960cc8c7d37 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpCompressedTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpCompressedTest.java @@ -71,27 +71,15 @@ */ /* - * @test id=ZSinglegen - * @requires vm.gc.ZSinglegen + * @test id=Z + * @requires vm.gc.Z * @summary Test of diagnostic command GC.heap_dump with gzipped output (Z GC) * @library /test/lib * @modules java.base/jdk.internal.misc * java.compiler * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational HeapDumpCompressedTest - */ - -/* - * @test id=ZGenerational - * @requires vm.gc.ZGenerational - * @summary Test of diagnostic command GC.heap_dump with gzipped output (Z GC) - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.compiler - * java.management - * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational HeapDumpCompressedTest + * @run main/othervm -XX:+UseZGC HeapDumpCompressedTest */ /* diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/NotifyFramePopStressTest/NotifyFramePopStressTest.java b/test/hotspot/jtreg/serviceability/jvmti/events/NotifyFramePopStressTest/NotifyFramePopStressTest.java new file mode 100644 index 0000000000000..8240d943cd42f --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/NotifyFramePopStressTest/NotifyFramePopStressTest.java @@ -0,0 +1,137 @@ +/* + * 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 8340698 + * @summary JVMTI FRAME_POP event is sometimes missed if NotifyFramePop is called as a method is returning + * @requires vm.jvmti + * @library /test/lib + * @compile NotifyFramePopStressTest.java + * @run main/othervm/native -agentlib:NotifyFramePopStressTest NotifyFramePopStressTest + */ + +import jtreg.SkippedException; + +public class NotifyFramePopStressTest { + static volatile boolean done = false; + + public static void main(String args[]) { + if (!canGenerateFramePopEvents()) { + throw new SkippedException("FramePop event is not supported"); + } + Thread testThread = Thread.currentThread(); + Thread controlThread = new Thread(() -> control(testThread), "Control Thread"); + + setFramePopNotificationMode(testThread); + controlThread.start(); + sleep(10); + + for (int i = 0; i < 10*1000; i++) { + foo(); + bar(); + } + done = true; + + try { + controlThread.join(); + } catch (InterruptedException e) { + } + + if (failed()) { + throw new RuntimeException("Test FAILED: see log for details"); + } else { + log("Test PASSED"); + } + } + + private static void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + } + } + + private static void control(Thread thread) { + int notifyCount = 0; + + log("control has started"); + while (!done) { + suspend(thread); + if (done) { + // Double check after suspending the thread. We don't want to do the notify + // if the main thread thinks it is done. An untimely notify during the + // join() call will result in a deadlock. + resume(thread); + break; + } + if (notifyFramePop(thread)) { + notifyCount++; + log("control incremented notifyCount to " + notifyCount); + } + resume(thread); + int waitCount = 0; + while (notifyCount != getPopCount()) { + sleep(1); + waitCount++; + if (waitCount > 1000) { + break; + } + } + if (waitCount > 100) { + log("About to fail. notifyCount=" + notifyCount + " getPopCount()=" + getPopCount()); + throw new RuntimeException("Test FAILED: Waited too long for notify: " + waitCount); + } + } + log("control has finished: " + notifyCount); + } + + private native static void suspend(Thread thread); + private native static void resume(Thread thread); + private native static int getPopCount(); + private native static boolean failed(); + private native static boolean canGenerateFramePopEvents(); + private native static void setFramePopNotificationMode(Thread thread); + private native static boolean notifyFramePop(Thread thread); + + private static void log(String msg) { + System.out.println(msg); + } + + private static int fetchIntFoo() { + return 13; + } + + private static int fetchIntBar() { + return 33; + } + + private static int foo() { + return fetchIntFoo(); + } + + private static int bar() { + return fetchIntBar(); + } +} + diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/NotifyFramePopStressTest/libNotifyFramePopStressTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/events/NotifyFramePopStressTest/libNotifyFramePopStressTest.cpp new file mode 100644 index 0000000000000..e4206c2766a70 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/NotifyFramePopStressTest/libNotifyFramePopStressTest.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "jvmti.h" +#include "jvmti_common.hpp" + +#ifdef __cplusplus +extern "C" { +#endif + +static jvmtiEnv *jvmti; +static jvmtiCapabilities caps; +static jvmtiEventCallbacks callbacks; +static volatile jint pop_count; +static char* volatile last_notify_method; +static volatile jboolean failed = JNI_FALSE; +static jboolean seenMain = JNI_FALSE; + +static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); + +JNIEXPORT +jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + +JNIEXPORT +jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + +JNIEXPORT +jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { + return JNI_VERSION_9; +} + +static void JNICALL +FramePop(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, + jmethodID method, jboolean wasPoppedByException) { + jvmtiError err; + jclass cls = nullptr; + char* csig = nullptr; + char* name = nullptr; + + err = jvmti->GetMethodDeclaringClass(method, &cls); + check_jvmti_status(jni, err, "FramePop: Failed in JVMTI GetMethodDeclaringClass"); + + err = jvmti->GetClassSignature(cls, &csig, nullptr); + check_jvmti_status(jni, err, "FramePop: Failed in JVMTI GetClassSignature"); + + name = get_method_name(jvmti, jni, method); + LOG("FramePop(%d) event from method: %s %s\n", pop_count + 1, csig, name); + + if (strcmp(name, "main") != 0) { // ignore FRAME_POP for main that comes in as the test exits + if (strcmp(name, (char*)last_notify_method) != 0) { + LOG("ERROR: FramePop event is for wrong method: expected %s, got %s\n", last_notify_method, name); + failed = JNI_TRUE; + } + } + pop_count++; + deallocate(jvmti, jni, csig); + deallocate(jvmti, jni, name); +} + +static +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { + jint res; + jvmtiError err; + + res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_9); + if (res != JNI_OK || jvmti == nullptr) { + LOG("GetEnv(JVMTI_VERSION_9) failed error(%d)", res); + return JNI_ERR; + } + err = jvmti->GetPotentialCapabilities(&caps); + check_jvmti_error(err, "Agent: GetPotentialCapabilities failed"); + + err = jvmti->AddCapabilities(&caps); + check_jvmti_error(err, "Agent: AddCapabilities failed"); + + err = jvmti->GetCapabilities(&caps); + check_jvmti_error(err, "Agent: GetCapabilities failed"); + + if (caps.can_generate_frame_pop_events) { + callbacks.FramePop = &FramePop; + err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); + check_jvmti_error(err, "Agent: SetEventCallbacks failed"); + } + return JNI_OK; +} + +JNIEXPORT jboolean JNICALL +Java_NotifyFramePopStressTest_canGenerateFramePopEvents(JNIEnv *env, jclass cls) { + return caps.can_generate_frame_pop_events ? JNI_TRUE : JNI_FALSE; +} + +JNIEXPORT void JNICALL +Java_NotifyFramePopStressTest_setFramePopNotificationMode(JNIEnv *env, jclass cl, jthread thread) { + set_event_notification_mode(jvmti, env, JVMTI_ENABLE, JVMTI_EVENT_FRAME_POP, thread); +} + +/* + * Call NotifyFramePop on the current frame. + */ +JNIEXPORT jboolean JNICALL +Java_NotifyFramePopStressTest_notifyFramePop(JNIEnv *jni, jclass cls, jthread thread) { + jmethodID method; + jlocation loc; + char* name; + jvmtiError err; + jboolean isMain; + + err = jvmti->GetFrameLocation(thread, 0, &method, &loc); + check_jvmti_status(jni, err, "notifyFramePop: Failed in JVMTI GetFrameLocation"); + + name = get_method_name(jvmti, jni, method); + + // We only want to do a NotifyFramePop once for the main method. The sole purpose is + // to force the thread into interpOnly mode, which seems to help the test's timing + // in a way that makes it more likely to reproduce the issue. + isMain = (strcmp(name, "main") == 0); + if (isMain) { + if (seenMain) { + deallocate(jvmti, jni, name); + return JNI_FALSE; // Only do NotifyFramePop once for main() + } else { + seenMain = JNI_TRUE; + } + } + + err= jvmti->NotifyFramePop(thread, 0); + if (err == JVMTI_ERROR_OPAQUE_FRAME || err == JVMTI_ERROR_DUPLICATE) { + //LOG("\nNotifyFramePop for method %s returned acceptable error: %s\n", name, TranslateError(err)); + deallocate(jvmti, jni, name); + return JNI_FALSE; + } + check_jvmti_status(jni, err, "notifyFramePop: Failed in JVMTI notifyFramePop"); + LOG("\nNotifyFramePop called for method %s\n", name); + + if (isMain) { + LOG("notifyFramePop not counting main method\n"); + deallocate(jvmti, jni, name); + return JNI_FALSE; + } else { + deallocate(jvmti, jni, last_notify_method); + last_notify_method = name; + return JNI_TRUE; + } +} + +JNIEXPORT void JNICALL +Java_NotifyFramePopStressTest_suspend(JNIEnv *jni, jclass cls, jthread thread) { + suspend_thread(jvmti, jni, thread); +} + +JNIEXPORT void JNICALL +Java_NotifyFramePopStressTest_resume(JNIEnv *jni, jclass cls, jthread thread) { + resume_thread(jvmti, jni, thread); +} + +JNIEXPORT jint JNICALL +Java_NotifyFramePopStressTest_getPopCount(JNIEnv *env, jclass cls) { + return pop_count; +} + +JNIEXPORT jboolean JNICALL +Java_NotifyFramePopStressTest_failed(JNIEnv *env, jclass cls) { + return failed; +} + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/serviceability/jvmti/thread/GetFrameCount/framecnt01/framecnt01.java b/test/hotspot/jtreg/serviceability/jvmti/thread/GetFrameCount/framecnt01/framecnt01.java index 8a7177ec25d5f..221363f56216f 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/thread/GetFrameCount/framecnt01/framecnt01.java +++ b/test/hotspot/jtreg/serviceability/jvmti/thread/GetFrameCount/framecnt01/framecnt01.java @@ -79,7 +79,7 @@ public static void main(String args[]) throws Exception { } // this is too fragile, implementation can change at any time. - checkFrames(vThread1, false, 13); + checkFrames(vThread1, false, 11); LockSupport.unpark(vThread1); vThread1.join(); diff --git a/test/hotspot/jtreg/gc/x/TestDeprecated.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/CheckHiddenFrames/CheckHiddenFrames.java similarity index 58% rename from test/hotspot/jtreg/gc/x/TestDeprecated.java rename to test/hotspot/jtreg/serviceability/jvmti/vthread/CheckHiddenFrames/CheckHiddenFrames.java index 39b0318d52b99..1b6d409e30b4c 100644 --- a/test/hotspot/jtreg/gc/x/TestDeprecated.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/CheckHiddenFrames/CheckHiddenFrames.java @@ -21,30 +21,36 @@ * questions. */ -package gc.x; - /* - * @test TestDeprecated - * @requires vm.gc.ZSinglegen - * @summary Test ZGenerational Deprecated - * @library /test/lib - * @run driver gc.x.TestDeprecated + * @test + * @bug 8341273 + * @summary Verifies JVMTI properly hides frames which are in VTMS transition + * @run main/othervm/native -agentlib:CheckHiddenFrames CheckHiddenFrames */ -import java.util.LinkedList; -import jdk.test.lib.process.ProcessTools; +public class CheckHiddenFrames { + static native boolean checkHidden(Thread t); -public class TestDeprecated { - static class Test { - public static void main(String[] args) throws Exception {} + static void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + } } + public static void main(String[] args) throws Exception { - ProcessTools.executeLimitedTestJava("-XX:+UseZGC", - "-XX:-ZGenerational", - "-Xlog:gc+init", - Test.class.getName()) - .shouldContain("Option ZGenerational was deprecated") - .shouldContain("Using deprecated non-generational mode") - .shouldHaveExitValue(0); + Thread thread = Thread.startVirtualThread(CheckHiddenFrames::test); + System.out.println("Started virtual thread: " + thread); + + if (!checkHidden(thread)) { + thread.interrupt(); + throw new RuntimeException("CheckHiddenFrames failed!"); + } + thread.interrupt(); + thread.join(); + } + + static void test() { + sleep(1000000); } } diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/CheckHiddenFrames/libCheckHiddenFrames.cpp b/test/hotspot/jtreg/serviceability/jvmti/vthread/CheckHiddenFrames/libCheckHiddenFrames.cpp new file mode 100644 index 0000000000000..50f930b573135 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/CheckHiddenFrames/libCheckHiddenFrames.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include "jvmti.h" +#include "jvmti_common.hpp" + +extern "C" { + +const int MAX_COUNT = 50; +static jvmtiEnv *jvmti = nullptr; + +static char* +get_frame_method_name(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread, jint depth) { + jmethodID method = nullptr; + jlocation location = 0; + + jvmtiError err = jvmti->GetFrameLocation(thread, 0, &method, &location); + check_jvmti_status(jni, err, "get_method_name_at_depth: error in JVMTI GetFrameLocation"); + + return get_method_name(jvmti, jni, method); +} + +static bool +method_must_be_hidden(char* mname) { + return strcmp(mname, "yield") == 0 || + strcmp(mname, "yield0") == 0; +} + +static jboolean +check_top_frames_location(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) { + jboolean status = JNI_TRUE; + + for (int depth = 0; depth < 2; depth++) { + char* mname = get_frame_method_name(jvmti, jni, thread, depth); + + if (method_must_be_hidden(mname)) { + LOG("Failed: GetFrameLocation returned info for frame expected to be hidden: frame[%d]=%s\n", depth, mname); + status = JNI_FALSE; + } + deallocate(jvmti, jni, mname); + } + return status; +} + +static jboolean +check_top_frames_in_stack_trace(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) { + jboolean status = JNI_TRUE; + jvmtiFrameInfo frameInfo[MAX_COUNT]; + jint count1 = 0; + jint count2 = 0; + + jvmtiError err = jvmti->GetStackTrace(thread, 0, MAX_COUNT, frameInfo, &count1); + check_jvmti_status(jni, err, "check_top_frames_in_stack_trace: error in JVMTI GetStackTrace"); + + for (int depth = 0; depth < 2; depth++) { + char* mname = get_method_name(jvmti, jni, frameInfo[depth].method); + + if (method_must_be_hidden(mname)) { + LOG("Failed: GetStackTrace returned info for frame expected to be hidden: frame[%d]=%s\n", depth, mname); + status = JNI_FALSE; + } + deallocate(jvmti, jni, mname); + } + + err = jvmti->GetFrameCount(thread, &count2); + check_jvmti_status(jni, err, "check_top_frames_in_stack_trace: error in JVMTI GetFrameCount"); + + if (count1 != count2) { + LOG("Failed: frame counts returned by GetStackTrace and GetFrameCount do not match: %d!=%d\n", count1, count2); + status = JNI_FALSE; + } + return status; +} + +JNIEXPORT jboolean JNICALL +Java_CheckHiddenFrames_checkHidden(JNIEnv *jni, jclass clazz, jthread thread) { + jboolean status = JNI_TRUE; + + wait_for_state(jvmti, jni, thread, JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT); + print_stack_trace(jvmti, jni, thread); + + + if (!check_top_frames_location(jvmti, jni, thread)) { + status = JNI_FALSE; + } + if (!check_top_frames_in_stack_trace(jvmti, jni, thread)) { + status = JNI_FALSE; + } + return status; +} + +extern JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + LOG("Agent_OnLoad started\n"); + if (jvm->GetEnv((void **)(&jvmti), JVMTI_VERSION) != JNI_OK) { + return JNI_ERR; + } + LOG("Agent_OnLoad finished\n"); + return JNI_OK; +} + +} // extern "C" diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java index b991610badb9f..bcf9349857462 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java @@ -103,7 +103,7 @@ private static void checkForTruncation(String longConstantOutput) throws Excepti String arch = System.getProperty("os.arch"); if (arch.equals("amd64") || arch.equals("i386") || arch.equals("x86")) { // Expected value obtained from the CPU_SHA definition in vm_version_x86.hpp - checkLongValue("VM_Version::CPU_SHA", + checkLongValue("VM_Version::CPU_SHA ", longConstantOutput, 17179869184L); } diff --git a/test/hotspot/jtreg/serviceability/sa/TestDebugInfoDecode.java b/test/hotspot/jtreg/serviceability/sa/TestDebugInfoDecode.java index 257f950b12f96..946189f11958a 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestDebugInfoDecode.java +++ b/test/hotspot/jtreg/serviceability/sa/TestDebugInfoDecode.java @@ -43,7 +43,7 @@ * jdk.hotspot.agent/sun.jvm.hotspot.code * jdk.hotspot.agent/sun.jvm.hotspot.debugger * jdk.hotspot.agent/sun.jvm.hotspot.runtime - * @run main/othervm/timeout=2400 -Xmx1g -Xcomp TestDebugInfoDecode + * @run driver TestDebugInfoDecode */ public class TestDebugInfoDecode { @@ -107,7 +107,7 @@ public static void main (String... args) throws Exception { if (args == null || args.length == 0) { try { theApp = new LingeredApp(); - LingeredApp.startApp(theApp); + LingeredApp.startApp(theApp, "-Xcomp"); createAnotherToAttach(theApp.getPid()); } finally { LingeredApp.stopApp(theApp); 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 df4f9063586f4..e2c7230bc0dc9 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 @@ -304,7 +304,17 @@ private String[] cmd(long classStart, long classStop) { "-XX:+StressMacroExpansion", "-XX:+StressIncrementalInlining", // StressSeed is uint - "-XX:StressSeed=" + rng.nextInt(Integer.MAX_VALUE))); + "-XX:StressSeed=" + rng.nextInt(Integer.MAX_VALUE), + // Do not fail on huge methods where StressGCM makes register + // allocation allocate lots of memory + "-XX:CompileCommand=memlimit,*.*,0")); + + // Use this stress mode 10% of the time as it could make some long-running compilations likely to abort. + if (rng.nextInt(10) == 0) { + Args.add("-XX:+StressBailout"); + Args.add("-XX:StressBailoutMean=100000"); + Args.add("-XX:+CaptureBailoutInformation"); + } for (String arg : CTW_EXTRA_ARGS.split(",")) { Args.add(arg); diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/CombinedJavaJasmExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/CombinedJavaJasmExample.java new file mode 100644 index 0000000000000..565c92c1b7068 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/CombinedJavaJasmExample.java @@ -0,0 +1,114 @@ +/* + * 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 + * @summary Example test to use the Compile Framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.examples.CombinedJavaJasmExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; + +/** + * This test shows a compilation of multiple Java and Jasm source code files. + * In this example, the classes even reference each other. + */ +public class CombinedJavaJasmExample { + + // Generate a source jasm file as String + public static String generateJasm() { + return """ + package p/xyz; + + super public class XYZJasm { + public static Method test:"(I)I" + stack 20 locals 20 + { + iload_0; + iconst_2; + imul; + invokestatic Method p/xyz/XYZJava."mul3":"(I)I"; + ireturn; + } + + public static Method mul5:"(I)I" + stack 20 locals 20 + { + iload_0; + ldc 5; + imul; + ireturn; + } + } + """; + } + + // Generate a source java file as String + public static String generateJava() { + return """ + package p.xyz; + + public class XYZJava { + public static int test(int i) { + return p.xyz.XYZJasm.mul5(i * 7); + } + + public static int mul3(int i) { + return i * 3; + } + } + """; + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Generate files. + comp.addJasmSourceCode("p.xyz.XYZJasm", generateJasm()); + comp.addJavaSourceCode("p.xyz.XYZJava", generateJava()); + + // Compile the source files. + comp.compile(); + + test(comp, "p.xyz.XYZJasm", "test", 11, 11 * 2 * 3); + test(comp, "p.xyz.XYZJava", "test", 13, 13 * 7 * 5); + + System.out.println("Success."); + } + + public static void test(CompileFramework comp, String className, String methodName, int input, int expected) { + Object ret = comp.invoke(className, methodName, new Object[] {input}); + + // Extract return value of invocation, verify its value. + int i = (int)ret; + System.out.println("Result of call: " + i + " vs expected: " + expected); + if (i != expected) { + throw new RuntimeException("wrong value: " + i); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/IRFrameworkJavaExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/IRFrameworkJavaExample.java new file mode 100644 index 0000000000000..11b8828d7530d --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/IRFrameworkJavaExample.java @@ -0,0 +1,156 @@ +/* + * 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 + * @summary Example test to use the Compile Framework together with the IR Framework (i.e. TestFramework). + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @compile ../../../compiler/lib/ir_framework/TestFramework.java + * @run driver compile_framework.examples.IRFrameworkJavaExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; +import jdk.test.lib.Utils; +import jdk.test.lib.Platform; +import java.lang.reflect.InvocationTargetException; + +/** + * This test shows that the IR verification can be done on code compiled by the Compile Framework. + * The "@compile" command for JTREG is required so that the IRFramework is compiled, other javac + * might not compile it because it is not present in the class, only in the dynamically compiled + * code. + *

            + * Additionally, we must set the classpath for the Test-VM, so that it has access to all compiled + * classes (see {@link CompileFramework#getEscapedClassPathOfCompiledClasses}). + */ +public class IRFrameworkJavaExample { + + public static void main(String[] args) { + testX1(); + testX2(); + } + + // Generate a source java file as String + public static String generateX1(CompileFramework comp) { + return String.format(""" + import compiler.lib.ir_framework.*; + + public class X1 { + public static void main(String args[]) { + TestFramework framework = new TestFramework(X1.class); + framework.addFlags("-classpath", "%s"); + framework.start(); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0"}, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + static float[] test() { + float[] a = new float[1024*8]; + for (int i = 0; i < a.length; i++) { + a[i]++; + } + return a; + } + } + """, comp.getEscapedClassPathOfCompiledClasses()); + } + + static void testX1() { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("X1", generateX1(comp)); + + // Compile the source file. + comp.compile(); + + // X1.main(); + comp.invoke("X1", "main", new Object[] {null}); + } + + // Generate a source java file as String + public static String generateX2(CompileFramework comp) { + // Example with conflicting "@IR" rules -> expect a IRViolationException. + return String.format(""" + import compiler.lib.ir_framework.*; + + public class X2 { + public static void main(String args[]) { + TestFramework framework = new TestFramework(X2.class); + framework.addFlags("-classpath", "%s"); + framework.start(); + } + + @Test + @IR(counts = {IRNode.LOAD, "> 0"}) + @IR(failOn = IRNode.LOAD) + static void test() { + } + } + """, comp.getEscapedClassPathOfCompiledClasses()); + } + + static void testX2() { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("X2", generateX2(comp)); + + // Compile the source file. + comp.compile(); + + // Load the compiled class. + Class c = comp.getClass("X2"); + + // Invoke the "X2.main" method from the compiled and loaded class. + try { + c.getDeclaredMethod("main", new Class[] { String[].class }).invoke(null, new Object[] { null }); + + // Check if IR framework is expected to execute the IR rules. + if (Utils.getTestJavaOpts().length == 0 && Platform.isDebugBuild() && !Platform.isInt() && !Platform.isComp()) { + throw new RuntimeException("IRViolationException expected."); + } else { + System.out.println("Got no IRViolationException, but was also not expected."); + } + } catch (NoSuchMethodException e) { + throw new RuntimeException("No such method:", e); + } catch (IllegalAccessException e) { + throw new RuntimeException("Illegal access:", e); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + if (t == null) { + throw new RuntimeException("IRViolationException expected:", e); + } + if (!t.getClass().getSimpleName().equals("IRViolationException")) { + throw new RuntimeException("IRViolationException expected:", e); + } + System.out.println("Success, we got a IRViolationException."); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJasmExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJasmExample.java new file mode 100644 index 0000000000000..33fe07a53970b --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJasmExample.java @@ -0,0 +1,88 @@ +/* + * 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 + * @summary Example test to use the Compile Framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver comile_framework.examples.MultiFileJasmExample + */ + +package comile_framework.examples; + +import compiler.lib.compile_framework.*; +import java.io.StringWriter; +import java.io.PrintWriter; + +/** + * This test shows a compilation of multiple jasm source code files. + */ +public class MultiFileJasmExample { + + // Generate a source jasm file as String + public static String generate(int i) { + StringWriter writer = new StringWriter(); + PrintWriter out = new PrintWriter(writer); + out.println("package p/xyz;"); + out.println(""); + out.println("super public class XYZ" + i + " {"); + out.println(" public static Method test:\"(I)I\""); + out.println(" stack 20 locals 20"); + out.println(" {"); + out.println(" iload_0;"); + out.println(" iconst_2;"); // every call multiplies by 2, in total 2^10 = 1024 + out.println(" imul;"); + if (i != 0) { + out.println(" invokestatic Method p/xyz/XYZ" + (i-1) + ".\"test\":\"(I)I\";"); + } + out.println(" ireturn;"); + out.println(" }"); + out.println("}"); + return writer.toString(); + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Generate 10 files. + for (int i = 0; i < 10; i++) { + comp.addJasmSourceCode("p.xyz.XYZ" + i, generate(i)); + } + + // Compile the source files. + comp.compile(); + + // Object ret = XYZ9.test(5); + Object ret = comp.invoke("p.xyz.XYZ9", "test", new Object[] { 5 }); + + // Extract return value of invocation, verify its value. + int i = (int)ret; + System.out.println("Result of call: " + i); + if (i != 5 * 1024) { + throw new RuntimeException("wrong value: " + i); + } + System.out.println("Success."); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJavaExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJavaExample.java new file mode 100644 index 0000000000000..e493ebab4e8c8 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJavaExample.java @@ -0,0 +1,81 @@ +/* + * 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 + * @summary Example test to use the Compile Framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.examples.MultiFileJavaExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; +import java.io.StringWriter; +import java.io.PrintWriter; + +/** + * This test shows a compilation of multiple java source code files. + */ +public class MultiFileJavaExample { + + // Generate a source java file as String + public static String generate(int i) { + StringWriter writer = new StringWriter(); + PrintWriter out = new PrintWriter(writer); + out.println("package p.xyz;"); + out.println(""); + out.println("public class XYZ" + i + " {"); + if (i > 0) { + out.println(" public XYZ" + (i - 1) + " xyz = new XYZ" + (i - 1) + "();"); + } + out.println(""); + out.println(" public static Object test() {"); + out.println(" return new XYZ" + i + "();"); + out.println(" }"); + out.println("}"); + return writer.toString(); + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Generate 10 files. + for (int i = 0; i < 10; i++) { + comp.addJavaSourceCode("p.xyz.XYZ" + i, generate(i)); + } + + // Compile the source files. + comp.compile(); + + // Object ret = XYZ9.test(); + Object ret = comp.invoke("p.xyz.XYZ9", "test", new Object[] {}); + + if (!ret.getClass().getSimpleName().equals("XYZ9")) { + throw new RuntimeException("wrong result:" + ret); + } + System.out.println("Success."); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/RunWithFlagsExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/RunWithFlagsExample.java new file mode 100644 index 0000000000000..a67e6e0eb4937 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/RunWithFlagsExample.java @@ -0,0 +1,99 @@ +/* + * 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 + * @summary Example test to use the Compile Framework and run the compiled code with additional flags + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.examples.RunWithFlagsExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +/** + * This test shows how the generated code can be compiled and invoked in a new VM. This allows + * the execution of the code with additional VM flags and options. + *

            + * The new VM must be able to locate the class files of the newly compiled code. For this we + * set the class path using {@link CompileFramework#getEscapedClassPathOfCompiledClasses}. + */ +public class RunWithFlagsExample { + + private static String generate() { + return """ + package p.xyz; + + public class X { + public static void main(String args[]) { + System.out.println("Hello world!"); + System.out.println(System.getProperty("MyMessage", "fail")); + System.err.println(args[0]); + } + } + """; + } + + public static void main(String[] args) throws Exception { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a Java source file. + comp.addJavaSourceCode("p.xyz.X", generate()); + + // Compile the source file. + comp.compile(); + + // Build command line. + String[] command = { + // Set the classpath to include our newly compiled class. + "-classpath", + comp.getEscapedClassPathOfCompiledClasses(), + // Pass additional flags here. + // "-Xbatch" is a harmless VM flag, so this example runs everywhere without issues. + "-Xbatch", + // We can also pass properties like "MyMessage". + "-DMyMessage=hello_world", + "p.xyz.X", + "hello_arg" + }; + + // Execute the command, and capture the output. + // The JTREG Java and VM options are automatically passed to the test VM. + OutputAnalyzer analyzer = ProcessTools.executeTestJava(command); + + // Verify output. + analyzer.shouldHaveExitValue(0); + analyzer.stdoutContains("Hello world!"); + analyzer.stdoutContains("hello_world"); + analyzer.stdoutContains("hello_arg"); + + // Print output to stderr. + analyzer.reportDiagnosticSummary(); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJasmExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJasmExample.java new file mode 100644 index 0000000000000..e01b45e744175 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJasmExample.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 + * @summary Example test to use the Compile Framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.examples.SimpleJasmExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; + +/** + * This test shows a simple compilation of java source code, and its invocation. + */ +public class SimpleJasmExample { + + // Generate a source jasm file as String + public static String generate() { + return """ + super public class XYZ { + public static Method test:"(I)I" + stack 20 locals 20 + { + iload_0; + iconst_2; + imul; + ireturn; + } + } + """; + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + String src = generate(); + comp.addJasmSourceCode("XYZ", src); + + // Compile the source file. + comp.compile(); + + // Object ret = XYZ.test(5); + Object ret = comp.invoke("XYZ", "test", new Object[] {5}); + + // Extract return value of invocation, verify its value. + int i = (int)ret; + System.out.println("Result of call: " + i); + if (i != 10) { + throw new RuntimeException("wrong value: " + i); + } + System.out.println("Success."); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJavaExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJavaExample.java new file mode 100644 index 0000000000000..5e54a6e8a08a6 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJavaExample.java @@ -0,0 +1,73 @@ +/* + * 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 + * @summary Example test to use the Compile Framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.examples.SimpleJavaExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; + +/** + * This test shows a simple compilation of java source code, and its invocation. + */ +public class SimpleJavaExample { + + // Generate a source java file as String + public static String generate() { + return """ + public class XYZ { + public static int test(int i) { + System.out.println("Hello from XYZ.test: " + i); + return i * 2; + } + } + """; + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("XYZ", generate()); + + // Compile the source file. + comp.compile(); + + // Object ret = XYZ.test(5); + Object ret = comp.invoke("XYZ", "test", new Object[] {5}); + + // Extract return value of invocation, verify its value. + int i = (int)ret; + System.out.println("Result of call: " + i); + if (i != 10) { + throw new RuntimeException("wrong value: " + i); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJasmCompilation.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJasmCompilation.java new file mode 100644 index 0000000000000..b5b6f3e104095 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJasmCompilation.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Example test with failing jasm compilation. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.tests.TestBadJasmCompilation + */ + +package compile_framework.tests; + +import compiler.lib.compile_framework.*; + +public class TestBadJasmCompilation { + + // Generate a source jasm file as String + public static String generate() { + return """ + super public class XYZ { + some bad code + } + """; + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJasmSourceCode("XYZ", generate()); + + try { + // Compile the source file. + comp.compile(); + throw new RuntimeException("Expected compilation to fail."); + } catch (CompileFrameworkException e) { + System.out.println("Success, expected compilation to fail."); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJavaCompilation.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJavaCompilation.java new file mode 100644 index 0000000000000..1cb1d79afbcca --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJavaCompilation.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Example test with failing java compilation. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.tests.TestBadJavaCompilation + */ + +package compile_framework.tests; + +import compiler.lib.compile_framework.*; + +public class TestBadJavaCompilation { + + // Generate a source java file as String + public static String generate() { + return """ + public class XYZ { + some bad code + } + """; + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("XYZ", generate()); + + try { + // Compile the source file. + comp.compile(); + throw new RuntimeException("Expected compilation to fail."); + } catch (CompileFrameworkException e) { + System.out.println("Success, expected compilation to fail."); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestConcurrentCompilation.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestConcurrentCompilation.java new file mode 100644 index 0000000000000..1cb902d34e4aa --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestConcurrentCompilation.java @@ -0,0 +1,108 @@ +/* + * 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 + * @summary Example test with multi-threaded use of the CompileFramework. + * Tests that the source and class directories are set up correctly. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.tests.TestConcurrentCompilation + */ + +package compile_framework.tests; + +import compiler.lib.compile_framework.*; + +import java.util.ArrayList; +import java.util.List; + +public class TestConcurrentCompilation { + + // Generate a source java file as String + public static String generate(int i) { + return String.format(""" + public class XYZ { + public static int test() { + return %d; + } + } + """, i); + } + + public static void test(int i) { + System.out.println("Generate and compile XYZ for " + i); + CompileFramework comp = new CompileFramework(); + comp.addJavaSourceCode("XYZ", generate(i)); + comp.compile(); + + // Now, sleep to give the other threads time to compile and store their class-files. + System.out.println("Sleep for " + i); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + System.out.println("Sleep interrupted for " + i); + } + + // Now, hopefully all threads have compiled and stored their class-files. + // We can check if we get the expected result, i.e. the class-file from the current thread. + System.out.println("Run XYZ.test for " + i); + int j = (int)comp.invoke("XYZ", "test", new Object[] {}); + if (i != j) { + System.out.println("Wrong value: " + i + " vs " + j); + throw new RuntimeException("Wrong value: " + i + " vs " + j); + } + System.out.println("Success for " + i); + } + + public static class MyRunnable implements Runnable { + private int i; + + public MyRunnable(int i) { + this.i = i; + } + + public void run() { + TestConcurrentCompilation.test(i); + } + } + + public static void main(String[] args) { + System.out.println("Generating threads:"); + List threads = new ArrayList(); + for (int i = 0; i < 3; i++) { + Thread thread = new Thread(new MyRunnable(i)); + thread.start(); + threads.add(thread); + } + System.out.println("Waiting to join threads:"); + try { + for (Thread thread : threads) { + thread.join(); + } + } catch (InterruptedException e) { + throw new RuntimeException("interrupted", e); + } + System.out.println("Success."); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/GCBarrierIRExample.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/GCBarrierIRExample.java index e0287fc39fe0a..11db83a1b3142 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/GCBarrierIRExample.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/GCBarrierIRExample.java @@ -33,7 +33,7 @@ * @summary Example test that illustrates the use of the IR test framework for * verification of late-expanded GC barriers. * @library /test/lib / - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @run driver ir_framework.examples.GCBarrierIRExample */ @@ -61,7 +61,7 @@ public static void main(String[] args) { // emission, such as ZGC. Because the collector selection flags are not // whitelisted (see IR framework's README.md file), the user (as opposed // to jtreg) needs to set these flags here. - TestFramework.runWithFlags("-XX:+UseZGC", "-XX:+ZGenerational"); + TestFramework.runWithFlags("-XX:+UseZGC"); } @Test diff --git a/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/bytecode/BytecodeGeneratorFactory.java b/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/bytecode/BytecodeGeneratorFactory.java index cad856f553e23..73f74794394ff 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/bytecode/BytecodeGeneratorFactory.java +++ b/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/bytecode/BytecodeGeneratorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ import java.util.Map; import java.util.Random; -import vm.share.InMemoryJavaCompiler; +import jdk.test.lib.compiler.InMemoryJavaCompiler; /** * BytecodeFactory that employs in memory compilation. @@ -44,12 +44,10 @@ public BytecodeGeneratorFactory(long seed) { @Override public Bytecode createBytecode(String className) { - Map sources = new HashMap(); - sources.put(className, sourceGenerator.generateSource(className, + byte[] bytecode = InMemoryJavaCompiler.compile(className, sourceGenerator.generateSource(className, "public static void main() { System.out.println(\"From main method in in-mem-compiled code " + random.nextGaussian() + " + str_bytesToReplace0 str_bytesToReplace1\"); }\n " + "public static int methodForCompilation(Object object) { int i = object.hashCode(); i = i * 2000 / 1994 + 153; return i; }\n")); - byte[] bytecode = InMemoryJavaCompiler.compile(sources).values().iterator().next(); return new Bytecode(className, bytecode); } diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/PhantomReference/phantom001/phantom001.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/PhantomReference/phantom001/phantom001.java index d45adbf4efd1a..9f5fc94221ede 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/PhantomReference/phantom001/phantom001.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/PhantomReference/phantom001/phantom001.java @@ -177,14 +177,15 @@ public void run() { // If referent is finalizable, provoke GCs and wait for finalization. if (type.equals("class")) { progress("Waiting for finalization: " + type); + WhiteBox.getWhiteBox().fullGC(); for (int checks = 0; !finalized && !shouldTerminate(); ++checks) { - // There are scenarios where one WB.fillGC() isn't enough, - // but 10 iterations really ought to be sufficient. + // Wait for up to 10 iterations that the finalizer has been run, + // this ought to be sufficient. Full GCs and other threads might + // starve out the finalizer thread, requiring more waiting. if (checks > 10) { fail("Waiting for finalization: " + type); return; } - WhiteBox.getWhiteBox().fullGC(); // Give some time for finalizer to run. try { Thread.sleep(checks * 100); diff --git a/test/hotspot/jtreg/vmTestbase/jit/escape/LockElision/MatMul/MatMul.java b/test/hotspot/jtreg/vmTestbase/jit/escape/LockElision/MatMul/MatMul.java index cf20b0df8a073..8d1a5fac9aefa 100644 --- a/test/hotspot/jtreg/vmTestbase/jit/escape/LockElision/MatMul/MatMul.java +++ b/test/hotspot/jtreg/vmTestbase/jit/escape/LockElision/MatMul/MatMul.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, 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 @@ -85,7 +85,7 @@ public static void main(String[] args) { } public int run() { - log = new Log(System.out, verbose); + log = new Log(System.out); log.display("Parallel matrix multiplication test"); Matrix a = Matrix.randomMatrix(dim); diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/staticReferences/StaticReferences.java b/test/hotspot/jtreg/vmTestbase/metaspace/staticReferences/StaticReferences.java index ce0dd65c7eebf..7ea901abe06f1 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/staticReferences/StaticReferences.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/staticReferences/StaticReferences.java @@ -60,7 +60,7 @@ import nsk.share.test.Stresser; import nsk.share.test.TestBase; import nsk.share.test.Tests; -import vm.share.InMemoryJavaCompiler; +import jdk.test.lib.compiler.InMemoryJavaCompiler; /** * Test checks that static fields will be initialized in new loaded class. Test performs in loop the following routine: @@ -210,9 +210,7 @@ private void checkStaticFields(Class clazz) { } private byte[] generateAndCompile(int[] fieldQuantities) { - Map sources = new HashMap(); - sources.put("A", generateSource(fieldQuantities)); - return InMemoryJavaCompiler.compile(sources).values().iterator().next(); + return InMemoryJavaCompiler.compile("A", generateSource(fieldQuantities)); } private StringBuffer generateSource(int[] fieldQuantities) { diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressDictionary/StressDictionary.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressDictionary/StressDictionary.java index b4c44a9a05970..0db2d24fa8f9d 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressDictionary/StressDictionary.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressDictionary/StressDictionary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, 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 @@ -43,7 +43,7 @@ import nsk.share.gc.GCTestBase; import nsk.share.test.*; -import vm.share.InMemoryJavaCompiler; +import jdk.test.lib.compiler.InMemoryJavaCompiler; /** * There is a data structure named "dictionary" in class BlockFreelist. It stores @@ -178,10 +178,8 @@ public void run() { } private byte[] generateAndCompile() { - Map sources = new HashMap(); String className = "MyClass" + classesCounter.incrementAndGet(); - sources.put(className, generateSource(className)); - return InMemoryJavaCompiler.compile(sources).values().iterator().next(); + return InMemoryJavaCompiler.compile(className, generateSource(className)); } private CharSequence generateSource(String className) { diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/generateHierarchy/GenerateHierarchyHelper.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/generateHierarchy/GenerateHierarchyHelper.java index daccf64439375..be6f1ebe85f33 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/generateHierarchy/GenerateHierarchyHelper.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/generateHierarchy/GenerateHierarchyHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ import java.util.*; -import vm.share.InMemoryJavaCompiler; +import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.Utils; public class GenerateHierarchyHelper { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001.java index 015643f3a1892..142d6387610f6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001.java @@ -73,7 +73,6 @@ private launchnosuspend001 (String args[], PrintStream out) { argHandler = new ArgumentHandler(args); log = new Log(this.out, argHandler); - //log.enableVerbose(true); } private PrintStream out; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java index c3c3cb31ebd27..44da4f71eb268 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java @@ -63,7 +63,7 @@ public static int run(String argv[], PrintStream out) { } // Virtual threads are not supported by GetObjectMonitorUsage. // Correct the expected values if the test is executed with - // JTREG_TEST_THREAD_FACTORY=Virtual. + // JTREG="TEST_THREAD_FACTORY=Virtual". Thread expOwner = mainThread.isVirtual() ? null : mainThread; int expEntryCount = mainThread.isVirtual() ? 0 : 1; @@ -157,7 +157,7 @@ public objmonusage001a(Thread mt, int i, Object s) { public void run() { // Virtual threads are not supported by GetObjectMonitorUsage. // Correct the expected values if the test is executed with - // JTREG_TEST_THREAD_FACTORY=Virtual. + // JTREG="TEST_THREAD_FACTORY=Virtual". Thread expOwner = this.isVirtual() ? null : this; Thread expNotifyWaiter = mainThread.isVirtual() ? null : mainThread; int expEntryCount = this.isVirtual() ? 0 : 1; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java index 8d79a6011f581..172d16445c1ff 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java @@ -62,7 +62,7 @@ public static int run(String args[], PrintStream out) { synchronized (lockCheck) { // Virtual threads are not supported by GetObjectMonitorUsage. // Correct the expected values if the test is executed with - // JTREG_TEST_THREAD_FACTORY=Virtual. + // JTREG="TEST_THREAD_FACTORY=Virtual". Thread expOwner = currThread.isVirtual() ? null : currThread; int expEntryCount = currThread.isVirtual() ? 0 : 2; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/IterateThroughHeap/filter_tagged/HeapFilter.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/IterateThroughHeap/filter_tagged/HeapFilter.java index 91f315ee7a968..b690955307ef7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/IterateThroughHeap/filter_tagged/HeapFilter.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/IterateThroughHeap/filter_tagged/HeapFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,6 @@ public int runTest(String args[], PrintStream out) { log = new Log(out, argHandler); testObjects = new Object[]{new TaggedClass(), new UntaggedClass()}; - log.enableVerbose(true); log.display("Verifying reachable objects."); status = checkStatus(status); testObjects = null; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RedefineClasses/StressRedefine.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RedefineClasses/StressRedefine.java index 1192de03f880f..d581cd5693b56 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RedefineClasses/StressRedefine.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RedefineClasses/StressRedefine.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 @@ -21,7 +21,6 @@ * questions. */ -//package nsk.jvmti.RedefineClasses.StressRedefine; package nsk.jvmti.RedefineClasses; @@ -41,7 +40,7 @@ import nsk.share.test.Stresser; import nsk.share.test.Tests; -import vm.share.InMemoryJavaCompiler; +import jdk.test.lib.compiler.InMemoryJavaCompiler; /** * There is a data structure named "dictionary" in class BlockFreelist. It stores @@ -203,9 +202,7 @@ private static ThreadFactory virtualThreadFactory() { } private static byte[] generateAndCompile() { - Map sources = new HashMap(); - sources.put(GenerateSourceHelper.CLASS_NAME, GenerateSourceHelper.generateSource()); - return InMemoryJavaCompiler.compile(sources).values().iterator().next(); + return InMemoryJavaCompiler.compile(GenerateSourceHelper.CLASS_NAME, GenerateSourceHelper.generateSource()); } // Auxiliary classloader. Used only once at the beginning. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP05/sp05t003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP05/sp05t003/TestDescription.java index ecb2cfc59e59d..1c8ca451c8e82 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP05/sp05t003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP05/sp05t003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @library /vmTestbase * /test/lib * @run main/othervm/native - * -agentlib:sp05t003=-waittime=5 + * -agentlib:sp05t003=-waittime=5,-verbose * nsk.jvmti.scenarios.sampling.SP05.sp05t003 */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isCollectionUsageThresholdExceeded/isexceeded001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isCollectionUsageThresholdExceeded/isexceeded001.java index 702a5a793791a..a9e75bb7cecee 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isCollectionUsageThresholdExceeded/isexceeded001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isCollectionUsageThresholdExceeded/isexceeded001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, 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 @@ -40,7 +40,6 @@ public static void main(String[] argv) { public static int run(String[] argv, PrintStream out) { ArgumentHandler argHandler = new ArgumentHandler(argv); Log log = new Log(out, argHandler); - log.enableVerbose(true); monitor = Monitor.getMemoryMonitor(log, argHandler); List pools = monitor.getMemoryPoolMBeans(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java index 390bfdd625188..a684c03e67a38 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2022, 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 @@ -47,7 +47,6 @@ public static void main(String[] argv) { public static int run(String[] argv, PrintStream out) { ArgumentHandler argHandler = new ArgumentHandler(argv); Log log = new Log(out, argHandler); - log.enableVerbose(true); // show log output MemoryMonitor monitor = Monitor.getMemoryMonitor(log, argHandler); List pools = monitor.getMemoryPoolMBeans(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/lowmem/lowmem001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/lowmem/lowmem001.java index d698e5aec837f..67f0d17f56109 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/lowmem/lowmem001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/lowmem/lowmem001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ public static void main(String[] args) { @Override public void run() { - Log log = new Log(System.out, true); + Log log = new Log(System.out); // System.err is duplicated into buffer // it should be empty MyStream stream = new MyStream(System.err); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java index e575018249533..99467fc033412 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java @@ -29,22 +29,15 @@ import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringReader; -import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.HashSet; import java.util.Vector; -import nsk.share.test.LazyFormatString; /** - * This class helps to print test-execution trace messages - * and filter them when execution mode is not verbose. - *

            - * Verbose mode if defined by providing -verbose command line - * option, handled by ArgumentParser. Use verbose() - * method to determine which mode is used. + * This class helps to print test-execution trace messages. *

            * Log provides with two main methods to print messages: *

              @@ -60,7 +53,6 @@ * To provide printing messages from different sources into one log * with distinct prefixes use internal Log.Logger class. * - * @see #verbose() * @see #complain(String) * @see #display(String) * @see ArgumentParser @@ -72,18 +64,6 @@ public class Log { */ private PrintStream out = null; - /** - * Is log-mode verbose? - * Always enabled. - */ - private final boolean verbose = true; - - /** - * Should log messages prefixed with timestamps? - * Always enabled. - */ - private final boolean timestamp = true; - /** * Names for trace levels */ @@ -188,41 +168,15 @@ public Log(PrintStream stream) { /** * Incarnate new Log for the given stream; and - * either for verbose or for non-verbose mode accordingly to - * the given verbose key. - */ - public Log(PrintStream stream, boolean verbose) { - this(stream); - } - - /** - * Incarnate new Log for the given stream; and - * either for verbose or for non-verbose mode accordingly to * the given argsHandler. */ public Log(PrintStream stream, ArgumentParser argsParser) { - this(stream, argsParser.verbose()); + this(stream); traceLevel = argsParser.getTraceLevel(); } ///////////////////////////////////////////////////////////////// - /** - * Return true if log mode is verbose. - */ - public boolean verbose() { - return verbose; - } - - /** - * Enable or disable verbose mode for printing messages. - */ - public void enableVerbose(boolean enable) { - if (!enable) { - throw new RuntimeException("The non-verbose logging is not supported."); - } - } - public int getTraceLevel() { return traceLevel; } @@ -266,9 +220,6 @@ public static String printExceptionToString(Object prefix, Throwable exception) @Deprecated public synchronized void println(String message) { doPrint(message); - if (!verbose()) { - keepLog(composeLine(message)); - } } /** @@ -282,9 +233,6 @@ public synchronized void println(String message) { */ @Deprecated public synchronized void comment(String message) { - if (!verbose()) { - doPrint(message); - } } /** @@ -314,17 +262,10 @@ public void trace(int level, Object message, Throwable exception) { } /** - * Print message to the assigned output stream, - * if log mode is verbose. The message will be lost, - * if execution mode is non-verbose, and there is no error messages - * printed. + * Print message to the assigned output stream. */ public synchronized void display(Object message) { - if (verbose()) { - doPrint(message.toString()); - } else { - keepLog(composeLine(message.toString())); - } + doPrint(message.toString()); } /** @@ -333,15 +274,6 @@ public synchronized void display(Object message) { * into errorsBuffer. */ public synchronized void complain(Object message) { - if (!verbose()) { - PrintStream stream = findOutStream(); - stream.println("#> "); - stream.println("#> WARNING: switching log to verbose mode,"); - stream.println("#> because error is complained"); - stream.println("#> "); - stream.flush(); - enableVerbose(true); - } String msgStr = message.toString(); printError(msgStr); @@ -406,10 +338,7 @@ private void logExceptionForFailureAnalysis(String msg) { ///////////////////////////////////////////////////////////////// /** - * Redirect log to the given stream, and switch - * log mode to verbose. - * Prints errors summary to current stream, cancel current stream - * and switches to new stream. Turns on verbose mode for new stream. + * Redirect log to the given stream. * * @deprecated This method is obsolete. */ @@ -430,20 +359,6 @@ public synchronized void clearLogBuffer() { logBuffer.clear(); } - /** - * Print all messages from log buffer which were hidden because - * of non-verbose mode, - */ - private synchronized void flushLogBuffer() { - if (!logBuffer.isEmpty()) { - PrintStream stream = findOutStream(); - for (int i = 0; i < logBuffer.size(); i++) { - stream.println(logBuffer.elementAt(i)); - } - stream.flush(); - } - } - /** * Return out stream if defined or Sytem.err otherwise; * print a warning message when System.err is used first time. @@ -468,18 +383,15 @@ private synchronized PrintStream findOutStream() { * Compose line to print possible prefixing it with timestamp. */ private String composeLine(String message) { - if (timestamp) { - long time = System.currentTimeMillis(); - long ms = time % 1000; - time /= 1000; - long secs = time % 60; - time /= 60; - long mins = time % 60; - time /= 60; - long hours = time % 24; - return "[" + hours + ":" + mins + ":" + secs + "." + ms + "] " + message; - } - return message; + long time = System.currentTimeMillis(); + long ms = time % 1000; + time /= 1000; + long secs = time % 60; + time /= 60; + long mins = time % 60; + time /= 60; + long hours = time % 24; + return "[" + hours + ":" + mins + ":" + secs + "." + ms + "] " + message; } /** @@ -513,13 +425,6 @@ private synchronized void printError(String message) { } } - /** - * Keep the given log message into logBuffer. - */ - private synchronized void keepLog(String message) { - logBuffer.addElement(message); - } - /** * This class can be used as a base for each class that use Log * for print messages and errors. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java index bde40cc7e2021..9899c762a7a90 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, 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 @@ -68,7 +68,7 @@ public class AODTestRunner { protected AODRunnerArgParser argParser; protected AODTestRunner(String[] args) { - log = new Log(System.out, true); + log = new Log(System.out); argParser = createArgParser(args); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java index 3fa3141a8cd9e..fb02327a42224 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.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 @@ -157,7 +157,7 @@ private void defaultInit(String[] args) { if (name == null) throw new TestBug("Agent name wasn't specified"); - log = new Log(System.out, true); + log = new Log(System.out); } /* diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java index bb726453e9bd3..c8fb3bf266324 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java @@ -39,7 +39,7 @@ */ public class DummyTargetApplication { - protected Log log = new Log(System.out, true); + protected Log log = new Log(System.out); protected AODTargetArgParser argParser; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java index 6f80033dff504..0b5acfb24ba00 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java @@ -213,7 +213,7 @@ private void initTargetApplication(String[] args) { if (targetApplicationInitialized) throw new TestBug("TargetApplication already initialized"); - log = new Log(System.out, true); + log = new Log(System.out); argParser = createArgParser(args); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/JVMTITest.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/JVMTITest.java index c8d26b6ea1f5e..d9b847e110dc0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/JVMTITest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/JVMTITest.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 @@ -87,7 +87,7 @@ static void attachAgent(String[] args) { AgentsAttacher attacher = new AgentsAttacher(Utils.findCurrentVMIdUsingJPS(jdkPath), agents, - new Log(System.out, true)); + new Log(System.out)); attacher.attachAgents(); } } diff --git a/test/hotspot/jtreg/vmTestbase/vm/compiler/coverage/parentheses/Parentheses.java b/test/hotspot/jtreg/vmTestbase/vm/compiler/coverage/parentheses/Parentheses.java index 66546e9b13f15..219af51045a23 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/compiler/coverage/parentheses/Parentheses.java +++ b/test/hotspot/jtreg/vmTestbase/vm/compiler/coverage/parentheses/Parentheses.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 @@ -69,7 +69,7 @@ public static void main(String[] args) throws Exception { public void run() throws IOException, ReflectiveOperationException { - log = new Log(System.out, verbose); + log = new Log(System.out); InstructionSequence instructionSequence = null; for (int i = 0; i < iterations * stressOptions.getIterationsFactor(); i++) { diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/InMemoryJavaCompiler.java b/test/hotspot/jtreg/vmTestbase/vm/share/InMemoryJavaCompiler.java deleted file mode 100644 index 6f5f1c0cbcd97..0000000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/share/InMemoryJavaCompiler.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package vm.share; - -import javax.tools.FileObject; -import javax.tools.ForwardingJavaFileManager; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.ToolProvider; -import java.io.ByteArrayOutputStream; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URI; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Map.Entry; - - -public class InMemoryJavaCompiler { - - public static Map compile(Map inputMap) { - Collection sourceFiles = new LinkedList(); - for (Entry entry : inputMap.entrySet()) { - sourceFiles.add(new SourceFile(entry.getKey(), entry.getValue())); - } - - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - FileManager fileManager = new FileManager(compiler.getStandardFileManager(null, null, null)); - - Writer writer = new StringWriter(); - Boolean exitCode = compiler.getTask(writer, fileManager, null, null, null, sourceFiles).call(); - if (!exitCode) { - System.out.println("*********** javac output begin ***********"); - System.out.println(writer.toString()); - System.out.println("*********** javac output end ***********"); - if (writer.toString().contains("java.lang.OutOfMemoryError")) { - System.out.println("Got OOME while performing in memory compilation. It happens on weak hosts and there is nothing we can do. "); - throw new OutOfMemoryError("Got OOME while performing in memory compilation."); - } - throw new RuntimeException("Test bug: in memory compilation failed."); - } - return fileManager.getByteCode(); - } - - // Wraper for class file - static class ClassFile extends SimpleJavaFileObject { - - private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - protected ClassFile(String name) { - super(URI.create("memo:///" + name.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS); - } - - @Override - public ByteArrayOutputStream openOutputStream() { return this.baos; } - - byte[] toByteArray() { return baos.toByteArray(); } - } - - // File manager which spawns ClassFile instances by demand - static class FileManager extends ForwardingJavaFileManager { - - private Map classesMap = new HashMap(); - - protected FileManager(JavaFileManager fileManager) { - super(fileManager); - } - - @Override - public ClassFile getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject source) { - ClassFile classFile = new ClassFile(name); - classesMap.put(name, classFile); - return classFile; - } - - public Map getByteCode() { - Map result = new HashMap(); - for (Entry entry : classesMap.entrySet()) { - result.put(entry.getKey(), entry.getValue().toByteArray()); - } - return result; - } - } - - // Wrapper for source file - static class SourceFile extends SimpleJavaFileObject { - - private CharSequence sourceCode; - - public SourceFile(String name, CharSequence sourceCode) { - super(URI.create("memo:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); - this.sourceCode = sourceCode; - } - - @Override - public CharSequence getCharContent(boolean ignore) { - return this.sourceCode; - } - } - -} diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 2fc09ee4df4a9..02f81b13badc3 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -28,5 +28,4 @@ ############################################################################# java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all -java/lang/management/MemoryMXBean/CollectionUsageThreshold.java 8318668 generic-all com/sun/jdi/InterruptHangTest.java 8043571 generic-all diff --git a/test/jdk/ProblemList-zgc.txt b/test/jdk/ProblemList-zgc.txt index 9fae070e25d1f..e81ac8137471c 100644 --- a/test/jdk/ProblemList-zgc.txt +++ b/test/jdk/ProblemList-zgc.txt @@ -27,5 +27,14 @@ # ############################################################################# -sun/tools/jhsdb/JShellHeapDumpTest.java 8276539 generic-all -sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java 8276539 generic-all +# Quiet all SA tests + +sun/tools/jhsdb/HeapDumpTest.java 8307393 generic-all +sun/tools/jhsdb/BasicLauncherTest.java 8307393 generic-all +sun/tools/jhsdb/JStackStressTest.java 8307393 generic-all +sun/tools/jhsdb/JShellHeapDumpTest.java 8307393 generic-all +sun/tools/jhsdb/SAGetoptTest.java 8307393 generic-all +sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java 8307393 generic-all +sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java 8307393 generic-all + +com/sun/jdi/ThreadMemoryLeakTest.java 8307402 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index bf1c9bd31e7a6..b37787b5f7e9d 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -121,13 +121,17 @@ java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java 6848406 gen java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java 6848407 generic-all java/awt/Frame/MaximizedUndecorated/MaximizedUndecorated.java 8022302 generic-all java/awt/Frame/RestoreToOppositeScreen/RestoreToOppositeScreen.java 8286840 linux-all -java/awt/Frame/InitialIconifiedTest.java 8203920 macosx-all,linux-all +java/awt/Frame/InitialIconifiedTest.java 7144049,8203920 macosx-all,linux-all java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java 8341370 macosx-all +java/awt/Frame/FocusTest.java 8341480 macosx-all java/awt/FileDialog/FileDialogIconTest/FileDialogIconTest.java 8160558 windows-all java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java 8060176 windows-all,macosx-all java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java 8060176 windows-all,macosx-all java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java 8171510 macosx-all java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java 8288839 windows-x64 +java/awt/dnd/DragExitBeforeDropTest.java 8242805 macosx-all +java/awt/dnd/DragThresholdTest.java 8076299 macosx-all +java/awt/dnd/CustomDragCursorTest.java 8242805 macosx-all java/awt/Focus/ChoiceFocus/ChoiceFocus.java 8169103 windows-all,macosx-all java/awt/Focus/ClearLwQueueBreakTest/ClearLwQueueBreakTest.java 8198618 macosx-all java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java 6986252 macosx-all @@ -140,6 +144,7 @@ java/awt/Focus/TestDisabledAutoTransferSwing.java 6962362 windows-all java/awt/Focus/ActivateOnProperAppContextTest.java 8136516 macosx-all java/awt/Focus/FocusPolicyTest.java 7160904 linux-all java/awt/EventQueue/6980209/bug6980209.java 8198615 macosx-all +java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java 8024034 generic-all java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java 7080150 macosx-all java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java 8168646 generic-all java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java 8049405 macosx-all @@ -196,6 +201,9 @@ java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java 8169476 windows java/awt/event/KeyEvent/KeyChar/KeyCharTest.java 8169474,8224055 macosx-all,windows-all java/awt/event/KeyEvent/KeyTyped/CtrlASCII.java 8298910 linux-all +java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java 8242805 macosx-all +java/awt/dnd/DnDCursorCrashTest.java 8242805 macosx-all +java/awt/dnd/DnDClipboardDeadlockTest.java 8079553 linux-all java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java 8194947 generic-all java/awt/Frame/FramesGC/FramesGC.java 8079069 macosx-all java/awt/TrayIcon/ActionCommand/ActionCommand.java 8150540 windows-all @@ -210,6 +218,9 @@ java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java 8150540,8295300 windows java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java 8150540 windows-all java/awt/TrayIcon/TrayIconPopup/TrayIconPopupClickTest.java 8150540 windows-all,macosx-all java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java 8150540 windows-all +java/awt/TrayIcon/MouseMoveTest.java 8203053 linux-all +java/awt/TrayIcon/TrayIconKeySelectTest.java 8341557 windows-all +java/awt/TrayIcon/TrayIconTest.java 8341559 generic-all java/awt/Window/ShapedAndTranslucentWindows/SetShapeAndClick.java 8197936 macosx-all java/awt/Window/ShapedAndTranslucentWindows/SetShapeDynamicallyAndClick.java 8013450 macosx-all @@ -433,6 +444,7 @@ java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.j java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java 7107528 linux-all,macosx-all java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java 8080676 linux-all java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersInKeyEvent.java 8157147 linux-all,windows-all,macosx-all +java/awt/Mouse/MouseClickCount.java 8017182 macosx-all java/awt/Toolkit/ToolkitPropertyTest/ToolkitPropertyTest_Enable.java 6847163 linux-all java/awt/xembed/server/RunTestXEmbed.java 7034201 linux-all java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsDocModalTest.java 8164473 linux-all @@ -466,7 +478,15 @@ java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemoni java/awt/Window/GetScreenLocation/GetScreenLocationTest.java 8225787 linux-x64 java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64 +java/awt/Dialog/PrintToFileTest/PrintToFileRevoked.java 8029249 macosx-all +java/awt/Dialog/PrintToFileTest/PrintToFileGranted.java 8029249 macosx-all +java/awt/Dialog/ChoiceModalDialogTest.java 8161475 macosx-all +java/awt/Dialog/FileDialogUserFilterTest.java 8001142 generic-all + java/awt/dnd/BadSerializationTest/BadSerializationTest.java 8277817 linux-x64,windows-x64 +java/awt/dnd/DragSourceMotionListenerTest.java 8225131 windows-all +java/awt/dnd/RejectDragTest.java 7124259 macosx-all +java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java 8027424 generic-all java/awt/GraphicsDevice/DisplayModes/UnknownRefrshRateTest.java 8286436 macosx-aarch64 java/awt/image/multiresolution/MultiresolutionIconTest.java 8291979 linux-x64,windows-all java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java 8305061 macosx-x64 @@ -511,6 +531,7 @@ java/lang/instrument/RetransformBigClass.sh 8065756 generic- # jdk_io java/io/pathNames/GeneralWin32.java 8180264 windows-all +java/io/IO/IO.java 8337935 linux-ppc64le ############################################################################ @@ -565,7 +586,7 @@ java/net/Socket/asyncClose/Race.java 8317801 aix-ppc6 # jdk_nio -java/nio/Buffer/LimitDirectMemory.java 8340728 generic-all +java/nio/Buffer/LimitDirectMemory.java 8342849 generic-all java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc64 @@ -667,7 +688,6 @@ javax/swing/AbstractButton/6711682/bug6711682.java 8060765 windows-all,macosx-al 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 javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java 8160720 generic-all javax/swing/JFileChooser/6798062/bug6798062.java 8146446 windows-all @@ -800,3 +820,7 @@ java/awt/PopupMenu/PopupHangTest.java 8340022 windows-all java/awt/Focus/MinimizeNonfocusableWindowTest.java 8024487 windows-all java/awt/Focus/InactiveFocusRace.java 8023263 linux-all java/awt/List/HandlingKeyEventIfMousePressedTest.java 6848358 macosx-all,windows-all +java/awt/Checkbox/CheckboxBoxSizeTest.java 8340870 windows-all +java/awt/Checkbox/CheckboxIndicatorSizeTest.java 8340870 windows-all +java/awt/Checkbox/CheckboxNullLabelTest.java 8340870 windows-all +java/awt/dnd/WinMoveFileToShellTest.java 8341665 windows-all diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index 6198d33214293..6276932afbd14 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -84,8 +84,6 @@ requires.properties= \ vm.gc.Shenandoah \ vm.gc.Epsilon \ vm.gc.Z \ - vm.gc.ZGenerational \ - vm.gc.ZSinglegen \ vm.graal.enabled \ vm.compiler1.enabled \ vm.compiler2.enabled \ @@ -100,7 +98,7 @@ requires.properties= \ vm.jvmci.enabled \ vm.jvmti \ vm.cpu.features \ - docker.support \ + container.support \ systemd.support \ release.implementor \ jdk.containerized \ diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 0c6b13fdca057..e7ee8990f94fb 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -1,4 +1,4 @@ -# 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 @@ -91,7 +91,8 @@ tier3 = \ :jdk_svc \ -:jdk_svc_sanity \ -:svc_tools \ - :jdk_jpackage + :jdk_jpackage \ + :jdk_since_checks # Everything not in other tiers tier4 = \ @@ -381,7 +382,8 @@ jdk_svc = \ jdk_foreign = \ java/foreign \ jdk/internal/reflect/CallerSensitive/CheckCSMs.java \ - -java/foreign/TestMatrix.java + -java/foreign/TestMatrix.java \ + -java/foreign/TestUpcallStress.java jdk_vector = \ jdk/incubator/vector @@ -665,3 +667,7 @@ jdk_containers_extended = \ jdk_core_no_security = \ :jdk_core \ -:jdk_security + +# Set of tests for `@since` checks in source code documentation +jdk_since_checks = \ + tools/sincechecker/modules/java_base/CheckSince_javaBase.java diff --git a/test/jdk/com/sun/crypto/provider/CICO/CICODESFuncTest.java b/test/jdk/com/sun/crypto/provider/CICO/CICODESFuncTest.java index 3164294ecca57..440914826bc42 100644 --- a/test/jdk/com/sun/crypto/provider/CICO/CICODESFuncTest.java +++ b/test/jdk/com/sun/crypto/provider/CICO/CICODESFuncTest.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 @@ -66,7 +66,8 @@ public class CICODESFuncTest { private static final int IV_LENGTH = 8; public static void main(String[] args) throws Exception { - Provider provider = Security.getProvider("SunJCE"); + Provider provider = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); if (provider == null) { throw new RuntimeException("SunJCE provider does not exist."); } diff --git a/test/jdk/com/sun/crypto/provider/CICO/CICOSkipTest.java b/test/jdk/com/sun/crypto/provider/CICO/CICOSkipTest.java index 0641845d7f9e4..d0af93ff646dd 100644 --- a/test/jdk/com/sun/crypto/provider/CICO/CICOSkipTest.java +++ b/test/jdk/com/sun/crypto/provider/CICO/CICOSkipTest.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 @@ -75,7 +75,7 @@ public class CICOSkipTest { "OFB", "OFB64", "PCBC"}; private static final String[] PADDINGS = {"NoPadding", "Pkcs5Padding"}; private static final String[] PBE_ALGOS = {"PBEWithMD5AndDES", - "PBEWithMD5AndDES/CBC/PKCS5Padding"}; + "PBEWithMD5AndDES/CBC/PKCS5Padding", "PBEWithSHA1AndDESede"}; public static void main(String[] args) throws Exception { // how many kinds of padding mode such as PKCS5padding and NoPadding @@ -204,9 +204,10 @@ private void initCiphers(String algo, SecretKey key, AlgorithmParameterSpec aps) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { - Provider provider = Security.getProvider("SunJCE"); + String providerName = System.getProperty("test.provider.name", "SunJCE"); + Provider provider = Security.getProvider(providerName); if (provider == null) { - throw new RuntimeException("SunJCE provider does not exist."); + throw new RuntimeException(providerName + " provider does not exist."); } Cipher ci1 = Cipher.getInstance(algo, provider); ci1.init(Cipher.ENCRYPT_MODE, key, aps); diff --git a/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/AESPBEWrapper.java b/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/AESPBEWrapper.java index e6e5c2faa01c6..3dd15d5005862 100644 --- a/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/AESPBEWrapper.java +++ b/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/AESPBEWrapper.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 @@ -69,9 +69,10 @@ public AESPBEWrapper(PBEAlgorithm algo, String passwd) */ @Override protected Cipher initCipher(int mode) throws GeneralSecurityException { - Provider provider = Security.getProvider("SunJCE"); + String providerName = System.getProperty("test.provider.name", "SunJCE"); + Provider provider = Security.getProvider(providerName); if (provider == null) { - throw new RuntimeException("SunJCE provider does not exist."); + throw new RuntimeException(providerName + ": provider does not exist."); } // get Cipher instance Cipher ci = Cipher.getInstance(transformation, provider); diff --git a/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/DefaultPBEWrapper.java b/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/DefaultPBEWrapper.java index f68fd85146bf7..cde094e1f90ee 100644 --- a/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/DefaultPBEWrapper.java +++ b/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/DefaultPBEWrapper.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 @@ -58,9 +58,10 @@ public DefaultPBEWrapper(PBEAlgorithm algo, String passwd) { */ @Override protected Cipher initCipher(int mode) throws GeneralSecurityException { - Provider provider = Security.getProvider("SunJCE"); + String providerName = System.getProperty("test.provider.name", "SunJCE"); + Provider provider = Security.getProvider(providerName); if (provider == null) { - throw new RuntimeException("SunJCE provider does not exist."); + throw new RuntimeException(providerName + ": provider does not exist."); } SecretKey key = SecretKeyFactory.getInstance(baseAlgo) .generateSecret(new PBEKeySpec(password.toCharArray())); diff --git a/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/PBKDF2Wrapper.java b/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/PBKDF2Wrapper.java index fb2d0ac901f89..ac7580990f032 100644 --- a/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/PBKDF2Wrapper.java +++ b/test/jdk/com/sun/crypto/provider/CICO/PBEFunc/PBKDF2Wrapper.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 @@ -89,9 +89,10 @@ public PBKDF2Wrapper(PBEAlgorithm algo, String passwd) */ @Override protected Cipher initCipher(int mode) throws GeneralSecurityException { - Provider provider = Security.getProvider("SunJCE"); + String providerName = System.getProperty("test.provider.name", "SunJCE"); + Provider provider = Security.getProvider(providerName); if (provider == null) { - throw new RuntimeException("SunJCE provider does not exist."); + throw new RuntimeException(providerName + ": provider does not exist."); } // Generate secret key PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/Encrypt.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/Encrypt.java index 58267c2ffbaeb..78b69c2ea95ee 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/Encrypt.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/Encrypt.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 @@ -122,7 +122,8 @@ public Encrypt(Provider provider, String algorithm, String mode, } public static void main(String[] args) throws Exception { - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); for (String alg : ALGORITHMS) { for (int keyStrength : KEY_STRENGTHS) { if (keyStrength > Cipher.getMaxAllowedKeyLength(alg)) { diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMLargeDataKAT.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMLargeDataKAT.java index 11efb2d0611b5..885b5998aa477 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMLargeDataKAT.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMLargeDataKAT.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 @@ -102,7 +102,8 @@ public class GCMLargeDataKAT { byte[] encrypt(int inLen) { try { - cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + cipher = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); cipher.init(Cipher.ENCRYPT_MODE, key, spec); return cipher.doFinal(plaintext, 0, inLen); } catch (Exception e) { @@ -125,7 +126,8 @@ boolean decrypt(byte[] data) { return false; } try { - cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + cipher = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); cipher.init(Cipher.DECRYPT_MODE, key, spec); result = cipher.doFinal(data); } catch (Exception e) { diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMParameterSpecTest.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMParameterSpecTest.java index 7250c4d7f0f36..f65a8eed2b9d8 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMParameterSpecTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMParameterSpecTest.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 @@ -87,7 +87,8 @@ public GCMParameterSpecTest(int keyLength, int tagLength, int IVlength, AAD = Helper.generateBytes(AADLength); // init a secret key - KeyGenerator kg = KeyGenerator.getInstance("AES", "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance("AES", + System.getProperty("test.provider.name", "SunJCE")); kg.init(keyLength); key = kg.generateKey(); } @@ -211,7 +212,8 @@ private byte[] recoverCipherText(byte[] cipherText, GCMParameterSpec spec) private Cipher createCipher(int mode, GCMParameterSpec spec) throws Exception { - Cipher cipher = Cipher.getInstance(TRANSFORMATION, "SunJCE"); + Cipher cipher = Cipher.getInstance(TRANSFORMATION, + System.getProperty("test.provider.name", "SunJCE")); cipher.init(mode, key, spec); return cipher; } diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/KeyWrapper.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/KeyWrapper.java index 21f1deec45b65..c1a0ae2dfd033 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/KeyWrapper.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/KeyWrapper.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 @@ -37,7 +37,7 @@ public class KeyWrapper { static final String AES = "AES"; static final String TRANSFORMATION = "AES/GCM/NoPadding"; - static final String PROVIDER = "SunJCE"; + static final String PROVIDER = System.getProperty("test.provider.name", "SunJCE"); static final int KEY_LENGTH = 128; public static void main(String argv[]) throws Exception { diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/ReadWriteSkip.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/ReadWriteSkip.java index f6bd3805ae4c6..fd7df41c91ad5 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/ReadWriteSkip.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/ReadWriteSkip.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 @@ -50,7 +50,7 @@ static enum BufferType { static final int BLOCK = 50; static final int SAVE = 45; static final int DISCARD = BLOCK - SAVE; - static final String PROVIDER = "SunJCE"; + static final String PROVIDER = System.getProperty("test.provider.name", "SunJCE"); static final String AES = "AES"; static final String GCM = "GCM"; static final String PADDING = "NoPadding"; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/SameBuffer.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/SameBuffer.java index 756fd624223af..3e3fa3d77b18f 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/SameBuffer.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/SameBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, 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 @@ -41,7 +41,7 @@ */ public class SameBuffer { - private static final String PROVIDER = "SunJCE"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunJCE"); private static final String AES = "AES"; private static final String GCM = "GCM"; private static final String PADDING = "NoPadding"; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/SealedObjectTest.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/SealedObjectTest.java index 6f5e8200e104d..accf38f98b5ac 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/SealedObjectTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/SealedObjectTest.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 @@ -37,7 +37,7 @@ public class SealedObjectTest { private static final String AES = "AES"; private static final String TRANSFORMATION = "AES/GCM/NoPadding"; - private static final String PROVIDER = "SunJCE"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunJCE"); private static final int KEY_LENGTH = 128; public static void main(String[] args) throws Exception { diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/WrongAAD.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/WrongAAD.java index 157a8bb329dea..6a35b3f2ce8f1 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/WrongAAD.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/WrongAAD.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 @@ -44,7 +44,7 @@ */ public class WrongAAD { - private static final String PROVIDER = "SunJCE"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunJCE"); private static final String TRANSFORMATION = "AES/GCM/NoPadding"; private static final int TEXT_SIZE = 800; private static final int KEY_SIZE = 128; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/CICO.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/CICO.java index 1bb9f0d061f21..5d6da523f2a84 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/CICO.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/CICO.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 @@ -52,7 +52,7 @@ public class CICO { "cFB24", "cFB32", "Cfb40", "CFB72", "OfB", "OfB20", "OfB48", "OfB56", "OFB64", "OFB112", "CFB112", "pCbC" }; private static final String[] PADDING = { "noPadding", "pkcs5padding" }; - private static final String PROVIDER = "SunJCE"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunJCE"); private static final int NREADS = 3; private static final int KEY_LENGTH = 128; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/CTR.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/CTR.java index d569965bca1d8..e610e98a27ba7 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/CTR.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/CTR.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 @@ -50,7 +50,8 @@ public class CTR { private static final String ALGORITHM = "AES"; - private static final String PROVIDER = "SunJCE"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunJCE"); private static final String[] MODES = {"CTR","CFB24","OFB32","GCM"}; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/Padding.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/Padding.java index 9598e1743c2c5..a494d2303815b 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/Padding.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/Padding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, 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 @@ -47,7 +47,8 @@ public class Padding { private static final String ALGORITHM = "AES"; - private static final String PROVIDER = "SunJCE"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunJCE"); private static final String[] MODES_PKCS5PAD = { "ECb", "CbC", "PCBC", "OFB", "OFB150", "cFB", "CFB7", "cFB8", "cFB16", "cFB24", "cFB32", diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4511676.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4511676.java index ef538f63f90c9..e8b8c3edf3002 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4511676.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4511676.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,10 +41,12 @@ public class Test4511676 { public boolean execute() throws Exception { - Cipher ci = Cipher.getInstance(ALGO, "SunJCE"); + Cipher ci = Cipher.getInstance(ALGO, + System.getProperty("test.provider.name", "SunJCE")); // TEST FIX 4511676 - KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance(ALGO, + System.getProperty("test.provider.name", "SunJCE")); kg.init(KEYSIZE*8); SecretKey key = kg.generateKey(); try { diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4512524.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4512524.java index b743d6bcefd04..c1428fdc03379 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4512524.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4512524.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,10 +45,12 @@ public class Test4512524 { public void execute(String mode) throws Exception { String transformation = ALGO+"/"+mode+"/"+PADDING; - Cipher ci = Cipher.getInstance(transformation, "SunJCE"); + Cipher ci = Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); // TEST FIX 4512524 - KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance(ALGO, + System.getProperty("test.provider.name", "SunJCE")); kg.init(KEYSIZE*8); SecretKey key = kg.generateKey(); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4512704.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4512704.java index bf00431439210..a33727075d7da 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4512704.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4512704.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,9 +45,11 @@ public void execute(String mode) throws Exception { AlgorithmParameterSpec aps = null; String transformation = ALGO + "/" + mode + "/"+PADDING; - Cipher ci = Cipher.getInstance(transformation, "SunJCE"); + Cipher ci = Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); - KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance(ALGO, + System.getProperty("test.provider.name", "SunJCE")); kg.init(KEYSIZE*8); SecretKey key = kg.generateKey(); // TEST FIX 4512704 diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4513830.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4513830.java index 856c55a6fbe4f..80d58dc19c53a 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4513830.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4513830.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,10 +52,12 @@ public boolean execute() throws Exception { byte[] plainText=new byte[125]; rdm.nextBytes(plainText); - Cipher ci = Cipher.getInstance(ALGO+"/"+MODE+"/"+PADDING, "SunJCE"); + Cipher ci = Cipher.getInstance(ALGO+"/"+MODE+"/"+PADDING, + System.getProperty("test.provider.name", "SunJCE")); // TEST FIX 4513830 - KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance(ALGO, + System.getProperty("test.provider.name", "SunJCE")); kg.init(KEYSIZE*8); SecretKey key = kg.generateKey(); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4517355.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4517355.java index ccab72bf69a89..1eed3831f53f5 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4517355.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4517355.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,8 +48,10 @@ public class Test4517355 { public void execute(String mode, String padding) throws Exception { String transformation = ALGO + "/" + mode + "/" + padding; - Cipher ci = Cipher.getInstance(transformation, "SunJCE"); - KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); + Cipher ci = Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); + KeyGenerator kg = KeyGenerator.getInstance(ALGO, + System.getProperty("test.provider.name", "SunJCE")); kg.init(KEYSIZE*8); SecretKey key = kg.generateKey(); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4626070.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4626070.java index 86409d3e4cd2a..e49ef86b3843e 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4626070.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/Test4626070.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,8 +38,10 @@ public class Test4626070 { public void execute(String mode, String padding) throws Exception { String transformation = ALGO + "/" + mode + "/" + padding; - Cipher ci = Cipher.getInstance(transformation, "SunJCE"); - KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); + Cipher ci = Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); + KeyGenerator kg = KeyGenerator.getInstance(ALGO, + System.getProperty("test.provider.name", "SunJCE")); kg.init(KEYSIZE*8); SecretKey key = kg.generateKey(); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCipher.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCipher.java index dd0d97101c115..9e2342c7be6f2 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCipher.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, 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 @@ -48,7 +48,7 @@ public class TestAESCipher { private static final String ALGORITHM = "AES"; - private static final String PROVIDER = "SunJCE"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunJCE"); private static final String[] MODES = { "ECb", "CbC", "CTR", "PCBC", "OFB", "OFB150", "cFB", "CFB7", "cFB8", "cFB16", "cFB24", "cFB32", "Cfb40", "cfB48", "cfB56", "cfB64", "cfB72", "cfB80", "cfB88", diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/Dynamic.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/Dynamic.java index 91d7426b7f177..65b345078357b 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/Dynamic.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/Dynamic.java @@ -46,7 +46,7 @@ public class Dynamic { static final String[] PADDING = { "NoPadding", "PKCS5Padding", "ISO10126Padding" }; - static final String SUNJCE = "SunJCE"; + static final String PROVIDER = System.getProperty("test.provider.name", "SunJCE"); Cipher ci = null; byte[] iv = null; @@ -128,8 +128,8 @@ protected boolean runTest(String algo, String mo, String pad) new Random().nextBytes(plainText); String transformation = algo + "/" + mo + "/" + pad; - ci = Cipher.getInstance(transformation, SUNJCE); - KeyGenerator kg = KeyGenerator.getInstance(algo, SUNJCE); + ci = Cipher.getInstance(transformation, PROVIDER); + KeyGenerator kg = KeyGenerator.getInstance(algo, PROVIDER); if (keyStrength > Cipher.getMaxAllowedKeyLength(transformation)) { // skip if this key length is larger than what's // configured in the jce jurisdiction policy files diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/TestAESWithProviderChange.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/TestAESWithProviderChange.java index d29a0aa09044b..bb9538c70a184 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/TestAESWithProviderChange.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/TestAESWithProviderChange.java @@ -33,7 +33,7 @@ public class TestAESWithProviderChange extends Dynamic { public static void main(String argv[]) throws Exception { - Security.removeProvider(SUNJCE); + Security.removeProvider(PROVIDER); Security.addProvider(new com.sun.crypto.provider.SunJCE()); new TestAESWithProviderChange().run(argv); } diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/TestAESWithRemoveAddProvider.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/TestAESWithRemoveAddProvider.java index 81761a7ea4bd8..677f9aa913a2c 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/TestAESWithRemoveAddProvider.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/TestAESWithRemoveAddProvider.java @@ -34,8 +34,8 @@ public class TestAESWithRemoveAddProvider extends Dynamic { public static void main(String argv[]) throws Exception { - Provider pJCE = Security.getProvider(SUNJCE); - Security.removeProvider(SUNJCE); + Provider pJCE = Security.getProvider(PROVIDER); + Security.removeProvider(PROVIDER); Security.addProvider(pJCE); new TestAESWithRemoveAddProvider().run(argv); } diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/testAES.policy b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/testAES.policy index 175e9cb86e587..5c6a06beb025d 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/testAES.policy +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/testAES.policy @@ -1,6 +1,7 @@ grant codeBase "file:${test.classes}/*" { - permission java.security.SecurityPermission "removeProvider.SunJCE"; - permission java.security.SecurityPermission "insertProvider.SunJCE"; + permission java.security.SecurityPermission "removeProvider.*"; + permission java.security.SecurityPermission "insertProvider.*"; permission java.lang.RuntimePermission "accessClassInPackage.com.sun.crypto.provider"; + permission java.util.PropertyPermission "test.provider.name", "read"; }; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCM.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCM.java index c6c7a66c5e46e..87d08b2c4a734 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCM.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCM.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 @@ -43,7 +43,8 @@ public class TestCICOWithGCM { public static void main(String[] args) throws Exception { //init Secret Key - KeyGenerator kg = KeyGenerator.getInstance("AES", "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance("AES", + System.getProperty("test.provider.name", "SunJCE")); kg.init(128); SecretKey key = kg.generateKey(); @@ -53,9 +54,11 @@ public static void main(String[] args) throws Exception { rdm.nextBytes(plainText); //init ciphers - Cipher encCipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + Cipher encCipher = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); encCipher.init(Cipher.ENCRYPT_MODE, key); - Cipher decCipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + Cipher decCipher = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); decCipher.init(Cipher.DECRYPT_MODE, key, encCipher.getParameters()); //init cipher streams diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCMAndAAD.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCMAndAAD.java index 807327622973a..960dd66567a27 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCMAndAAD.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCMAndAAD.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 @@ -39,7 +39,8 @@ public class TestCICOWithGCMAndAAD { public static void main(String[] args) throws Exception { //init Secret Key - KeyGenerator kg = KeyGenerator.getInstance("AES", "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance("AES", + System.getProperty("test.provider.name", "SunJCE")); kg.init(128); SecretKey key = kg.generateKey(); @@ -53,10 +54,12 @@ public static void main(String[] args) throws Exception { byte[] aad2 = aad.clone(); aad2[50]++; - Cipher encCipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + Cipher encCipher = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); encCipher.init(Cipher.ENCRYPT_MODE, key); encCipher.updateAAD(aad); - Cipher decCipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + Cipher decCipher = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); decCipher.init(Cipher.DECRYPT_MODE, key, encCipher.getParameters()); decCipher.updateAAD(aad); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCopySafe.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCopySafe.java index 697da6750ade9..70a9dd5998f64 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCopySafe.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestCopySafe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, 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 @@ -57,7 +57,8 @@ public class TestCopySafe { public static void main(String[] argv) throws Exception { - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); AlgorithmParameterSpec params = null; boolean result = true; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java index 0777508b36f1e..d94753e941ec8 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.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 @@ -68,7 +68,8 @@ private static void checkISE(Cipher c) throws Exception { } public void test() throws Exception { - Cipher c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + Cipher c = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); SecretKey key = new SecretKeySpec(new byte[16], "AES"); // First try parameter-less init. diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestISO10126Padding.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestISO10126Padding.java index 9b91e612c3544..26b160eaae1bd 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestISO10126Padding.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestISO10126Padding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, 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 @@ -45,7 +45,8 @@ public class TestISO10126Padding { private TestISO10126Padding() throws Exception { // setup - KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance(ALGO, + System.getProperty("test.provider.name", "SunJCE")); kg.init(KEYSIZE*8); key = kg.generateKey(); } @@ -59,7 +60,8 @@ private void runTest(int dataLength) throws Exception { // TEST#1 -- // generate the cipher text using manually-supplied // XML Encryption padding - Cipher ci = Cipher.getInstance(TRANS + "/NoPadding", "SunJCE"); + Cipher ci = Cipher.getInstance(TRANS + "/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); ci.init(Cipher.ENCRYPT_MODE, key); byte[] paddedData = new byte[ci.getBlockSize()]; System.arraycopy(data, 0, paddedData, 0, data.length); @@ -68,7 +70,8 @@ private void runTest(int dataLength) throws Exception { byte[] cipherText = ci.doFinal(paddedData); // decrypt using ISO10126Padding - ci = Cipher.getInstance(TRANS + "/ISO10126Padding", "SunJCE"); + ci = Cipher.getInstance(TRANS + "/ISO10126Padding", + System.getProperty("test.provider.name", "SunJCE")); ci.init(Cipher.DECRYPT_MODE, key); byte[] recovered = ci.doFinal(cipherText); if (!Arrays.equals(data, recovered)) { @@ -76,7 +79,8 @@ private void runTest(int dataLength) throws Exception { } // TEST#2 -- // generate the cipher text using ISO10126Padding - ci = Cipher.getInstance(TRANS + "/ISO10126Padding", "SunJCE"); + ci = Cipher.getInstance(TRANS + "/ISO10126Padding", + System.getProperty("test.provider.name", "SunJCE")); ci.init(Cipher.ENCRYPT_MODE, key); cipherText = ci.doFinal(data); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_IV.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_IV.java index a9576e7f3ebe9..71f07d61b13cf 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_IV.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_IV.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,7 +83,8 @@ private static byte[] constructByteArray(String s) { public boolean execute() throws Exception { String transformation = ALGO+"/"+MODE+"/"+PADDING; - Cipher c = Cipher.getInstance(transformation, "SunJCE"); + Cipher c = Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); for (int i=0; i diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_VK.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_VK.java index 098232b8c4cbf..623f5f5d28117 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_VK.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_VK.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -707,7 +707,8 @@ private static byte[] constructByteArray(String s) { public boolean execute() throws Exception { String transformation = ALGO+"/"+MODE+"/"+PADDING; - Cipher c = Cipher.getInstance(transformation, "SunJCE"); + Cipher c = Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); for (int i=0; i diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_VT.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_VT.java index b8f83bd7b0559..6265ca1028143 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_VT.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForECB_VT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -513,7 +513,8 @@ private static byte[] constructByteArray(String s) { public boolean execute() throws Exception { String transformation = ALGO+"/"+MODE+"/"+PADDING; - Cipher c = Cipher.getInstance(transformation, "SunJCE"); + Cipher c = Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); for (int i=0; i diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java index bdcf465f854eb..70db7b166e80f 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.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 @@ -278,7 +278,8 @@ public String toString() { }; void executeArray(TestVector tv) throws Exception { - Cipher c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + Cipher c = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); try { System.out.println("Test #" + tv.id + ": byte[]."); @@ -320,7 +321,8 @@ void executeArray(TestVector tv) throws Exception { } void executeByteBuffer(TestVector tv, boolean direct, int offset) throws Exception { - Cipher c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + Cipher c = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); ByteBuffer src; ByteBuffer ctdst; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestNoPaddingModes.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestNoPaddingModes.java index 9747f3bced21d..a32f787a72a06 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestNoPaddingModes.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestNoPaddingModes.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 @@ -42,7 +42,8 @@ public class TestNoPaddingModes { }; public static void main(String[] args) throws Exception { - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); String transformation; for (String mode : MODES) { for (String padding : PADDINGS) { @@ -50,7 +51,8 @@ public static void main(String[] args) throws Exception { System.out.println("Test using " + transformation); try { - Cipher c = Cipher.getInstance(transformation, "SunJCE"); + Cipher c = Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); throw new RuntimeException("=> Fail, no exception thrown"); } catch (NoSuchAlgorithmException | NoSuchPaddingException ex) { System.out.println("=> Expected ex: " + ex); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestNonexpanding.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestNonexpanding.java index 3ed865f5a9853..140f24d51d113 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestNonexpanding.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestNonexpanding.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 @@ -45,7 +45,8 @@ public class TestNonexpanding { private static final String ALGORITHM = "AES"; - private static final String PROVIDER = "SunJCE"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunJCE"); private static final String[] MODES = { "ECb", "CbC", "OFB", "OFB150", "cFB", "CFB7", "cFB8", "cFB16", "cFB24", "cFB32", "Cfb40", "cfB48", "cfB56", "cfB64", "cfB72", "cfB80", "cfB88", "cfB96", "cfb104", diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestSameBuffer.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestSameBuffer.java index e158bc5465206..cc8c050396e72 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestSameBuffer.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestSameBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, 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 @@ -47,7 +47,8 @@ public class TestSameBuffer { private static final String ALGORITHM = "AES"; - private static final String PROVIDER = "SunJCE"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunJCE"); private static final String[] MODES = { "ECb", "CbC", "OFB", "CFB150", "cFB", "CFB7", " cFB8", "cFB16", "cFB24", "cFB32", "Cfb40", "cfB48", " cfB56", "cfB64", "cfB72", "cfB80", "cfB88", "cfB96", diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestShortBuffer.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestShortBuffer.java index 52d6c43bdb1a9..fe1f76c0a0450 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestShortBuffer.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestShortBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2007, 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 @@ -71,7 +71,7 @@ private static void runTest() throws Exception { for (int i = 0; i < MODES.length; i++) { System.out.println("===== TESTING MODE " + MODES[i] + " ====="); Cipher ci = Cipher.getInstance(ALGO+"/"+MODES[i]+"/PKCS5Padding", - "SunJCE"); + System.getProperty("test.provider.name", "SunJCE")); TestShortBuffer test = null; int stored = 0; AlgorithmParameters params = null; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/CTR/CounterMode.java b/test/jdk/com/sun/crypto/provider/Cipher/CTR/CounterMode.java index 6d985312b6b7b..1073985c18cef 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/CTR/CounterMode.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/CTR/CounterMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, 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 @@ -162,7 +162,8 @@ public static void main(String[] args) throws Exception { continue; } System.out.println("Running test " + i + " (" + alg + ")"); - Cipher cipher = Cipher.getInstance(alg + "/CTR/NoPadding", "SunJCE"); + Cipher cipher = Cipher.getInstance(alg + "/CTR/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); SecretKeySpec key = new SecretKeySpec(KEYS[i], alg); IvParameterSpec iv = new IvParameterSpec(IVS[i]); byte[] plainText = PLAIN[i]; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/CTS/CTSMode.java b/test/jdk/com/sun/crypto/provider/Cipher/CTS/CTSMode.java index 6dba280899f7b..6d34fd3d50bf9 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/CTS/CTSMode.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/CTS/CTSMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2007, 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 @@ -156,7 +156,7 @@ private static void test1() throws Exception { } System.out.println("Running test1_" + i + " (" + algo + ")"); Cipher cipher = Cipher.getInstance(algo+ "/CTS/NoPadding", - "SunJCE"); + System.getProperty("test.provider.name", "SunJCE")); byte[] plainText = PLAIN1[i]; byte[] cipherText = CIPHER1[i]; cipher.init(Cipher.ENCRYPT_MODE, KEY1, IV1); @@ -194,7 +194,8 @@ private static void test2() throws Exception { continue; } Cipher cipher = - Cipher.getInstance(algo+"/CTS/NoPadding", "SunJCE"); + Cipher.getInstance(algo+"/CTS/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); int blockSize = cipher.getBlockSize(); SecretKeySpec key = new SecretKeySpec(new byte[keySize], algo); // Make sure encryption works for inputs with valid length @@ -226,7 +227,8 @@ private static void test2() throws Exception { IvParameterSpec iv2 = new IvParameterSpec(IV2_SRC, 0, blockSize); cipher.init(Cipher.ENCRYPT_MODE, key, iv2); Cipher cipher2 = - Cipher.getInstance(algo+"/CBC/NoPadding", "SunJCE"); + Cipher.getInstance(algo+"/CBC/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); cipher2.init(Cipher.ENCRYPT_MODE, key, iv2); byte[] eout = cipher.doFinal(IV2_SRC, 0, blockSize); @@ -294,7 +296,8 @@ private static void test3() throws Exception { continue; } Cipher cipher = - Cipher.getInstance(algo+ "/CTS/NoPadding", "SunJCE"); + Cipher.getInstance(algo+ "/CTS/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); byte[] plainText = PLAIN1[i]; byte[] cipherText = CIPHER1[i]; byte[] enc = new byte[plainText.length]; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/DES/KeyWrapping.java b/test/jdk/com/sun/crypto/provider/Cipher/DES/KeyWrapping.java index c1447eb3e51ff..a71390b504ef6 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/DES/KeyWrapping.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/DES/KeyWrapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, 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 @@ -24,16 +24,19 @@ /* * @test * @bug 0000000 + * @library /test/lib * @summary KeyWrapping * @author Jan Luehe */ import javax.crypto.*; import java.security.*; +import jdk.test.lib.security.SecurityUtils; public class KeyWrapping { public static void main(String[] args) throws Exception { - Cipher c1 = Cipher.getInstance("DES", "SunJCE"); + Cipher c1 = Cipher.getInstance("DES", + System.getProperty("test.provider.name", "SunJCE")); Cipher c2 = Cipher.getInstance("DES"); KeyGenerator keyGen = KeyGenerator.getInstance("DES"); @@ -70,8 +73,9 @@ public static void main(String[] args) throws Exception { if (!msg.equals(new String(clearText))) throw new Exception("The unwrapped session key is corrupted."); - KeyPairGenerator kpairGen = KeyPairGenerator.getInstance("DSA"); - kpairGen.initialize(1024); + String kpgAlgorithm = "DSA"; + KeyPairGenerator kpairGen = KeyPairGenerator.getInstance(kpgAlgorithm); + kpairGen.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair kpair = kpairGen.genKeyPair(); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/DES/Sealtest.java b/test/jdk/com/sun/crypto/provider/Cipher/DES/Sealtest.java index abc536f14e2f4..d4b2173358cf3 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/DES/Sealtest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/DES/Sealtest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, 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 @@ -24,20 +24,23 @@ /* * @test * @bug 0000000 7055362 + * @library /test/lib * @summary Sealtest * @author Jan Luehe */ import java.io.*; import java.security.*; import javax.crypto.*; +import jdk.test.lib.security.SecurityUtils; public class Sealtest { public static void main(String[] args) throws Exception { // create DSA keypair - KeyPairGenerator kpgen = KeyPairGenerator.getInstance("DSA"); - kpgen.initialize(512); + String kpgAlgorithm = "DSA"; + KeyPairGenerator kpgen = KeyPairGenerator.getInstance(kpgAlgorithm); + kpgen.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair kp = kpgen.generateKeyPair(); // create DES key diff --git a/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/NISTWrapKAT.java b/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/NISTWrapKAT.java index 3da7c7072f0dc..a79f48196d13d 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/NISTWrapKAT.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/NISTWrapKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2021, 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 @@ -259,9 +259,12 @@ public void testKeyWrap(String algo, String key, int keyLen, System.out.println("=> skip, exceeds max allowed size " + allowed); return; } - Cipher c1 = Cipher.getInstance(algo, "SunJCE"); - Cipher c2 = Cipher.getInstance(algo, "SunJCE"); - Cipher c3 = Cipher.getInstance(algo, "SunJCE"); + Cipher c1 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); + Cipher c2 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); + Cipher c3 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); byte[] keyVal = toBytes(key, keyLen << 1); byte[] dataVal = toBytes(data, dataLen << 1); @@ -318,9 +321,12 @@ public void testEnc(String algo, String key, int keyLen, String data, int dataLe System.out.println("=> skip, exceeds max allowed size " + allowed); return; } - Cipher c1 = Cipher.getInstance(algo, "SunJCE"); - Cipher c2 = Cipher.getInstance(algo, "SunJCE"); - Cipher c3 = Cipher.getInstance(algo, "SunJCE"); + Cipher c1 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); + Cipher c2 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); + Cipher c3 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); byte[] keyVal = toBytes(key, keyLen << 1); byte[] dataVal = toBytes(data, dataLen << 1); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestCipherKeyWrapperTest.java b/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestCipherKeyWrapperTest.java index 6a3708bff9ebe..2ae0d91d5928d 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestCipherKeyWrapperTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestCipherKeyWrapperTest.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 @@ -50,15 +50,18 @@ import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; +import jdk.test.lib.security.SecurityUtils; /* * @test * @bug 8048599 8248268 8288050 + * @library /test/lib * @summary Tests for key wrap and unwrap operations */ public class TestCipherKeyWrapperTest { - private static final String SUN_JCE = "SunJCE"; + private static final String PROVIDER_NAME = + System.getProperty("test.provider.name", "SunJCE"); // Blowfish Variable key length: 32 bits to 448 bits private static final int BLOWFISH_MIN_KEYSIZE = 32; private static final int BLOWFISH_MAX_KEYSIZE = 448; @@ -157,14 +160,15 @@ public static void main(String[] args) throws Exception { // PBE and public wrapper test. String[] publicPrivateAlgos = new String[] { "DiffieHellman", "DSA", "RSA" }; - Provider provider = Security.getProvider(SUN_JCE); + Provider provider = Security.getProvider(PROVIDER_NAME); if (provider == null) { - throw new RuntimeException("SUN_JCE provider not exist"); + throw new RuntimeException(PROVIDER_NAME + " provider not exist"); } test.wrapperPBEKeyTest(provider); // Public and private key wrap test - test.wrapperPublicPriviteKeyTest(provider, publicPrivateAlgos); + test.wrapperPublicPriviteKeyTest(provider, publicPrivateAlgos, "DES"); + test.wrapperPublicPriviteKeyTest(provider, publicPrivateAlgos, "AES"); } private void wrapperAesDESedeKeyTest(String algo, String wrapAlgo, @@ -260,7 +264,7 @@ private void wrapperPBEKeyTest(Provider p) throws InvalidKeySpecException, } } - private void wrapperPublicPriviteKeyTest(Provider p, String[] algorithms) + private void wrapperPublicPriviteKeyTest(Provider p, String[] algorithms, String algoWrap) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException { @@ -269,10 +273,9 @@ private void wrapperPublicPriviteKeyTest(Provider p, String[] algorithms) System.out.println("Generate key pair (algorithm: " + algo + ", provider: " + p.getName() + ")"); KeyPairGenerator kpg = KeyPairGenerator.getInstance(algo); - kpg.initialize(512); + kpg.initialize(SecurityUtils.getTestKeySize(algo)); KeyPair kp = kpg.genKeyPair(); // key generated - String algoWrap = "DES"; KeyGenerator kg = KeyGenerator.getInstance(algoWrap, p); Key key = kg.generateKey(); wrapTest(algo, algoWrap, key, kp.getPrivate(), Cipher.PRIVATE_KEY, diff --git a/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestGeneral.java b/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestGeneral.java index bdc36b9a35e82..66bc6d7f7fa44 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestGeneral.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestGeneral.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -220,7 +220,8 @@ public static void main(String[] argv) throws Exception { SecretKey aes256 = new SecretKeySpec(DATA_32, "AES"); SecretKey any256 = new SecretKeySpec(DATA_32, "ANY"); PrivateKey priv = KeyPairGenerator.getInstance - ("RSA", "SunRsaSign").generateKeyPair().getPrivate(); + ("RSA", System.getProperty("test.provider.name", "SunRsaSign")) + .generateKeyPair().getPrivate(); String[] algos = { "AES/KW/PKCS5Padding", "AES/KW/NoPadding", "AES/KWP/NoPadding" @@ -228,7 +229,8 @@ public static void main(String[] argv) throws Exception { for (String a : algos) { System.out.println("Testing " + a); - Cipher c = Cipher.getInstance(a, "SunJCE"); + Cipher c = Cipher.getInstance(a, + System.getProperty("test.provider.name", "SunJCE")); int blkSize = c.getBlockSize(); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestKeySizeCheck.java b/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestKeySizeCheck.java index 4732836d6d99d..ea8ac397ebba8 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestKeySizeCheck.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/TestKeySizeCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,8 @@ public static void test(String algo, int[] invalidKeySizes) throws Exception { System.out.println("Testing " + algo); - Cipher c = Cipher.getInstance(algo, "SunJCE"); + Cipher c = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); int[] modes = { Cipher.ENCRYPT_MODE, Cipher.WRAP_MODE }; for (int ks : invalidKeySizes) { diff --git a/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/XMLEncKAT.java b/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/XMLEncKAT.java index 90cfacf36fd2e..e9d9038ada95c 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/XMLEncKAT.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/KeyWrap/XMLEncKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2007, 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 @@ -111,7 +111,8 @@ public static void testKeyWrap(String cAlg, byte[] cKeyVal, String cKeyAlg, String[] base64Wrapped) throws Exception { System.out.println("Testing " + cAlg + " Cipher with " + 8*cKeyVal.length + "-bit key"); - Cipher c = Cipher.getInstance(cAlg, "SunJCE"); + Cipher c = Cipher.getInstance(cAlg, + System.getProperty("test.provider.name", "SunJCE")); SecretKey cKey = new SecretKeySpec(cKeyVal, cKeyAlg); c.init(Cipher.UNWRAP_MODE, cKey); Key[] key = new SecretKey[base64Wrapped.length]; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/DecryptWithoutParameters.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/DecryptWithoutParameters.java index 35cb5184441d9..f8af47d6e6d26 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/DecryptWithoutParameters.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/DecryptWithoutParameters.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 @@ -113,7 +113,8 @@ public static void main(String argv[]) throws Exception { boolean status = true; for (String algo : PBES1ALGOS) { - Cipher cipher = Cipher.getInstance(algo, "SunJCE"); + Cipher cipher = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); SecretKey key = new SecretKeySpec(new byte[5], algo); status = status && test(cipher, key, null); } @@ -122,7 +123,8 @@ public static void main(String argv[]) throws Exception { int iterCount = 123456; PBEParameterSpec spec = new PBEParameterSpec(salt, iterCount); for (String algo : PBES2ALGOS) { - Cipher cipher = Cipher.getInstance(algo, "SunJCE"); + Cipher cipher = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); SecretKey key = new SecretKeySpec(new byte[5], algo); PBEKey key2 = new MyPBEKey(algo, new PBEKeySpec("phrase".toCharArray(), salt, iterCount)); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java index 9c4cc3663c159..736e0a9fe640b 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/NegativeLength.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 @@ -38,7 +38,9 @@ public class NegativeLength { public static void main(String[] args) throws Exception { SecretKeyFactory skf = SecretKeyFactory.getInstance( - "PBKDF2WithHmacSHA1", "SunJCE"); + "PBKDF2WithHmacSHA1", + System.getProperty("test.provider.name", "SunJCE")); + // Create a valid PBEKeySpec PBEKeySpec pbeks = new PBEKeySpec( diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEInvalidParamsTest.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEInvalidParamsTest.java index bb327b247439c..cc15ac6dbc774 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEInvalidParamsTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEInvalidParamsTest.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 @@ -67,7 +67,8 @@ public static void main(String[] args) throws Exception { System.out.println("=>testing " + algo); SecretKeyFactory skf = SecretKeyFactory.getInstance(algo); SecretKey key = skf.generateSecret(ks); - Cipher c = Cipher.getInstance(algo, "SunJCE"); + Cipher c = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); try { c.init(Cipher.ENCRYPT_MODE, key, INVALID_PARAMS); throw new Exception("Test Failed: expected IAPE is " + diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEKeyCleanupTest.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEKeyCleanupTest.java index 03da1d9c9a9f1..77cf745fb3b70 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEKeyCleanupTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEKeyCleanupTest.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 @@ -23,6 +23,7 @@ /* * @test + * @library /test/lib * @modules java.base/com.sun.crypto.provider:+open * @run main/othervm PBEKeyCleanupTest * @summary Verify that key storage is cleared @@ -38,6 +39,7 @@ import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; +import jdk.test.lib.security.SecurityUtils; /** * Test that the array holding the key bytes is cleared when it is @@ -45,7 +47,8 @@ */ public class PBEKeyCleanupTest { - private final static String SunJCEProvider = "SunJCE"; + private final static String PROVIDER_NAME = + System.getProperty("test.provider.name", "SunJCE"); private static final String PASS_PHRASE = "some hidden string"; private static final int ITERATION_COUNT = 1000; @@ -60,19 +63,19 @@ private static void testPBESecret(String algorithm) throws Exception { char[] password = new char[] {'f', 'o', 'o'}; PBEKeySpec pbeKeySpec = new PBEKeySpec(password); SecretKeyFactory keyFac = - SecretKeyFactory.getInstance(algorithm, SunJCEProvider); + SecretKeyFactory.getInstance(algorithm, PROVIDER_NAME); testCleanupSecret(algorithm, keyFac.generateSecret(pbeKeySpec)); } private static void testPBKSecret(String algorithm) throws Exception { - byte[] salt = new byte[8]; + byte[] salt = new byte[SecurityUtils.getTestSaltSize()]; new Random().nextBytes(salt); char[] password = new char[] {'f', 'o', 'o'}; PBEKeySpec pbeKeySpec = new PBEKeySpec(PASS_PHRASE.toCharArray(), salt, ITERATION_COUNT, KEY_SIZE); SecretKeyFactory keyFac = - SecretKeyFactory.getInstance(algorithm, SunJCEProvider); + SecretKeyFactory.getInstance(algorithm, PROVIDER_NAME); testCleanupSecret(algorithm, keyFac.generateSecret(pbeKeySpec)); } diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEKeysAlgorithmNames.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEKeysAlgorithmNames.java index 9e2debc40f186..2a5a83e45b9b0 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEKeysAlgorithmNames.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEKeysAlgorithmNames.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 @@ -59,7 +59,8 @@ public static void main(String[] argv) throws Exception { for (String s : algs) { System.out.println("Testing " + s); - SecretKeyFactory skf = SecretKeyFactory.getInstance(s, "SunJCE"); + SecretKeyFactory skf = SecretKeyFactory.getInstance(s, + System.getProperty("test.provider.name", "SunJCE")); System.out.println(" Checking skf.getAlgorithm()"); if (!skf.getAlgorithm().equalsIgnoreCase(s)) { diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEParametersTest.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEParametersTest.java index 757a7663d27fe..f380ad58111d7 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEParametersTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBEParametersTest.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 @@ -61,7 +61,8 @@ public static void main(String[] args) throws Exception { String algo = PBE_ALGOS[i]; SecretKeyFactory skf = SecretKeyFactory.getInstance(algo); SecretKey key = skf.generateSecret(ks); - Cipher c = Cipher.getInstance(algo, "SunJCE"); + Cipher c = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); c.init(Cipher.ENCRYPT_MODE, key); c.doFinal(new byte[10]); // force the generation of parameters AlgorithmParameters params = c.getParameters(); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBESameBuffer/PBESameBuffer.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBESameBuffer/PBESameBuffer.java index 4fe20f8cbacd1..cba73f325c649 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBESameBuffer/PBESameBuffer.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBESameBuffer/PBESameBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, 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 @@ -81,7 +81,7 @@ public static void main(String[] args) { public boolean test(String[] args, PrintStream out) { boolean result = true; - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); for (int loop : OFFSETS) { OUTPUT_OFFSET = loop; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBESealedObject.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBESealedObject.java index f7b80ea8eccdc..fdf06edda1bf1 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBESealedObject.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PBESealedObject.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 @@ -80,9 +80,12 @@ public class PBESealedObject { "PBEWithHmacSHA512/256AndAES_256", }; + private static final String PROVIDER_NAME = + System.getProperty("test.provider.name", "SunJCE"); + public static void main(String[] args) { PBESealedObject test = new PBESealedObject(); - Provider sunjce = Security.getProvider("SunJCE"); + Provider sunjce = Security.getProvider(PROVIDER_NAME); if (!test.runAll(sunjce, System.out)) { throw new RuntimeException("One or more tests have failed...."); @@ -163,7 +166,7 @@ public boolean runTest(Provider p, String algo, PrintStream out) return false; } - unsealedKey = (SecretKey) so.getObject(key, "SunJCE"); + unsealedKey = (SecretKey) so.getObject(key, PROVIDER_NAME); return Arrays.equals(unsealedKey.getEncoded(), key.getEncoded()); } catch (InvalidKeyException ex) { if (keyAlgo.endsWith("TRIPLEDES") || keyAlgo.endsWith("AES_256")) { diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PKCS12Cipher.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PKCS12Cipher.java index 9f80b0ae152b9..d19da00b6381f 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PKCS12Cipher.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PKCS12Cipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, 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 @@ -84,7 +84,8 @@ public static void main(String[] argv) throws Exception { new SecureRandom().nextBytes(input); char[] PASSWD = { 'p','a','s','s','w','o','r','d' }; long start = System.currentTimeMillis(); - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + p.getName() + "..."); runTest("PBEWithSHA1AndDESede", input, PASSWD, p); runTest("PBEWithSHA1AndRC2_40", input, PASSWD, p); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PKCS12CipherKAT.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PKCS12CipherKAT.java index 7943e8d228f64..a5911a91ebf23 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/PKCS12CipherKAT.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/PKCS12CipherKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, 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 @@ -179,7 +179,8 @@ private static Test t(String alg, String plaintext, char[] password, static void runTests(Test[] tests) throws Exception { long start = System.currentTimeMillis(); - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + p.getName() + "..."); Cipher.getInstance("PBEWithSHA1AndRC2_40", p); Cipher.getInstance("PBEWithSHA1AndDESede", p); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/TestCipherKeyWrapperPBEKey.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/TestCipherKeyWrapperPBEKey.java index 2f1419a930306..f9e6ca78df060 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/TestCipherKeyWrapperPBEKey.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/TestCipherKeyWrapperPBEKey.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 @@ -83,7 +83,8 @@ public class TestCipherKeyWrapperPBEKey { public static void main(String[] args) { TestCipherKeyWrapperPBEKey test = new TestCipherKeyWrapperPBEKey(); - Provider sunjce = Security.getProvider("SunJCE"); + Provider sunjce = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); if (!test.runAll(sunjce, System.out)) { throw new RuntimeException("One or more tests have failed...."); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java b/test/jdk/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java index e3167068029cc..a3432c1ba937e 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, 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 @@ -40,14 +40,15 @@ public class TestCipherPBECons { private static final String[] PBEAlgorithms = {"pbeWithMD5ANDdes", - "PBEWithMD5AndTripleDES"}; + "PBEWithMD5AndTripleDES", "PBEWithSHA1AndDESede"}; private static final String[] cipherModes = {"ECb", "cbC", "cFB", "Cfb32", "OfB", "oFb64", "pCbC"}; private static final String[] cipherPaddings = {"Pkcs5Padding", "NoPaDDing"}; public static void main(String[] args) { TestCipherPBECons test = new TestCipherPBECons(); - Provider sunjce = Security.getProvider("SunJCE"); + Provider sunjce = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); if (!test.runAll(sunjce, System.out)) { throw new RuntimeException("One or more tests have failed...."); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEP.java b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEP.java index 28d22e22f7533..0775336ca2632 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEP.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,9 +47,10 @@ public class TestOAEP { public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); - cp = Security.getProvider("SunJCE"); + cp = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + cp.getName() + "..."); - Provider kfp = Security.getProvider("SunRsaSign"); + Provider kfp = Security.getProvider( + System.getProperty("test.provider.name", "SunRsaSign")); KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", kfp); kpg.initialize(768); KeyPair kp = kpg.generateKeyPair(); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPPadding.java b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPPadding.java index fe1ca35fcc433..2a82f2214d459 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPPadding.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPPadding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 8020081 8022669 + * @library /test/lib * @summary encryption/decryption test for using OAEPPadding with * OAEPParameterSpec specified and not specified during a Cipher.init(). * @author Anthony Scarpino @@ -43,7 +44,7 @@ import javax.crypto.spec.OAEPParameterSpec; import javax.crypto.IllegalBlockSizeException; import javax.crypto.spec.PSource; - +import jdk.test.lib.security.SecurityUtils; public class TestOAEPPadding { private static RSAPrivateKey privateKey; @@ -52,11 +53,14 @@ public class TestOAEPPadding { static boolean failed = false; public static void main(String args[]) throws Exception { - cp = Security.getProvider("SunJCE"); + cp = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + cp.getName() + "..."); - Provider kfp = Security.getProvider("SunRsaSign"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", kfp); - kpg.initialize(2048); + Provider kfp = Security.getProvider( + System.getProperty("test.providername", "SunRsaSign")); + String kpgAlgorithm = "RSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, kfp); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair kp = kpg.generateKeyPair(); privateKey = (RSAPrivateKey)kp.getPrivate(); publicKey = (RSAPublicKey)kp.getPublic(); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPParameterSpec.java b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPParameterSpec.java index 9f17da2a7117c..8578930dbc1dd 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPParameterSpec.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,8 @@ private static boolean runTest(String mdName, MGF1ParameterSpec mgfSpec, byte[] p) throws Exception { OAEPParameterSpec spec = new OAEPParameterSpec(mdName, "MGF1", mgfSpec, new PSource.PSpecified(p)); - cp = Security.getProvider("SunJCE"); + cp = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + cp.getName() + "..."); AlgorithmParameters ap = AlgorithmParameters.getInstance("OAEP", cp); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPWithParams.java b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPWithParams.java index 308171d766e2e..6cf66178da7b5 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPWithParams.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEPWithParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 4923484 8146293 + * @library /test/lib * @summary encryption/decryption test for using OAEPParameterSpec. * @author Valerie Peng */ @@ -35,6 +36,7 @@ import javax.crypto.*; import javax.crypto.spec.PSource; import javax.crypto.spec.OAEPParameterSpec; +import jdk.test.lib.security.SecurityUtils; public class TestOAEPWithParams { @@ -54,11 +56,14 @@ public class TestOAEPWithParams { }; public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); - cp = Security.getProvider("SunJCE"); + cp = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + cp.getName() + "..."); - Provider kfp = Security.getProvider("SunRsaSign"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", kfp); - kpg.initialize(768); + Provider kfp = Security.getProvider( + System.getProperty("test.provider.name", "SunRsaSign")); + String kpgAlgorithm = "RSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, kfp); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair kp = kpg.generateKeyPair(); privateKey = kp.getPrivate(); publicKey = kp.getPublic(); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEP_KAT.java b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEP_KAT.java index 6d43ce1a715d9..3cbbfc3ba3ff8 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEP_KAT.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestOAEP_KAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, 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 @@ -57,8 +57,10 @@ public class TestOAEP_KAT { public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); - Provider provider = Security.getProvider("SunJCE"); - Provider kfProvider = Security.getProvider("SunRsaSign"); + Provider provider = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); + Provider kfProvider = Security.getProvider( + System.getProperty("test.provider.name", "SunRsaSign")); System.out.println("Testing provider " + provider.getName() + "..."); Cipher c = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding", provider); KeyFactory kf = KeyFactory.getInstance("RSA", kfProvider); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestRSA.java b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestRSA.java index 1e4c6ed10b123..610890a5247e7 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestRSA.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/RSA/TestRSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, 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 @@ -101,20 +101,28 @@ private static int nextNibble(StringReader r) throws IOException { } private final static BigInteger N = new BigInteger - ("116231208661367609700141079576488663663527180869991078124978203037949869" - +"312762870627991319537001781149083155962615105864954367253799351549459177" - +"839995715202060014346744789001273681801687605044315560723525700773069112" - +"214443196787519930666193675297582113726306864236010438506452172563580739" - +"994193451997175316921"); + ("188266606413163647033284152746165049309898453322378171182320013745371408" + +"184225151227340555539225381200565037956400694325061098310480360339435446" + +"755336872372614880713694669514510970895097323213784523223711244354375506" + +"545371740274561954822416119304686041493350049135717091225288845575963270" + +"990119098295690603875646206002898855577388327774594330896529948536446408" + +"529165060686851725546480612209956477350581924733034990053737541249952501" + +"521769091148873248215142518797910690254486909784694829645856181407041627" + +"170373444275842961547787746324163594572697634605250977434548015081503826" + +"85269006571608614747965903308253511034583"); private final static BigInteger E = BigInteger.valueOf(65537); private final static BigInteger D = new BigInteger - ("528278531576995741358027120152717979850387435582102361125581844437708890" - +"736418759997555187916546691958396015481089485084669078137376029510618510" - +"203389286674134146181629472813419906337170366867244770096128371742241254" - +"843638089774095747779777512895029847721754360216404183209801002443859648" - +"26168432372077852785"); + ("559658959270449023652159986632594861346314765962941829914811303419116045" + +"486272857832294696380057096672262714220410818939360476461317579410769250" + +"330981320689411092912185059149606517928125605236733543203155054153225543" + +"370812803235323701309554652228655108862291812277980776744407549833834128" + +"186640306349843950814414209051640048163781518404082259622597528271617305" + +"214590875955949331568915021275293633454662841999317653268823194135508673" + +"577887397954709453731172900970199673444683653554380810128925964066225098" + +"009484055412274405773246950554037029408478181447349886871279557912030178" + +"079306593910311097342934485929224862873"); private final static Random RANDOM = new Random(); @@ -154,21 +162,22 @@ public static void testKat(String alg, int mode, Key key, String in, String out, } private final static String in2 = "0f:7d:6c:20:75:99:a5:bc:c1:53:b0:4e:8d:ef:98:fb:cf:2d:e5:1d:d4:bf:71:56:12:b7:a3:c3:e4:53:1b:07:d3:bb:94:a7:a7:28:75:1e:83:46:c9:80:4e:3f:ac:b2:47:06:9f:1b:68:38:73:b8:69:9e:6b:8b:8b:23:60:31:ae:ea:36:24:6f:85:af:de:a5:2a:88:7d:6a:9f:8a:9f:61:f6:59:3f:a8:ce:91:75:49:e9:34:b8:9f:b6:21:8c"; - private final static String out2 = "7d:84:d1:3a:dc:ac:46:09:3a:0c:e5:4b:85:5d:fa:bb:52:f1:0f:de:d9:87:ef:b3:f7:c8:e3:9a:29:be:e9:b5:51:57:fd:07:5b:3c:1c:1c:56:aa:0c:a6:3f:79:40:16:ee:2c:2c:2e:fe:b8:3e:fd:45:90:1c:e7:87:1d:0a:0a:c5:de:9d:2b:a9:dd:77:d2:89:ba:98:fe:78:5b:a3:91:b4:ac:b5:ae:ce:45:21:f7:74:97:3e:a9:58:59:bc:14:13:02:3f:09:7b:97:90:b3:bd:53:cb:15:c0:6e:36:ea:d4:a3:3e:fc:94:85:a9:66:7f:57:b4:2a:ae:70:2e:fb"; + private final static String out2 = "4d:17:15:23:d9:f6:97:4d:4b:5b:9b:37:bd:a7:c5:33:b9:40:1f:c4:63:fa:7c:2a:fb:19:0b:d8:c4:3a:bd:e7:46:6b:1b:09:20:93:39:7c:e5:5f:7b:83:a7:a6:f6:f5:42:20:e7:7f:d3:14:9a:14:25:f9:31:9e:3c:c9:04:20:be:31:ac:77:45:37:4d:76:1b:10:3a:aa:42:c7:df:4c:61:a4:35:4d:28:41:c2:f9:b7:ce:00:94:42:06:c7:35:06:ca:f2:9e:96:c3:89:54:10:82:d8:de:f3:6c:23:8c:47:41:5a:13:fa:33:e0:a5:7f:ec:43:5d:b0:ea:c9:43:17:72:73:ce:11:48:fb:19:ee:13:6a:92:13:06:5c:55:dc:9e:86:b9:fb:44:62:44:9e:a9:e8:bd:6a:c0:c1:64:4b:fd:a9:5d:ef:59:1e:16:fe:64:c1:07:31:9e:9f:4d:4e:28:34:ea:39:e0:65:68:d4:8b:02:0b:8b:ed:bb:a6:a6:4a:29:b9:b5:08:f3:7a:a8:fd:03:3e:0d:d0:9e:25:47:2c:45:f2:40:39:58:e8:95:64:04:2b:50:1e:a5:ff:00:a4:cf:a9:13:4b:17:3a:e8:d1:2c:c1:4a:ab:1c:07:b4:b5:f6:c9:3f:38:48:89:55:59:00:c1:25:c9:d7:68"; private final static String in1 = "17:a3:a7:b1:86:29:06:c5:81:33:cd:2f:da:32:7c:0e:26:a8:18:aa:37:9b:dd:4a:b0:b0:a7:1c:14:82:6c:d9:c9:14:9f:55:19:91:02:0d:d9:d7:95:c2:2b:a6:fa:ba:a3:51:00:83:6b:ec:97:27:40:a3:8f:ba:b1:09:15:11:44:33:c6:3c:47:95:50:71:50:5a:f4:aa:00:4e:b9:48:6a:b1:34:e9:d0:c8:b8:92:bf:95:f3:3d:91:66:93:2b"; - private final static String out1 = "28:b7:b4:73:f2:16:11:c0:67:70:96:ee:dc:3e:23:87:9f:30:a7:e5:f0:db:aa:67:33:27:0e:75:79:af:29:f5:88:3d:93:22:14:d2:59:b4:eb:ce:95:7f:24:74:df:f2:aa:4d:e6:65:5a:63:6d:64:30:ef:31:f1:a6:df:17:42:b6:d1:ed:22:1f:b0:96:69:9d:f8:ce:ff:3a:47:96:51:ba:d9:8d:57:39:40:dc:fc:d3:03:92:39:f4:dd:4b:1b:07:8b:33:60:27:2d:5f:c6:cf:17:92:c6:12:69:a3:54:2e:b8:0f:ca:d9:46:0f:da:95:34:d0:84:35:9c:f6:44"; + private final static String out1 = "18:6d:d2:89:43:cb:ec:5c:ff:3d:fd:d5:23:2d:aa:fc:db:a7:63:5f:c7:2d:6f:81:c2:9f:aa:47:ed:fc:79:39:8a:6d:8f:c3:d0:f9:64:c3:e1:5f:1a:b3:20:03:1e:8a:3a:c5:58:ef:78:6b:fc:50:98:0a:11:d3:30:d9:68:44:9b:93:a6:b3:92:8f:09:0c:7a:d0:64:ac:e2:c7:b5:6a:37:35:00:3b:4e:d7:64:fb:54:c2:54:90:b9:71:6a:48:c4:6c:1e:e4:e6:4c:3f:fc:34:69:16:b9:53:8c:9f:30:4e:2e:7e:9c:fb:5f:26:18:c0:6e:69:32:18:30:40:59:8c:d1:c2:7a:41:75:06:9d:1c:0f:14:74:a9:f0:47:3a:97:0d:c4:c6:3f:24:ee:ed:c5:f8:2c:b6:ae:1d:e5:64:33:cd:e1:e0:21:d6:10:c0:8b:59:06:59:81:73:28:b4:f4:ef:fa:e8:67:a8:65:a5:e4:3c:c3:7e:99:f8:55:7a:e9:0d:41:3a:bf:c1:8c:41:f3:71:32:b6:c0:05:8b:91:8a:90:35:60:95:52:78:8e:a7:e5:a9:a1:bf:a3:de:55:c6:02:03:d5:98:01:59:fb:91:da:37:9e:3f:39:85:e1:3f:79:23:6c:0e:68:25:4c:13:3a:52:a2:f8:d9:4c:ce"; - private final static String rin1 = "09:01:06:53:a7:96:09:63:ef:e1:3f:e9:8d:95:22:d1:0e:1b:87:c1:a2:41:b2:09:97:a3:5e:e0:a4:1d:59:91:21:e4:ca:87:bf:77:4a:7e:a2:22:ff:59:1e:bd:a4:80:aa:93:4a:41:56:95:5b:f4:57:df:fc:52:2f:46:9b:45:d7:03:ae:22:8e:67:9e:6c:b9:95:4f:bd:8e:e8:67:90:5b:fe:de:2f:11:22:2e:9d:30:93:6d:c0:48:00:cb:08:b9:c4:36:e9:03:7c:08:2d:68:42:cb:71:d0:7d:47:22:c1:58:c5:b8:2f:28:3e:98:78:11:6d:71:5b:3b:36:3c"; - private final static String rout1 = "4a:21:64:20:56:5f:27:0c:90:1d:f3:1b:64:8e:16:d3:af:79:ca:c6:65:56:19:77:8f:25:35:70:be:f3:15:b3:e3:d8:8f:04:ec:c3:60:59:d0:9a:66:be:1c:ad:f7:09:46:a9:09:46:12:5f:28:b6:28:b1:53:fb:fe:07:73:b8:8b:f8:83:64:8e:2d:45:ca:1a:fd:85:4a:2c:fa:fc:e6:58:f7:e4:83:68:8c:38:49:2b:f3:5c:c1:2d:24:6a:cd:22:6d:cb:f4:f1:8c:9e:1a:94:a7:4b:6f:d1:b4:b4:ab:56:8b:a3:a9:89:88:c3:5d:a8:47:2a:67:50:32:71:19"; + private final static String rin1 = "09:01:06:53:a7:96:09:63:ef:e1:3f:e9:8d:95:22:d1:0e:1b:87:c1:a2:41:b2:09:97:a3:5e:e0:a4:1d:59:91:21:e4:ca:87:bf:77:4a:7e:a2:22:ff:59:1e:bd:a4:80:aa:93:4a:41:56:95:5b:f4:57:df:fc:52:2f:46:9b:45:d7:03:ae:22:8e:67:9e:6c:b9:95:4f:bd:8e:e8:67:90:5b:fe:de:2f:11:22:2e:9d:30:93:6d:c0:48:00:cb:08:b9:c4:36:e9:03:7c:08:2d:68:42:cb:71:d0:7d:47:22:c1:58:c5:b8:2f:28:3e:98:78:11:6d:71:5b:3b:36:3c:09:01:06:53:a7:96:09:63:ef:e1:3f:e9:8d:95:22:d1:0e:1b:87:c1:a2:41:b2:09:97:a3:5e:e0:a4:1d:59:91:21:e4:ca:87:bf:77:4a:7e:a2:22:ff:59:1e:bd:a4:80:aa:93:4a:41:56:95:5b:f4:57:df:fc:52:2f:46:9b:45:d7:03:ae:22:8e:67:9e:6c:b9:95:4f:bd:8e:e8:67:90:5b:fe:de:2f:11:22:2e:9d:30:93:6d:c0:48:00:cb:08:b9:c4:36:e9:03:7c:08:2d:68:42:cb:71:d0:7d:47:22:c1:58:c5:b8:2f:28:3e:98:78:11:6d:71:5b:3b:36:3c"; + private final static String rout1 = "19:dd:a2:f9:57:d4:6b:60:85:ec:2d:5d:f9:64:f8:a0:c0:33:36:a2:8c:59:0f:74:9b:62:a8:ad:42:ed:be:34:0e:dc:13:db:d5:b9:aa:64:38:35:18:d7:6c:1d:da:5b:ff:f2:98:f5:fc:67:36:fb:9f:84:df:84:a3:af:ce:02:e5:05:ca:a7:e4:29:c0:5c:55:6a:8d:dc:8f:f7:6e:d4:ee:2e:6c:5b:ea:f8:bf:4c:7d:5f:af:6a:c3:77:02:80:33:be:13:4c:98:cf:dc:aa:e8:7d:73:69:6e:30:2c:35:c5:90:83:45:0d:64:04:af:b6:94:c3:a8:e2:d4:08:98:1d:b1:73:e3:fc:10:1f:71:0f:d0:13:f3:58:80:c4:a3:a9:02:52:cf:aa:41:b6:9b:69:33:9d:2a:d6:f6:02:07:ec:ce:19:01:f1:2f:90:27:fe:00:a5:d7:8d:01:97:36:fd:88:34:2f:f3:ab:38:ed:9d:69:91:af:b2:0d:ca:92:ca:9e:e7:24:37:d6:e3:c7:02:30:69:5b:ea:b4:b2:68:5f:4e:8c:cc:fd:bb:2e:96:2f:a3:c6:f7:71:93:24:5c:ca:8f:bc:f9:d8:bd:d3:b9:d1:16:ba:5a:ac:62:41:b4:d8:56:45:74:55:c2:a5:ef:23:f5:e3:27:ce:99:97:e9"; - private final static String rin2 = "1b:49:a6:7a:83:1c:b6:28:47:16:2f:be:6a:d3:28:a6:83:07:4f:50:be:5c:99:26:2a:15:b8:21:a8:cc:8a:45:93:07:ff:32:67:3c:a4:92:d2:cd:43:eb:f5:2e:09:79:c8:32:3a:9d:00:4c:f5:6e:65:b2:ca:9c:c2:d5:35:8e:fe:6c:ba:1a:7b:65:c1:4f:e9:6c:cb:5d:9f:13:5d:5f:be:32:cd:91:ed:8b:d7:d7:e9:d6:5c:cc:11:7b:d9:ff:7a:93:de:e4:81:92:56:0c:52:47:75:56:a8:e0:9a:55:16:0c:43:df:ae:be:a1:6a:9d:5a:be:fc:51:ea:52:0c"; - private final static String rout2 = "65:28:b9:48:8d:68:3f:5e:9a:85:e7:09:78:4c:0c:0e:60:6c:89:43:3c:d3:72:b9:2f:5a:eb:4f:15:77:93:9d:47:05:a6:52:48:72:ee:ce:e8:5a:6d:28:b0:06:5a:a1:93:58:a1:61:3f:9b:42:0d:c1:ec:32:0a:7a:1e:38:45:47:87:52:16:62:c9:44:c6:04:4d:82:64:01:f4:b1:26:dc:7f:61:82:52:7a:f6:6b:ab:22:98:87:93:63:4c:3f:92:c7:5b:cc:e5:2b:15:db:f7:d3:c7:b5:38:6f:15:3b:1e:88:3d:31:0c:b4:f9:6d:66:41:b7:1b:a0:4a:b8:16"; + private final static String rin2 = "1b:49:a6:7a:83:1c:b6:28:47:16:2f:be:6a:d3:28:a6:83:07:4f:50:be:5c:99:26:2a:15:b8:21:a8:cc:8a:45:93:07:ff:32:67:3c:a4:92:d2:cd:43:eb:f5:2e:09:79:c8:32:3a:9d:00:4c:f5:6e:65:b2:ca:9c:c2:d5:35:8e:fe:6c:ba:1a:7b:65:c1:4f:e9:6c:cb:5d:9f:13:5d:5f:be:32:cd:91:ed:8b:d7:d7:e9:d6:5c:cc:11:7b:d9:ff:7a:93:de:e4:81:92:56:0c:52:47:75:56:a8:e0:9a:55:16:0c:43:df:ae:be:a1:6a:9d:5a:be:fc:51:ea:52:0c:1b:49:a6:7a:83:1c:b6:28:47:16:2f:be:6a:d3:28:a6:83:07:4f:50:be:5c:99:26:2a:15:b8:21:a8:cc:8a:45:93:07:ff:32:67:3c:a4:92:d2:cd:43:eb:f5:2e:09:79:c8:32:3a:9d:00:4c:f5:6e:65:b2:ca:9c:c2:d5:35:8e:fe:6c:ba:1a:7b:65:c1:4f:e9:6c:cb:5d:9f:13:5d:5f:be:32:cd:91:ed:8b:d7:d7:e9:d6:5c:cc:11:7b:d9:ff:7a:93:de:e4:81:92:56:0c:52:47:75:56:a8:e0:9a:55:16:0c:43:df:ae:be:a1:6a:9d:5a:be:fc:51:ea:52:0c"; + private final static String rout2 = "7a:11:19:cf:76:97:4b:29:48:66:69:e7:f0:db:18:53:d4:50:71:a4:9d:90:47:9f:e6:8a:f3:ba:2e:96:fd:c8:4b:02:7e:06:a9:2b:47:0d:68:3c:6a:f9:21:62:77:0d:4e:e1:1b:82:97:66:13:01:c2:3b:b2:d3:f8:9e:cc:c9:2a:1a:76:05:3f:d4:f7:fb:9d:9b:bf:a8:2d:fd:81:e5:f4:bb:ca:3b:5f:93:ea:ef:88:1c:c1:18:52:38:be:50:42:29:08:d9:65:43:5f:01:7d:50:22:7a:2f:f1:29:14:95:30:c1:b8:fd:eb:da:c1:4e:8a:ef:97:84:f9:cf:34:ab:89:a6:3c:4a:ff:a4:98:a8:7c:c6:2c:c3:e3:10:a9:8b:67:32:47:35:37:15:03:3b:d0:f3:23:fc:bb:42:64:a2:ba:63:3e:94:6e:7a:e6:94:05:79:29:28:d5:99:5b:f9:67:fd:ea:d3:5f:b5:7b:f4:10:9b:0a:1c:20:6b:0c:59:56:76:45:07:56:cb:d0:ab:08:fc:19:8e:f1:27:03:22:f1:e9:23:d3:01:b1:4d:cf:96:f7:a6:44:59:de:2a:52:fd:bb:14:ae:39:c4:e4:0f:4e:10:f7:c6:61:79:0a:a6:4c:ed:ee:d7:40:fe:ef:f3:85:ae:3e:f3:bb:6e:de"; public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); - p = Security.getProvider("SunJCE"); + p = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + p.getName() + "..."); KeyFactory kf; @@ -189,8 +198,8 @@ public static void main(String[] args) throws Exception { // blocktype 1 testEncDec("RSA/ECB/PKCS1Padding", 96, privateKey, publicKey); - testEncDec("RSA/ECB/NoPadding", 128, publicKey, privateKey); - testEncDec("RSA/ECB/NoPadding", 128, privateKey, publicKey); + testEncDec("RSA/ECB/NoPadding", 256, publicKey, privateKey); + testEncDec("RSA/ECB/NoPadding", 256, privateKey, publicKey); // expected failure, blocktype 2 random padding bytes are different testKat("RSA/ECB/PKCS1Padding", Cipher.ENCRYPT_MODE, publicKey, in2, out2, false); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/TestCipher.java b/test/jdk/com/sun/crypto/provider/Cipher/TestCipher.java index b5e50c842a0cd..dd3568f2e19e8 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/TestCipher.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/TestCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, 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 @@ -44,7 +44,7 @@ */ public abstract class TestCipher { - private final String SUNJCE = "SunJCE"; + private final String PROVIDER_NAME = System.getProperty("test.provider.name", "SunJCE"); private final String ALGORITHM; private final String[] MODES; private final String[] PADDINGS; @@ -138,8 +138,8 @@ private void runTest(String mo, String pad, int keySize) out.println("Testing: " + TRANSFORMATION); // Initialization - Cipher ci = Cipher.getInstance(TRANSFORMATION, SUNJCE); - KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM, SUNJCE); + Cipher ci = Cipher.getInstance(TRANSFORMATION, PROVIDER_NAME); + KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM, PROVIDER_NAME); if (keySize != 0) { kg.init(keySize); } diff --git a/test/jdk/com/sun/crypto/provider/Cipher/TextLength/SameBufferOverwrite.java b/test/jdk/com/sun/crypto/provider/Cipher/TextLength/SameBufferOverwrite.java index d110c05a339ef..22da35e7e6b51 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/TextLength/SameBufferOverwrite.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/TextLength/SameBufferOverwrite.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 @@ -44,9 +44,11 @@ public class SameBufferOverwrite { SameBufferOverwrite(String algo, String transformation) throws Exception { - KeyGenerator kg = KeyGenerator.getInstance(algo, "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); skey = kg.generateKey(); - c = Cipher.getInstance(transformation, "SunJCE"); + c = Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); } /* diff --git a/test/jdk/com/sun/crypto/provider/Cipher/UTIL/StrongOrUnlimited.java b/test/jdk/com/sun/crypto/provider/Cipher/UTIL/StrongOrUnlimited.java index 70908a2374680..5c806df25bd7b 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/UTIL/StrongOrUnlimited.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/UTIL/StrongOrUnlimited.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2007, 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 @@ -38,7 +38,8 @@ public static void main(String[] args) throws Exception { // decide if the installed jurisdiction policy file is the // unlimited version boolean isUnlimited = true; - Cipher c = Cipher.getInstance("AES", "SunJCE"); + Cipher c = Cipher.getInstance("AES", + System.getProperty("test.provider.name", "SunJCE")); try { c.init(Cipher.ENCRYPT_MODE, diff --git a/test/jdk/com/sun/crypto/provider/Cipher/UTIL/SunJCEGetInstance.java b/test/jdk/com/sun/crypto/provider/Cipher/UTIL/SunJCEGetInstance.java index d9bf59b63f07b..6ba7f9a0d695c 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/UTIL/SunJCEGetInstance.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/UTIL/SunJCEGetInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, 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,9 +40,10 @@ public static void main(String[] args) throws Exception { Cipher jce; try{ + String providerName = System.getProperty("test.provider.name", "SunJCE"); // Remove SunJCE from Provider list - Provider prov = Security.getProvider("SunJCE"); - Security.removeProvider("SunJCE"); + Provider prov = Security.getProvider(providerName); + Security.removeProvider(providerName); // Create our own instance of SunJCE provider. Purposefully not // using SunJCE.getInstance() so we can have our own instance // for the test. diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHGenSharedSecret.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHGenSharedSecret.java index 34e87030636ac..9fe96d967dcbb 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHGenSharedSecret.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHGenSharedSecret.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, 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,6 +24,7 @@ /* * @test * @bug 0000000 + * @library /test/lib * @summary DHGenSharedSecret * @author Jan Luehe */ @@ -33,40 +34,11 @@ import javax.crypto.*; import javax.crypto.spec.*; import java.math.BigInteger; +import jdk.test.lib.security.DiffieHellmanGroup; +import jdk.test.lib.security.SecurityUtils; public class DHGenSharedSecret { - static byte[] DHPrime = { -(byte)0x00, (byte)0x8D, (byte)0x8A, (byte)0x6C, (byte)0x7F, (byte)0xCC, -(byte)0xA5, (byte)0xBF, (byte)0x9C, (byte)0xE1, (byte)0xFA, (byte)0x3C, -(byte)0xCA, (byte)0x98, (byte)0xB7, (byte)0x99, (byte)0xD1, (byte)0xE5, -(byte)0x2C, (byte)0xC0, (byte)0x26, (byte)0x97, (byte)0x12, (byte)0x80, -(byte)0x12, (byte)0xEF, (byte)0x0B, (byte)0xDE, (byte)0x71, (byte)0x76, -(byte)0xAA, (byte)0x2D, (byte)0x86, (byte)0x41, (byte)0x0E, (byte)0x6A, -(byte)0xC2, (byte)0x12, (byte)0xAA, (byte)0xAA, (byte)0xE4, (byte)0x84, -(byte)0x80, (byte)0x13, (byte)0x95, (byte)0x06, (byte)0xC4, (byte)0x83, -(byte)0xB9, (byte)0xD3, (byte)0x72, (byte)0xC5, (byte)0xC8, (byte)0x85, -(byte)0x96, (byte)0x59, (byte)0x08, (byte)0xFA, (byte)0x9E, (byte)0x3C, -(byte)0xDC, (byte)0x92, (byte)0x28, (byte)0xC3, (byte)0x1D, (byte)0x6F, -(byte)0x44, (byte)0x36, (byte)0x70, (byte)0x40, (byte)0x80, (byte)0xF1, -(byte)0x35 - }; - - static byte[] DHBase = { -(byte)0x72, (byte)0x21, (byte)0xB3, (byte)0xA8, (byte)0x83, (byte)0xDD, -(byte)0x76, (byte)0xF5, (byte)0x0D, (byte)0x9B, (byte)0x81, (byte)0x11, -(byte)0x15, (byte)0x03, (byte)0x6D, (byte)0x4D, (byte)0x46, (byte)0x65, -(byte)0x30, (byte)0xB0, (byte)0xFA, (byte)0xFE, (byte)0xBE, (byte)0xA8, -(byte)0xD9, (byte)0x83, (byte)0x33, (byte)0x54, (byte)0xC7, (byte)0xF6, -(byte)0x81, (byte)0xAC, (byte)0xCC, (byte)0xA3, (byte)0xAE, (byte)0xAA, -(byte)0xC8, (byte)0x11, (byte)0x38, (byte)0xD4, (byte)0x4F, (byte)0xC4, -(byte)0x89, (byte)0xD3, (byte)0x72, (byte)0xEE, (byte)0x22, (byte)0x5A, -(byte)0x68, (byte)0xF7, (byte)0xAC, (byte)0x24, (byte)0x01, (byte)0x9B, -(byte)0xE9, (byte)0x08, (byte)0xFE, (byte)0x58, (byte)0x0A, (byte)0xCF, -(byte)0xB9, (byte)0x52, (byte)0xB4, (byte)0x02, (byte)0x73, (byte)0xA4, -(byte)0xA6, (byte)0xB9, (byte)0x0C, (byte)0x8D, (byte)0xA7, (byte)0xFB, - }; - public static void main(String[] args) throws Exception { DHGenSharedSecret test = new DHGenSharedSecret(); test.run(); @@ -75,8 +47,9 @@ public static void main(String[] args) throws Exception { public void run() throws Exception { long start, end; - BigInteger p = new BigInteger(1, DHPrime); - BigInteger g = new BigInteger(1, DHBase); + DiffieHellmanGroup dhGroup = SecurityUtils.getTestDHGroup(); + BigInteger p = dhGroup.getPrime(); + BigInteger g = new BigInteger(1, dhGroup.getBase().toByteArray()); int l = 512; DHParameterSpec spec = diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreement2.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreement2.java index c7a0c4aeb331b..da583c9dc2915 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreement2.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreement2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 7146728 + * @library /test/lib * @summary DHKeyAgreement2 * @author Jan Luehe * @run main/othervm -Djdk.crypto.KeyAgreement.legacyKDF=true DHKeyAgreement2 @@ -38,13 +39,14 @@ import javax.crypto.*; import javax.crypto.spec.*; import javax.crypto.interfaces.*; +import jdk.test.lib.security.DiffieHellmanGroup; +import jdk.test.lib.security.SecurityUtils; /** * This test utility executes the Diffie-Hellman key agreement protocol * between 2 parties: Alice and Bob. * - * By default, preconfigured parameters (1024 bit prime modulus and base - * generator used by SKIP) are used. + * By default, preconfigured parameters are used. * If this program is called with the "-gen" option, a new set of parameters * are created. */ @@ -59,7 +61,7 @@ public class DHKeyAgreement2 { private DHKeyAgreement2() {} public static void main(String argv[]) throws Exception { - String mode = "USE_SKIP_DH_PARAMS"; + String mode = "USE_PRECONFIGURED_DH_PARAMS"; DHKeyAgreement2 keyAgree = new DHKeyAgreement2(); @@ -80,22 +82,25 @@ public static void main(String argv[]) throws Exception { private void run(String mode) throws Exception { - DHParameterSpec dhSkipParamSpec; + DHParameterSpec dhParameterSpec; + String algorithm = "DH"; + int primeSize = SecurityUtils.getTestKeySize(algorithm); if (mode.equals("GENERATE_DH_PARAMS")) { // Some central authority creates new DH parameters System.err.println("Creating Diffie-Hellman parameters ..."); AlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DH", SUNJCE); - paramGen.init(512); + paramGen.init(primeSize); AlgorithmParameters params = paramGen.generateParameters(); - dhSkipParamSpec = (DHParameterSpec)params.getParameterSpec + dhParameterSpec = (DHParameterSpec)params.getParameterSpec (DHParameterSpec.class); } else { - // use some pre-generated, default DH parameters - System.err.println("Using SKIP Diffie-Hellman parameters"); - dhSkipParamSpec = new DHParameterSpec(skip1024Modulus, - skip1024Base); + // use some pre-generated, test default DH parameters + DiffieHellmanGroup dhGroup = SecurityUtils.getTestDHGroup(primeSize); + System.err.println("Using " + dhGroup.name() + " Diffie-Hellman parameters"); + dhParameterSpec = new DHParameterSpec(dhGroup.getPrime(), + dhGroup.getBase()); } /* @@ -104,7 +109,7 @@ private void run(String mode) throws Exception { */ System.err.println("ALICE: Generate DH keypair ..."); KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH", SUNJCE); - aliceKpairGen.initialize(dhSkipParamSpec); + aliceKpairGen.initialize(dhParameterSpec); KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); System.out.println("Alice DH public key:\n" + aliceKpair.getPublic().toString()); @@ -227,20 +232,26 @@ private void run(String mode) throws Exception { } System.err.println("Shared secrets are the same"); + testSecretKey(bobKeyAgree, alicePubKey, "DES"); + testSecretKey(bobKeyAgree, alicePubKey, "AES"); + } + + private static void testSecretKey(KeyAgreement bobKeyAgree, PublicKey alicePubKey, String algo) + throws Exception { // Now let's return the shared secret as a SecretKey object // and use it for encryption - System.out.println("Return shared secret as SecretKey object ..."); + System.out.println("Return shared secret as SecretKey object with algorithm: " + algo); bobKeyAgree.doPhase(alicePubKey, true); - SecretKey desKey = bobKeyAgree.generateSecret("DES"); + SecretKey key = bobKeyAgree.generateSecret(algo); - Cipher desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); - desCipher.init(Cipher.ENCRYPT_MODE, desKey); + Cipher cipher = Cipher.getInstance(algo + "/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, key); byte[] cleartext = "This is just an example".getBytes(); - byte[] ciphertext = desCipher.doFinal(cleartext); + byte[] ciphertext = cipher.doFinal(cleartext); - desCipher.init(Cipher.DECRYPT_MODE, desKey); - byte[] cleartext1 = desCipher.doFinal(ciphertext); + cipher.init(Cipher.DECRYPT_MODE, key); + byte[] cleartext1 = cipher.doFinal(ciphertext); int clearLen = cleartext.length; int clear1Len = cleartext1.length; @@ -274,47 +285,4 @@ private void usage() { System.err.print("DHKeyAgreement usage: "); System.err.println("[-gen]"); } - - // The 1024 bit Diffie-Hellman modulus values used by SKIP - private static final byte skip1024ModulusBytes[] = { - (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58, - (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD, - (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4, - (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B, - (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D, - (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C, - (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C, - (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6, - (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0, - (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B, - (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB, - (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D, - (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD, - (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43, - (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C, - (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C, - (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C, - (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40, - (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C, - (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72, - (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03, - (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29, - (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C, - (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB, - (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B, - (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08, - (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D, - (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C, - (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22, - (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB, - (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55, - (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7 - }; - - // The SKIP 1024 bit modulus - private static final BigInteger skip1024Modulus - = new BigInteger(1, skip1024ModulusBytes); - - // The base used with the SKIP 1024 bit modulus - private static final BigInteger skip1024Base = BigInteger.valueOf(2); } diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreement3.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreement3.java index 6cdcf1dad2e5b..d4f70ea256364 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreement3.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreement3.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 @@ -24,6 +24,7 @@ /* * @test * @bug 0000000 + * @library /test/lib * @summary DHKeyAgreement3 * @author Jan Luehe */ @@ -37,13 +38,14 @@ import javax.crypto.*; import javax.crypto.spec.*; import javax.crypto.interfaces.*; +import jdk.test.lib.security.DiffieHellmanGroup; +import jdk.test.lib.security.SecurityUtils; /** * This test utility executes the Diffie-Hellman key agreement protocol * between 3 parties: Alice, Bob, and Carol. * - * We use the same 1024 bit prime modulus and base generator that are used by - * SKIP. + * By default, preconfigured parameters are used. */ public class DHKeyAgreement3 { @@ -61,27 +63,27 @@ public static void main(String argv[]) throws Exception { private void run() throws Exception { - DHParameterSpec dhSkipParamSpec; - - System.err.println("Using SKIP Diffie-Hellman parameters"); - dhSkipParamSpec = new DHParameterSpec(skip1024Modulus, skip1024Base); + DiffieHellmanGroup dhGroup = SecurityUtils.getTestDHGroup(); + DHParameterSpec dhParamSpec; + System.err.println("Using " + dhGroup.name() + " Diffie-Hellman parameters"); + dhParamSpec = new DHParameterSpec(dhGroup.getPrime(), dhGroup.getBase()); // Alice creates her own DH key pair System.err.println("ALICE: Generate DH keypair ..."); KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH", "SunJCE"); - aliceKpairGen.initialize(dhSkipParamSpec); + aliceKpairGen.initialize(dhParamSpec); KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); // Bob creates his own DH key pair System.err.println("BOB: Generate DH keypair ..."); KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH", "SunJCE"); - bobKpairGen.initialize(dhSkipParamSpec); + bobKpairGen.initialize(dhParamSpec); KeyPair bobKpair = bobKpairGen.generateKeyPair(); // Carol creates her own DH key pair System.err.println("CAROL: Generate DH keypair ..."); KeyPairGenerator carolKpairGen = KeyPairGenerator.getInstance("DH", "SunJCE"); - carolKpairGen.initialize(dhSkipParamSpec); + carolKpairGen.initialize(dhParamSpec); KeyPair carolKpair = carolKpairGen.generateKeyPair(); @@ -178,47 +180,4 @@ private void usage() { System.err.print("DHKeyAgreement usage: "); System.err.println("[-gen]"); } - - // The 1024 bit Diffie-Hellman modulus values used by SKIP - private static final byte skip1024ModulusBytes[] = { - (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58, - (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD, - (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4, - (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B, - (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D, - (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C, - (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C, - (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6, - (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0, - (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B, - (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB, - (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D, - (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD, - (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43, - (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C, - (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C, - (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C, - (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40, - (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C, - (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72, - (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03, - (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29, - (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C, - (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB, - (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B, - (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08, - (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D, - (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C, - (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22, - (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB, - (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55, - (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7 - }; - - // The SKIP 1024 bit modulus - private static final BigInteger skip1024Modulus - = new BigInteger(1, skip1024ModulusBytes); - - // The base used with the SKIP 1024 bit modulus - private static final BigInteger skip1024Base = BigInteger.valueOf(2); } diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreementPadding.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreementPadding.java index dc963bf62677b..c863da6b4b436 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreementPadding.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreementPadding.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 @@ -34,21 +34,22 @@ import java.security.KeyPairGenerator; import java.util.Arrays; import java.util.HexFormat; +import jdk.test.lib.security.SecurityUtils; public class DHKeyAgreementPadding { public static void main(String[] args) throws Exception { - - byte[] aliceSecret = new byte[80]; - byte[] bobSecret = new byte[80]; - - KeyAgreement alice = KeyAgreement.getInstance("DiffieHellman"); - KeyAgreement bob = KeyAgreement.getInstance("DiffieHellman"); + String kpgAlgorithm = "DiffieHellman"; + KeyAgreement alice = KeyAgreement.getInstance(kpgAlgorithm); + KeyAgreement bob = KeyAgreement.getInstance(kpgAlgorithm); + int keySizeBits = SecurityUtils.getTestKeySize(kpgAlgorithm); + byte[] aliceSecret = new byte[keySizeBits / 8]; + byte[] bobSecret = new byte[keySizeBits / 8]; // The probability of an error is 0.2% or 1/500. Try more times. for (int i = 0; i < 5000; i++) { - KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DiffieHellman"); - keyPairGen.initialize(512); + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(kpgAlgorithm); + keyPairGen.initialize(keySizeBits); KeyPair aliceKeyPair = keyPairGen.generateKeyPair(); KeyPair bobKeyPair = keyPairGen.generateKeyPair(); diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyFactory.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyFactory.java index e12f3871ec23c..356cfc4b20a06 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyFactory.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 0000000 + * @library /test/lib * @summary DHKeyFactory * @author Jan Luehe */ @@ -36,6 +37,8 @@ import javax.crypto.*; import javax.crypto.spec.*; import javax.crypto.interfaces.*; +import jdk.test.lib.security.DiffieHellmanGroup; +import jdk.test.lib.security.SecurityUtils; /** * This test creates a DH keypair, retrieves the encodings of the DH public and @@ -55,15 +58,13 @@ public static void main(String argv[]) throws Exception { private void run() throws Exception { - DHParameterSpec dhSkipParamSpec; + DiffieHellmanGroup dhGroup = SecurityUtils.getTestDHGroup(); + DHParameterSpec dhParamSpec = new DHParameterSpec(dhGroup.getPrime(), dhGroup.getBase()); + System.out.println("Using " + dhGroup.name() + " Diffie-Hellman parameters"); - // use some pre-generated, default DH parameters - System.err.println("Using SKIP Diffie-Hellman parameters"); - dhSkipParamSpec = new DHParameterSpec(skip1024Modulus, - skip1024Base); - - KeyPairGenerator kpgen = KeyPairGenerator.getInstance("DH", "SunJCE"); - kpgen.initialize(dhSkipParamSpec); + KeyPairGenerator kpgen = KeyPairGenerator.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); + kpgen.initialize(dhParamSpec); KeyPair kp = kpgen.generateKeyPair(); // get the public key encoding @@ -72,7 +73,8 @@ private void run() throws Exception { // get the private key encoding byte[] privKeyEnc = kp.getPrivate().getEncoded(); - KeyFactory kfac = KeyFactory.getInstance("DH", "SunJCE"); + KeyFactory kfac = KeyFactory.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKeyEnc); PublicKey pubKey = kfac.generatePublic(x509KeySpec); @@ -80,47 +82,4 @@ private void run() throws Exception { PKCS8EncodedKeySpec pkcsKeySpec = new PKCS8EncodedKeySpec(privKeyEnc); PrivateKey privKey = kfac.generatePrivate(pkcsKeySpec); } - - // The 1024 bit Diffie-Hellman modulus values used by SKIP - private static final byte skip1024ModulusBytes[] = { - (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58, - (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD, - (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4, - (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B, - (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D, - (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C, - (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C, - (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6, - (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0, - (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B, - (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB, - (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D, - (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD, - (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43, - (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C, - (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C, - (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C, - (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40, - (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C, - (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72, - (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03, - (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29, - (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C, - (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB, - (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B, - (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08, - (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D, - (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C, - (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22, - (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB, - (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55, - (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7 - }; - - // The SKIP 1024 bit modulus - private static final BigInteger skip1024Modulus - = new BigInteger(1, skip1024ModulusBytes); - - // The base used with the SKIP 1024 bit modulus - private static final BigInteger skip1024Base = BigInteger.valueOf(2); } diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyGenSpeed.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyGenSpeed.java index b24f0a66fb906..723ce11760b17 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyGenSpeed.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyGenSpeed.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, 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,6 +24,7 @@ /* * @test * @bug 0000000 + * @library /test/lib * @summary DHKeyGenSpeed * @author Jan Luehe */ @@ -33,42 +34,11 @@ import javax.crypto.*; import javax.crypto.spec.*; import java.math.*; +import jdk.test.lib.security.DiffieHellmanGroup; +import jdk.test.lib.security.SecurityUtils; public class DHKeyGenSpeed { - static byte[] DHPrime = { -(byte)0x00, (byte)0x91, (byte)0x18, (byte)0x26, (byte)0x9A, (byte)0x26, -(byte)0x43, (byte)0xA6, (byte)0x1E, (byte)0x11, (byte)0x02, (byte)0xA0, -(byte)0x88, (byte)0xFE, (byte)0x12, (byte)0xEA, (byte)0x63, (byte)0x20, -(byte)0x6D, (byte)0x4F, (byte)0x40, (byte)0x3C, (byte)0x4F, (byte)0x13, -(byte)0x10, (byte)0x97, (byte)0xEC, (byte)0x3A, (byte)0x38, (byte)0x87, -(byte)0x9B, (byte)0x08, (byte)0x66, (byte)0x0C, (byte)0x82, (byte)0xD0, -(byte)0x57, (byte)0xE0, (byte)0x37, (byte)0x16, (byte)0x8E, (byte)0xB4, -(byte)0xEA, (byte)0xB7, (byte)0xE6, (byte)0xAF, (byte)0x4C, (byte)0xE0, -(byte)0x40, (byte)0x07, (byte)0xF4, (byte)0x81, (byte)0xDD, (byte)0x36, -(byte)0x33, (byte)0xAD, (byte)0x92, (byte)0xC6, (byte)0x0F, (byte)0xB5, -(byte)0xE4, (byte)0x0F, (byte)0x0E, (byte)0xEA, (byte)0x91, (byte)0x35, -(byte)0xFB, (byte)0x55, (byte)0x7A, (byte)0x39, (byte)0xD1, (byte)0xF0, -(byte)0x6B, (byte)0x9A, (byte)0xB9, (byte)0xFA, (byte)0x19, (byte)0xBE, -(byte)0x1B, (byte)0xFD, (byte)0x77 - }; - static byte[] DHBase = { -(byte)0x29, (byte)0xF2, (byte)0x29, (byte)0xC8, (byte)0x42, (byte)0x25, -(byte)0x29, (byte)0xC3, (byte)0xF2, (byte)0xAA, (byte)0xF2, (byte)0x6A, -(byte)0x3C, (byte)0xD2, (byte)0xD2, (byte)0xDE, (byte)0xD3, (byte)0x6B, -(byte)0x85, (byte)0xA5, (byte)0xE1, (byte)0x43, (byte)0x90, (byte)0xA2, -(byte)0xB6, (byte)0xA5, (byte)0x0C, (byte)0xBA, (byte)0xB9, (byte)0x4C, -(byte)0x25, (byte)0xE0, (byte)0xC8, (byte)0xEA, (byte)0xA1, (byte)0x7B, -(byte)0xB9, (byte)0xF8, (byte)0xFF, (byte)0x15, (byte)0x66, (byte)0x5B, -(byte)0xB0, (byte)0x00, (byte)0x18, (byte)0xE2, (byte)0xF4, (byte)0xF1, -(byte)0xB4, (byte)0x7A, (byte)0xC2, (byte)0xCF, (byte)0x9C, (byte)0x61, -(byte)0x36, (byte)0xED, (byte)0x14, (byte)0x72, (byte)0xD7, (byte)0xD4, -(byte)0x94, (byte)0x20, (byte)0x5E, (byte)0x1E, (byte)0xE4, (byte)0xB1, -(byte)0x60, (byte)0xC8, (byte)0x10, (byte)0x85, (byte)0xBD, (byte)0x74, -(byte)0x34, (byte)0x8C, (byte)0x3C, (byte)0x2A, (byte)0xBD, (byte)0x3C, -(byte)0xFF, (byte)0x14 - }; - public static void main(String[] args) throws Exception { DHKeyGenSpeed test = new DHKeyGenSpeed(); test.run(); @@ -78,8 +48,9 @@ public static void main(String[] args) throws Exception { public void run() throws Exception { long start, end; - BigInteger p = new BigInteger(1, DHPrime); - BigInteger g = new BigInteger(1, DHBase); + DiffieHellmanGroup dhGroup = SecurityUtils.getTestDHGroup(); + BigInteger p = dhGroup.getPrime(); + BigInteger g = new BigInteger(1, dhGroup.getBase().toByteArray()); int l = 576; DHParameterSpec spec = @@ -87,14 +58,15 @@ public void run() throws Exception { // generate keyPairs using parameters KeyPairGenerator keyGen = - KeyPairGenerator.getInstance("DH", "SunJCE"); + KeyPairGenerator.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); start = System.currentTimeMillis(); keyGen.initialize(spec); KeyPair keys = keyGen.generateKeyPair(); end = System.currentTimeMillis(); System.out.println("PrimeBits\tExponentBits"); - System.out.println(DHPrime.length*8 + "\t\t" + l); + System.out.println(dhGroup.getPrime().bitLength() + "\t\t" + l); System.out.println("keyGen(millisecond): " + (end - start)); System.out.println("Test Passed!"); } diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/SameDHKeyStressTest.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/SameDHKeyStressTest.java index 910104b98c56e..9b7eec95d6dcd 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/SameDHKeyStressTest.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/SameDHKeyStressTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, 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 @@ -78,7 +78,8 @@ public static boolean runTest(String algo, int numParties, String secretAlgo) { Key[] keyArchives = new Key[numParties]; try { // generate AlogirhtmParameterSpec - AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance("DH","SunJCE"); + AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); AlgorithmParameterSpec aps = new DHGenParameterSpec(512, 64); apg.init(aps); DHParameterSpec spec = apg.generateParameters(). @@ -139,8 +140,10 @@ class KAParticipant { public KAParticipant(String pName, String algo) throws NoSuchAlgorithmException, NoSuchProviderException { name = pName; algorithm = algo; - keyGen = KeyPairGenerator.getInstance(algo,"SunJCE"); - ka = KeyAgreement.getInstance(algo,"SunJCE"); + keyGen = KeyPairGenerator.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); + ka = KeyAgreement.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); } public void initialize(AlgorithmParameterSpec spec) throws InvalidAlgorithmParameterException, InvalidKeyException { diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHKeys.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHKeys.java index 1faaa6783b4f1..71f383079e010 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHKeys.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHKeys.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 @@ -55,7 +55,8 @@ private enum SupportedKeySize { public static void main(String[] args) throws Exception { for (SupportedKeySize keySize : SupportedKeySize.values()) { System.out.println("Checking " + keySize.primeSize + " ..."); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", "SunJCE"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); kpg.initialize(keySize.primeSize); KeyPair kp = kpg.generateKeyPair(); checkKeyPair(kp, keySize.primeSize); diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGens.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGens.java index 27f010dd1419d..efc85999b3e00 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGens.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGens.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 @@ -24,6 +24,7 @@ /** * @test * @bug 8072452 8163498 + * @library /test/lib * @summary Support DHE sizes up to 8192-bits and DSA sizes up to 3072-bits * This test has been split based on lower/higher key sizes in order to * reduce individual execution times and run in parallel @@ -33,14 +34,16 @@ * @run main/timeout=300 SupportedDHParamGens 832 * @run main/timeout=300 SupportedDHParamGens 1024 * @run main/timeout=600 SupportedDHParamGens 2048 + * @run main/timeout=600 SupportedDHParamGens 3072 + * @run main/timeout=600 SupportedDHParamGens 4096 */ - import java.math.BigInteger; import java.security.*; -import javax.crypto.*; import javax.crypto.interfaces.*; import javax.crypto.spec.*; +import jdk.test.lib.security.DiffieHellmanGroup; +import jdk.test.lib.security.SecurityUtils; public class SupportedDHParamGens { @@ -48,18 +51,31 @@ public static void main(String[] args) throws Exception { int primeSize = Integer.valueOf(args[0]).intValue(); System.out.println("Checking " + primeSize + " ..."); - AlgorithmParameterGenerator apg = - AlgorithmParameterGenerator.getInstance("DH", "SunJCE"); - apg.init(primeSize); - AlgorithmParameters ap = apg.generateParameters(); - DHParameterSpec spec = ap.getParameterSpec(DHParameterSpec.class); + DHParameterSpec spec = null; + switch (primeSize) { + case 2048, 3072, 4096 -> spec = getDHParameterSpec(primeSize); + default -> { + AlgorithmParameterGenerator apg = + AlgorithmParameterGenerator.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); + apg.init(primeSize); + AlgorithmParameters ap = apg.generateParameters(); + spec = ap.getParameterSpec(DHParameterSpec.class); + } + } - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", "SunJCE"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); kpg.initialize(spec); KeyPair kp = kpg.generateKeyPair(); checkKeyPair(kp, primeSize); } + private static DHParameterSpec getDHParameterSpec(int primeSize) { + DiffieHellmanGroup dhGroup = SecurityUtils.getTestDHGroup(primeSize); + return new DHParameterSpec(dhGroup.getPrime(), dhGroup.getBase()); + } + private static void checkKeyPair(KeyPair kp, int pSize) throws Exception { DHPrivateKey privateKey = (DHPrivateKey)kp.getPrivate(); diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGensLongKey.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGensLongKey.java index 740486e06cf92..7d2570991d5d8 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGensLongKey.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGensLongKey.java @@ -24,6 +24,7 @@ /** * @test * @bug 8072452 8163498 + * @library /test/lib * @summary Support DHE sizes up to 8192-bits and DSA sizes up to 3072-bits * This test has been split based on lower/higher key sizes in order to * reduce individual execution times and run in parallel diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/TestExponentSize.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/TestExponentSize.java index 2367c361d5730..ade1d1fb6e964 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/TestExponentSize.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/TestExponentSize.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 @@ -81,7 +81,8 @@ BigInteger getBigIntValue() { public static void main(String[] args) throws Exception { KeyPair kp; - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", "SunJCE"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); // Sun's default uses a default psize of 3072 and // lsize of (pSize / 2) but at least 384 bits diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/UnsupportedDHKeys.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/UnsupportedDHKeys.java index d2ef5fab80730..dff10c3d21a10 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/UnsupportedDHKeys.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/UnsupportedDHKeys.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 @@ -61,7 +61,8 @@ public static void main(String[] args) throws Exception { try { System.out.println("Checking " + keySize.primeSize + " ..."); KeyPairGenerator kpg = - KeyPairGenerator.getInstance("DH", "SunJCE"); + KeyPairGenerator.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); kpg.initialize(keySize.primeSize); throw new Exception("Should not support " + keySize.primeSize); diff --git a/test/jdk/com/sun/crypto/provider/KeyFactory/PBKDF2HmacSHA1FactoryTest.java b/test/jdk/com/sun/crypto/provider/KeyFactory/PBKDF2HmacSHA1FactoryTest.java index 1f2fa128db8f8..e5c8bb63aa7d4 100644 --- a/test/jdk/com/sun/crypto/provider/KeyFactory/PBKDF2HmacSHA1FactoryTest.java +++ b/test/jdk/com/sun/crypto/provider/KeyFactory/PBKDF2HmacSHA1FactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,8 @@ public class PBKDF2HmacSHA1FactoryTest { }; private static void test() throws Exception { - SecretKeyFactory skf = SecretKeyFactory.getInstance(ALGO, "SunJCE"); + SecretKeyFactory skf = SecretKeyFactory.getInstance(ALGO, + System.getProperty("test.provider.name", "SunJCE")); for (int i = 0; i < TEST_VECTORS.length; i++) { System.out.println("=>Testing vector#" + (i+1)); diff --git a/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java b/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java index 650e743baa9b1..b2122d5691b35 100644 --- a/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java +++ b/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, 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,6 +24,7 @@ /* * @test * @bug 6578538 8027624 + * @library /test/lib * @summary com.sun.crypto.provider.SunJCE instance leak using KRB5 and * LoginContext * @author Brad Wetmore @@ -45,6 +46,7 @@ import java.util.*; import java.util.concurrent.*; +import jdk.test.lib.security.SecurityUtils; public class TestProviderLeak { private static final int MB = 1024 * 1024; @@ -106,9 +108,10 @@ private static void dumpMemoryStats(String s) throws Exception { public static void main(String [] args) throws Exception { // Prepare the test final SecretKeyFactory skf = - SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1", "SunJCE"); + SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1", + System.getProperty("test.provider.name", "SunJCE")); final PBEKeySpec pbeKS = new PBEKeySpec( - "passPhrase".toCharArray(), new byte [] { 0 }, 5, 512); + "passPhrase".toCharArray(), new byte [SecurityUtils.getTestSaltSize()], 1000, 512); ExecutorService executor = Executors.newSingleThreadExecutor(); Callable task = new Callable() { diff --git a/test/jdk/com/sun/crypto/provider/KeyGenerator/Test4628062.java b/test/jdk/com/sun/crypto/provider/KeyGenerator/Test4628062.java index 04ca4944aff59..f8502ce2bf157 100644 --- a/test/jdk/com/sun/crypto/provider/KeyGenerator/Test4628062.java +++ b/test/jdk/com/sun/crypto/provider/KeyGenerator/Test4628062.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,8 @@ public class Test4628062 { private static final int[] HMACSHA512_256_SIZES = { 32 }; public boolean execute(String algo, int[] keySizes) throws Exception { - KeyGenerator kg = KeyGenerator.getInstance(algo, "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); // TEST FIX 4628062 Key keyWithDefaultSize = kg.generateKey(); diff --git a/test/jdk/com/sun/crypto/provider/KeyGenerator/Test6227536.java b/test/jdk/com/sun/crypto/provider/KeyGenerator/Test6227536.java index 43de6ead59a5f..db8f78af835f9 100644 --- a/test/jdk/com/sun/crypto/provider/KeyGenerator/Test6227536.java +++ b/test/jdk/com/sun/crypto/provider/KeyGenerator/Test6227536.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 @@ -38,7 +38,8 @@ public class Test6227536 { String[] keyGensToTest = new String[]{"HmacSHA1", "HmacMD5"}; public boolean execute(String algo) throws Exception { - KeyGenerator kg = KeyGenerator.getInstance(algo, "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); Utils.runAndCheckException(() -> kg.init(0), IllegalArgumentException.class); diff --git a/test/jdk/com/sun/crypto/provider/KeyGenerator/TestExplicitKeyLength.java b/test/jdk/com/sun/crypto/provider/KeyGenerator/TestExplicitKeyLength.java index fd53497a4b46f..a1226b89d344e 100644 --- a/test/jdk/com/sun/crypto/provider/KeyGenerator/TestExplicitKeyLength.java +++ b/test/jdk/com/sun/crypto/provider/KeyGenerator/TestExplicitKeyLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, 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 @@ -35,13 +35,14 @@ public class TestExplicitKeyLength { - private static final String ALGOS[] = { "RC2", "ARCFOUR" }; + private static final String ALGOS[] = { "RC2", "ARCFOUR", "AES", "AES", "AES" }; private static final int KEY_SIZES[] = - { 64, 80 }; // in bits + { 64, 80, 128, 192, 256 }; // in bits public static void runTest(String algo, int keysize) throws Exception { - KeyGenerator kg = KeyGenerator.getInstance(algo, "SunJCE"); + KeyGenerator kg = KeyGenerator.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); kg.init(keysize); Key generatedKey = kg.generateKey(); int actualSizeInBits = generatedKey.getEncoded().length*8; diff --git a/test/jdk/com/sun/crypto/provider/Mac/DigestCloneabilityTest.java b/test/jdk/com/sun/crypto/provider/Mac/DigestCloneabilityTest.java index 2c54237fac529..5fac9ffc72d50 100644 --- a/test/jdk/com/sun/crypto/provider/Mac/DigestCloneabilityTest.java +++ b/test/jdk/com/sun/crypto/provider/Mac/DigestCloneabilityTest.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 @@ -40,7 +40,8 @@ public static void main(String[] args) throws Exception { // make SampleProvider the most preferred, so its digest impl is picked int status = Security.insertProviderAt(p, 1); try { - Mac mac = Mac.getInstance(ALGO, "SunJCE"); + Mac mac = Mac.getInstance(ALGO, + System.getProperty("test.provider.name", "SunJCE")); // do a complete mac generation and check if the supplied // digest is used mac.init(new SecretKeySpec(new byte[512>>3], ALGO)); @@ -72,7 +73,8 @@ public static class CloneableDigest extends MessageDigestSpi public CloneableDigest() throws NoSuchAlgorithmException { try { - md = MessageDigest.getInstance("SHA-512", "SUN"); + md = MessageDigest.getInstance("SHA-512", + System.getProperty("test.provider.name", "SUN")); } catch (NoSuchProviderException nspe) { // should never happen } diff --git a/test/jdk/com/sun/crypto/provider/Mac/EmptyByteBufferTest.java b/test/jdk/com/sun/crypto/provider/Mac/EmptyByteBufferTest.java index 9b1dd1cb3736d..dafc6023a7990 100644 --- a/test/jdk/com/sun/crypto/provider/Mac/EmptyByteBufferTest.java +++ b/test/jdk/com/sun/crypto/provider/Mac/EmptyByteBufferTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, 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 @@ -51,7 +51,8 @@ public void doTest(String alg) throws NoSuchAlgorithmException, SecretKey key = Utils.getSecretKeySpec(); // instantiate Mac object and init it with a SecretKey - Mac mac = Mac.getInstance(alg, "SunJCE"); + Mac mac = Mac.getInstance(alg, + System.getProperty("test.provider.name", "SunJCE")); mac.init(key); // prepare buffer diff --git a/test/jdk/com/sun/crypto/provider/Mac/HmacPBESHA1.java b/test/jdk/com/sun/crypto/provider/Mac/HmacPBESHA1.java index 8f72f5b6aae80..1222736f6f9fa 100644 --- a/test/jdk/com/sun/crypto/provider/Mac/HmacPBESHA1.java +++ b/test/jdk/com/sun/crypto/provider/Mac/HmacPBESHA1.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 @@ -49,7 +49,8 @@ public class HmacPBESHA1 { }; private static final int[] MAC_LENGTHS = { 20, 20, 28, 32, 48, 64, 28, 32 }; private static final String KEY_ALGO = "PBE"; - private static final String PROVIDER = "SunJCE"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunJCE"); private static SecretKey key = null; diff --git a/test/jdk/com/sun/crypto/provider/Mac/HmacSaltLengths.java b/test/jdk/com/sun/crypto/provider/Mac/HmacSaltLengths.java index a7a5a8e0ee9b6..d1c8383e6a171 100644 --- a/test/jdk/com/sun/crypto/provider/Mac/HmacSaltLengths.java +++ b/test/jdk/com/sun/crypto/provider/Mac/HmacSaltLengths.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 @@ -41,6 +41,10 @@ public class HmacSaltLengths { private static final String[] ALGOS = { "HmacPBESHA1", + "HmacPBESHA224", + "HmacPBESHA256", + "HmacPBESHA384", + "HmacPBESHA512", "PBEWithHmacSHA1", "PBEWithHmacSHA224", "PBEWithHmacSHA256", @@ -91,7 +95,8 @@ public static void main(String[] argv) throws Exception { new SecureRandom().nextBytes(input); char[] PASSWD = { 'p','a','s','s','w','o','r','d' }; long start = System.currentTimeMillis(); - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + p.getName() + "..."); for (String algo : ALGOS) { runTest(algo, input, PASSWD, p); diff --git a/test/jdk/com/sun/crypto/provider/Mac/LargeByteBufferTest.java b/test/jdk/com/sun/crypto/provider/Mac/LargeByteBufferTest.java index f294b67743b9a..4b2f8d8abc707 100644 --- a/test/jdk/com/sun/crypto/provider/Mac/LargeByteBufferTest.java +++ b/test/jdk/com/sun/crypto/provider/Mac/LargeByteBufferTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, 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 @@ -53,7 +53,8 @@ public void doTest(String alg) throws NoSuchAlgorithmException, SecretKey key = Utils.getSecretKeySpec(); // instantiate Mac object and init it with a SecretKey - Mac mac = Mac.getInstance(alg, "SunJCE"); + Mac mac = Mac.getInstance(alg, + System.getProperty("test.provider.name", "SunJCE")); mac.init(key); // prepare buffer diff --git a/test/jdk/com/sun/crypto/provider/Mac/MacClone.java b/test/jdk/com/sun/crypto/provider/Mac/MacClone.java index 46e797a189a12..5d491ded32435 100644 --- a/test/jdk/com/sun/crypto/provider/Mac/MacClone.java +++ b/test/jdk/com/sun/crypto/provider/Mac/MacClone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, 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 @@ -26,6 +26,8 @@ * @bug 7087021 8013069 8288050 * @summary Clone tests for all MAC algorithms. * @author Jan Luehe + * @run main MacClone DES + * @run main MacClone AES */ import java.security.spec.AlgorithmParameterSpec; import javax.crypto.*; @@ -39,7 +41,8 @@ public static void main(String[] args) throws Exception { "HmacSHA384", "HmacSHA512", "HmacSHA512/224", "HmacSHA512/256", }; - KeyGenerator kgen = KeyGenerator.getInstance("DES"); + String keyAlgo = args[0]; + KeyGenerator kgen = KeyGenerator.getInstance(keyAlgo); SecretKey skey = kgen.generateKey(); for (String algo : algos) { doTest(algo, skey, null); @@ -64,7 +67,8 @@ private static void doTest(String algo, SecretKey skey, // // Clone an uninitialized Mac object // - Mac mac = Mac.getInstance(algo, "SunJCE"); + Mac mac = Mac.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); Mac macClone = (Mac)mac.clone(); System.out.println(macClone.getProvider().toString()); System.out.println(macClone.getAlgorithm()); @@ -81,7 +85,8 @@ private static void doTest(String algo, SecretKey skey, // // Clone an initialized Mac object // - mac = Mac.getInstance(algo, "SunJCE"); + mac = Mac.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); mac.init(skey, params); macClone = (Mac)mac.clone(); System.out.println(macClone.getProvider().toString()); diff --git a/test/jdk/com/sun/crypto/provider/Mac/MacKAT.java b/test/jdk/com/sun/crypto/provider/Mac/MacKAT.java index b75359e2ddf08..9721668ea9197 100644 --- a/test/jdk/com/sun/crypto/provider/Mac/MacKAT.java +++ b/test/jdk/com/sun/crypto/provider/Mac/MacKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, 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 @@ -333,7 +333,8 @@ private static Test t(String alg, byte[] input, String macvalue, byte[] key) { static void runTests(Test[] tests) throws Exception { long start = System.currentTimeMillis(); - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + p.getName() + "..."); for (int i = 0; i < tests.length; i++) { Test test = tests[i]; diff --git a/test/jdk/com/sun/crypto/provider/Mac/MacSameTest.java b/test/jdk/com/sun/crypto/provider/Mac/MacSameTest.java index 598ea6a910c9b..e8b8351c974a7 100644 --- a/test/jdk/com/sun/crypto/provider/Mac/MacSameTest.java +++ b/test/jdk/com/sun/crypto/provider/Mac/MacSameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, 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 @@ -63,7 +63,8 @@ public void doTest(String algo) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException { Mac mac; try { - mac = Mac.getInstance(algo, "SunJCE"); + mac = Mac.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); } catch (NoSuchAlgorithmException nsae) { // depending on Solaris configuration, // it can support HMAC or not with Mac diff --git a/test/jdk/com/sun/crypto/provider/Mac/NullByteBufferTest.java b/test/jdk/com/sun/crypto/provider/Mac/NullByteBufferTest.java index d71d4f9631766..a4f3e441cb36f 100644 --- a/test/jdk/com/sun/crypto/provider/Mac/NullByteBufferTest.java +++ b/test/jdk/com/sun/crypto/provider/Mac/NullByteBufferTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, 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 @@ -51,7 +51,8 @@ public void doTest(String alg) throws NoSuchAlgorithmException, SecretKey key = Utils.getSecretKeySpec(); // instantiate Mac object and init it with a SecretKey - Mac mac = Mac.getInstance(alg, "SunJCE"); + Mac mac = Mac.getInstance(alg, + System.getProperty("test.provider.name", "SunJCE")); mac.init(key); try { diff --git a/test/jdk/com/sun/crypto/provider/NSASuiteB/TestAESOids.java b/test/jdk/com/sun/crypto/provider/NSASuiteB/TestAESOids.java index 062c34ceda351..445ccf8c7397c 100644 --- a/test/jdk/com/sun/crypto/provider/NSASuiteB/TestAESOids.java +++ b/test/jdk/com/sun/crypto/provider/NSASuiteB/TestAESOids.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,8 @@ */ public class TestAESOids { - private static final String PROVIDER_NAME = "SunJCE"; + private static final String PROVIDER_NAME = + System.getProperty("test.provider.name", "SunJCE"); private static final byte[] INPUT = "1234567890123456".getBytes(); private static final List DATA = Arrays.asList( diff --git a/test/jdk/com/sun/crypto/provider/NSASuiteB/TestAESWrapOids.java b/test/jdk/com/sun/crypto/provider/NSASuiteB/TestAESWrapOids.java index a75694be832e1..9b99ece8bdaee 100644 --- a/test/jdk/com/sun/crypto/provider/NSASuiteB/TestAESWrapOids.java +++ b/test/jdk/com/sun/crypto/provider/NSASuiteB/TestAESWrapOids.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,8 @@ */ public class TestAESWrapOids { - private static final String PROVIDER_NAME = "SunJCE"; + private static final String PROVIDER_NAME = + System.getProperty("test.provider.name", "SunJCE"); private static final List DATA = Arrays.asList( new DataTuple("2.16.840.1.101.3.4.1.5", "AESWrap_128"), diff --git a/test/jdk/com/sun/crypto/provider/NSASuiteB/TestHmacSHAOids.java b/test/jdk/com/sun/crypto/provider/NSASuiteB/TestHmacSHAOids.java index 3ac097fe0eaff..30989b9405013 100644 --- a/test/jdk/com/sun/crypto/provider/NSASuiteB/TestHmacSHAOids.java +++ b/test/jdk/com/sun/crypto/provider/NSASuiteB/TestHmacSHAOids.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 @@ -41,7 +41,8 @@ */ public class TestHmacSHAOids { - private static final String PROVIDER_NAME = "SunJCE"; + private static final String PROVIDER_NAME = + System.getProperty("test.provider.name", "SunJCE"); private static final byte[] INPUT = "1234567890".getBytes(); private static final List DATA = Arrays.asList( diff --git a/test/jdk/com/sun/crypto/provider/TLS/TestKeyMaterial.java b/test/jdk/com/sun/crypto/provider/TLS/TestKeyMaterial.java index 983e8acb4c307..b23390f0e5022 100644 --- a/test/jdk/com/sun/crypto/provider/TLS/TestKeyMaterial.java +++ b/test/jdk/com/sun/crypto/provider/TLS/TestKeyMaterial.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 @@ -47,7 +47,8 @@ public class TestKeyMaterial extends Utils { private static int PREFIX_LENGTH = "km-master: ".length(); public static void main(String[] args) throws Exception { - Provider provider = Security.getProvider("SunJCE"); + Provider provider = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); InputStream in = new FileInputStream(new File(BASE, "keymatdata.txt")); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); diff --git a/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java b/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java index bf47477b1350e..9dc22c77fd045 100644 --- a/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java +++ b/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,8 @@ public class TestLeadingZeroes { - private static final String SUNJCE = "SunJCE"; + private static final String PROVIDER_NAME = + System.getProperty("test.provider.name", "SunJCE"); // Hex formatter to upper case with ":" delimiter private static final HexFormat HEX_FORMATTER = HexFormat.ofDelimiter(":").withUpperCase(); @@ -73,14 +74,14 @@ private void run() throws Exception { kfac.generatePrivate(new PKCS8EncodedKeySpec(bobPrivKeyEnc)); // generate normal shared secret - KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH", SUNJCE); + KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH", PROVIDER_NAME); aliceKeyAgree.init(alicePrivKey); aliceKeyAgree.doPhase(bobPubKey, true); byte[] sharedSecret = aliceKeyAgree.generateSecret(); System.out.println("shared secret:\n" + HEX_FORMATTER.formatHex(sharedSecret)); // verify that leading zero is present - if (sharedSecret.length != 128) { + if (sharedSecret.length != 256) { throw new Exception("Unexpected shared secret length"); } if (sharedSecret[0] != 0) { @@ -96,7 +97,7 @@ private void run() throws Exception { "tls premaster secret:\n" + HEX_FORMATTER.formatHex(tlsPremasterSecret)); // check that leading zero has been stripped - if (tlsPremasterSecret.length != 127) { + if (tlsPremasterSecret.length != 255) { throw new Exception("Unexpected TLS premaster secret length"); } if (tlsPremasterSecret[0] == 0) { @@ -111,279 +112,455 @@ private void run() throws Exception { } private static final byte alicePubKeyEnc[] = { - (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x24, - (byte)0x30, (byte)0x81, (byte)0x99, (byte)0x06, - (byte)0x09, (byte)0x2A, (byte)0x86, (byte)0x48, - (byte)0x86, (byte)0xF7, (byte)0x0D, (byte)0x01, - (byte)0x03, (byte)0x01, (byte)0x30, (byte)0x81, - (byte)0x8B, (byte)0x02, (byte)0x81, (byte)0x81, - (byte)0x00, (byte)0xF4, (byte)0x88, (byte)0xFD, - (byte)0x58, (byte)0x4E, (byte)0x49, (byte)0xDB, - (byte)0xCD, (byte)0x20, (byte)0xB4, (byte)0x9D, - (byte)0xE4, (byte)0x91, (byte)0x07, (byte)0x36, - (byte)0x6B, (byte)0x33, (byte)0x6C, (byte)0x38, - (byte)0x0D, (byte)0x45, (byte)0x1D, (byte)0x0F, - (byte)0x7C, (byte)0x88, (byte)0xB3, (byte)0x1C, - (byte)0x7C, (byte)0x5B, (byte)0x2D, (byte)0x8E, - (byte)0xF6, (byte)0xF3, (byte)0xC9, (byte)0x23, - (byte)0xC0, (byte)0x43, (byte)0xF0, (byte)0xA5, - (byte)0x5B, (byte)0x18, (byte)0x8D, (byte)0x8E, - (byte)0xBB, (byte)0x55, (byte)0x8C, (byte)0xB8, - (byte)0x5D, (byte)0x38, (byte)0xD3, (byte)0x34, - (byte)0xFD, (byte)0x7C, (byte)0x17, (byte)0x57, - (byte)0x43, (byte)0xA3, (byte)0x1D, (byte)0x18, - (byte)0x6C, (byte)0xDE, (byte)0x33, (byte)0x21, - (byte)0x2C, (byte)0xB5, (byte)0x2A, (byte)0xFF, - (byte)0x3C, (byte)0xE1, (byte)0xB1, (byte)0x29, - (byte)0x40, (byte)0x18, (byte)0x11, (byte)0x8D, - (byte)0x7C, (byte)0x84, (byte)0xA7, (byte)0x0A, - (byte)0x72, (byte)0xD6, (byte)0x86, (byte)0xC4, - (byte)0x03, (byte)0x19, (byte)0xC8, (byte)0x07, - (byte)0x29, (byte)0x7A, (byte)0xCA, (byte)0x95, - (byte)0x0C, (byte)0xD9, (byte)0x96, (byte)0x9F, - (byte)0xAB, (byte)0xD0, (byte)0x0A, (byte)0x50, - (byte)0x9B, (byte)0x02, (byte)0x46, (byte)0xD3, - (byte)0x08, (byte)0x3D, (byte)0x66, (byte)0xA4, - (byte)0x5D, (byte)0x41, (byte)0x9F, (byte)0x9C, - (byte)0x7C, (byte)0xBD, (byte)0x89, (byte)0x4B, - (byte)0x22, (byte)0x19, (byte)0x26, (byte)0xBA, - (byte)0xAB, (byte)0xA2, (byte)0x5E, (byte)0xC3, - (byte)0x55, (byte)0xE9, (byte)0x2F, (byte)0x78, - (byte)0xC7, (byte)0x02, (byte)0x01, (byte)0x02, - (byte)0x02, (byte)0x02, (byte)0x02, (byte)0x00, - (byte)0x03, (byte)0x81, (byte)0x85, (byte)0x00, - (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00, - (byte)0xEE, (byte)0xD6, (byte)0xB1, (byte)0xA3, - (byte)0xB4, (byte)0x78, (byte)0x2B, (byte)0x35, - (byte)0xEF, (byte)0xCD, (byte)0x17, (byte)0x86, - (byte)0x63, (byte)0x2B, (byte)0x97, (byte)0x0E, - (byte)0x7A, (byte)0xD1, (byte)0xFF, (byte)0x7A, - (byte)0xEB, (byte)0x57, (byte)0x61, (byte)0xA1, - (byte)0xF7, (byte)0x90, (byte)0x11, (byte)0xA7, - (byte)0x79, (byte)0x28, (byte)0x69, (byte)0xBA, - (byte)0xA7, (byte)0xB2, (byte)0x37, (byte)0x17, - (byte)0xAE, (byte)0x3C, (byte)0x92, (byte)0x89, - (byte)0x88, (byte)0xE5, (byte)0x7E, (byte)0x8E, - (byte)0xF0, (byte)0x24, (byte)0xD0, (byte)0xE1, - (byte)0xC4, (byte)0xB0, (byte)0x26, (byte)0x5A, - (byte)0x1E, (byte)0xBD, (byte)0xA0, (byte)0xCF, - (byte)0x3E, (byte)0x97, (byte)0x2A, (byte)0x13, - (byte)0x92, (byte)0x3B, (byte)0x39, (byte)0xD0, - (byte)0x1D, (byte)0xA3, (byte)0x6B, (byte)0x3E, - (byte)0xC2, (byte)0xBB, (byte)0x14, (byte)0xB6, - (byte)0xE2, (byte)0x4C, (byte)0x0E, (byte)0x5B, - (byte)0x4B, (byte)0xA4, (byte)0x9D, (byte)0xA6, - (byte)0x21, (byte)0xB0, (byte)0xF9, (byte)0xDE, - (byte)0x55, (byte)0xAE, (byte)0x5C, (byte)0x29, - (byte)0x0E, (byte)0xC1, (byte)0xFC, (byte)0xBA, - (byte)0x51, (byte)0xD3, (byte)0xB6, (byte)0x6D, - (byte)0x75, (byte)0x72, (byte)0xDF, (byte)0x43, - (byte)0xAB, (byte)0x94, (byte)0x21, (byte)0x6E, - (byte)0x0C, (byte)0xD1, (byte)0x93, (byte)0x54, - (byte)0x56, (byte)0x7D, (byte)0x4B, (byte)0x90, - (byte)0xF1, (byte)0x94, (byte)0x45, (byte)0xD4, - (byte)0x2A, (byte)0x71, (byte)0xA1, (byte)0xB8, - (byte)0xDD, (byte)0xAA, (byte)0x05, (byte)0xF0, - (byte)0x27, (byte)0x37, (byte)0xBD, (byte)0x44 + (byte)0x30, (byte)0x82, (byte)0x02, (byte)0x25, + (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x17, + (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, + (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, + (byte)0x01, (byte)0x03, (byte)0x01, (byte)0x30, + (byte)0x82, (byte)0x01, (byte)0x08, (byte)0x02, + (byte)0x82, (byte)0x01, (byte)0x01, (byte)0x00, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xad, (byte)0xf8, (byte)0x54, (byte)0x58, + (byte)0xa2, (byte)0xbb, (byte)0x4a, (byte)0x9a, + (byte)0xaf, (byte)0xdc, (byte)0x56, (byte)0x20, + (byte)0x27, (byte)0x3d, (byte)0x3c, (byte)0xf1, + (byte)0xd8, (byte)0xb9, (byte)0xc5, (byte)0x83, + (byte)0xce, (byte)0x2d, (byte)0x36, (byte)0x95, + (byte)0xa9, (byte)0xe1, (byte)0x36, (byte)0x41, + (byte)0x14, (byte)0x64, (byte)0x33, (byte)0xfb, + (byte)0xcc, (byte)0x93, (byte)0x9d, (byte)0xce, + (byte)0x24, (byte)0x9b, (byte)0x3e, (byte)0xf9, + (byte)0x7d, (byte)0x2f, (byte)0xe3, (byte)0x63, + (byte)0x63, (byte)0x0c, (byte)0x75, (byte)0xd8, + (byte)0xf6, (byte)0x81, (byte)0xb2, (byte)0x02, + (byte)0xae, (byte)0xc4, (byte)0x61, (byte)0x7a, + (byte)0xd3, (byte)0xdf, (byte)0x1e, (byte)0xd5, + (byte)0xd5, (byte)0xfd, (byte)0x65, (byte)0x61, + (byte)0x24, (byte)0x33, (byte)0xf5, (byte)0x1f, + (byte)0x5f, (byte)0x06, (byte)0x6e, (byte)0xd0, + (byte)0x85, (byte)0x63, (byte)0x65, (byte)0x55, + (byte)0x3d, (byte)0xed, (byte)0x1a, (byte)0xf3, + (byte)0xb5, (byte)0x57, (byte)0x13, (byte)0x5e, + (byte)0x7f, (byte)0x57, (byte)0xc9, (byte)0x35, + (byte)0x98, (byte)0x4f, (byte)0x0c, (byte)0x70, + (byte)0xe0, (byte)0xe6, (byte)0x8b, (byte)0x77, + (byte)0xe2, (byte)0xa6, (byte)0x89, (byte)0xda, + (byte)0xf3, (byte)0xef, (byte)0xe8, (byte)0x72, + (byte)0x1d, (byte)0xf1, (byte)0x58, (byte)0xa1, + (byte)0x36, (byte)0xad, (byte)0xe7, (byte)0x35, + (byte)0x30, (byte)0xac, (byte)0xca, (byte)0x4f, + (byte)0x48, (byte)0x3a, (byte)0x79, (byte)0x7a, + (byte)0xbc, (byte)0x0a, (byte)0xb1, (byte)0x82, + (byte)0xb3, (byte)0x24, (byte)0xfb, (byte)0x61, + (byte)0xd1, (byte)0x08, (byte)0xa9, (byte)0x4b, + (byte)0xb2, (byte)0xc8, (byte)0xe3, (byte)0xfb, + (byte)0xb9, (byte)0x6a, (byte)0xda, (byte)0xb7, + (byte)0x60, (byte)0xd7, (byte)0xf4, (byte)0x68, + (byte)0x1d, (byte)0x4f, (byte)0x42, (byte)0xa3, + (byte)0xde, (byte)0x39, (byte)0x4d, (byte)0xf4, + (byte)0xae, (byte)0x56, (byte)0xed, (byte)0xe7, + (byte)0x63, (byte)0x72, (byte)0xbb, (byte)0x19, + (byte)0x0b, (byte)0x07, (byte)0xa7, (byte)0xc8, + (byte)0xee, (byte)0x0a, (byte)0x6d, (byte)0x70, + (byte)0x9e, (byte)0x02, (byte)0xfc, (byte)0xe1, + (byte)0xcd, (byte)0xf7, (byte)0xe2, (byte)0xec, + (byte)0xc0, (byte)0x34, (byte)0x04, (byte)0xcd, + (byte)0x28, (byte)0x34, (byte)0x2f, (byte)0x61, + (byte)0x91, (byte)0x72, (byte)0xfe, (byte)0x9c, + (byte)0xe9, (byte)0x85, (byte)0x83, (byte)0xff, + (byte)0x8e, (byte)0x4f, (byte)0x12, (byte)0x32, + (byte)0xee, (byte)0xf2, (byte)0x81, (byte)0x83, + (byte)0xc3, (byte)0xfe, (byte)0x3b, (byte)0x1b, + (byte)0x4c, (byte)0x6f, (byte)0xad, (byte)0x73, + (byte)0x3b, (byte)0xb5, (byte)0xfc, (byte)0xbc, + (byte)0x2e, (byte)0xc2, (byte)0x20, (byte)0x05, + (byte)0xc5, (byte)0x8e, (byte)0xf1, (byte)0x83, + (byte)0x7d, (byte)0x16, (byte)0x83, (byte)0xb2, + (byte)0xc6, (byte)0xf3, (byte)0x4a, (byte)0x26, + (byte)0xc1, (byte)0xb2, (byte)0xef, (byte)0xfa, + (byte)0x88, (byte)0x6b, (byte)0x42, (byte)0x38, + (byte)0x61, (byte)0x28, (byte)0x5c, (byte)0x97, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x03, + (byte)0x82, (byte)0x01, (byte)0x06, (byte)0x00, + (byte)0x02, (byte)0x82, (byte)0x01, (byte)0x01, + (byte)0x00, (byte)0xb0, (byte)0x6e, (byte)0x76, + (byte)0x73, (byte)0x32, (byte)0xd4, (byte)0xcf, + (byte)0xb8, (byte)0x16, (byte)0x46, (byte)0x76, + (byte)0x8b, (byte)0x2b, (byte)0x2b, (byte)0xda, + (byte)0x6e, (byte)0x25, (byte)0x52, (byte)0x87, + (byte)0x9e, (byte)0x0c, (byte)0x97, (byte)0xc7, + (byte)0x16, (byte)0x42, (byte)0xb6, (byte)0x30, + (byte)0xc6, (byte)0x30, (byte)0xce, (byte)0xc5, + (byte)0xf4, (byte)0x8e, (byte)0x28, (byte)0xe0, + (byte)0x8d, (byte)0x5b, (byte)0x44, (byte)0x59, + (byte)0xae, (byte)0x5e, (byte)0xb6, (byte)0x5f, + (byte)0x48, (byte)0x8e, (byte)0x13, (byte)0x91, + (byte)0x00, (byte)0x72, (byte)0x9b, (byte)0x1b, + (byte)0xd8, (byte)0x69, (byte)0xe4, (byte)0xdf, + (byte)0x10, (byte)0x50, (byte)0x53, (byte)0x0f, + (byte)0x3d, (byte)0xba, (byte)0x82, (byte)0x02, + (byte)0x1c, (byte)0x78, (byte)0xf3, (byte)0xf3, + (byte)0x9a, (byte)0x01, (byte)0x3d, (byte)0xb6, + (byte)0x65, (byte)0xc2, (byte)0x6f, (byte)0x70, + (byte)0xec, (byte)0x67, (byte)0x14, (byte)0x56, + (byte)0xa0, (byte)0x98, (byte)0xef, (byte)0xc8, + (byte)0x63, (byte)0xbe, (byte)0x14, (byte)0x78, + (byte)0x1d, (byte)0xff, (byte)0xf8, (byte)0xf9, + (byte)0xd9, (byte)0x53, (byte)0xb2, (byte)0xc4, + (byte)0x40, (byte)0x3e, (byte)0x90, (byte)0x5c, + (byte)0x10, (byte)0xf8, (byte)0xa4, (byte)0xd3, + (byte)0xa2, (byte)0x39, (byte)0xc6, (byte)0xeb, + (byte)0xcd, (byte)0x3d, (byte)0xd1, (byte)0x27, + (byte)0x51, (byte)0xc8, (byte)0x4f, (byte)0x9b, + (byte)0x86, (byte)0xce, (byte)0xcf, (byte)0x80, + (byte)0x96, (byte)0x3d, (byte)0xb9, (byte)0x25, + (byte)0x05, (byte)0x54, (byte)0x15, (byte)0x8d, + (byte)0x02, (byte)0xd2, (byte)0x6f, (byte)0xed, + (byte)0xaf, (byte)0x49, (byte)0x0d, (byte)0x3e, + (byte)0xda, (byte)0xe6, (byte)0x3d, (byte)0x1a, + (byte)0x91, (byte)0x8f, (byte)0xca, (byte)0x6d, + (byte)0x88, (byte)0xff, (byte)0x0f, (byte)0x75, + (byte)0xf5, (byte)0x4e, (byte)0x08, (byte)0x42, + (byte)0xf0, (byte)0xa3, (byte)0x4a, (byte)0x95, + (byte)0xca, (byte)0x18, (byte)0xc1, (byte)0x3d, + (byte)0x9a, (byte)0x12, (byte)0x3e, (byte)0x09, + (byte)0x29, (byte)0x82, (byte)0x8e, (byte)0xe5, + (byte)0x3a, (byte)0x4c, (byte)0xcc, (byte)0x8f, + (byte)0x94, (byte)0x14, (byte)0xe3, (byte)0xc7, + (byte)0x63, (byte)0x8a, (byte)0x23, (byte)0x11, + (byte)0x03, (byte)0x77, (byte)0x7d, (byte)0xe8, + (byte)0x03, (byte)0x15, (byte)0x37, (byte)0xa9, + (byte)0xe5, (byte)0xd7, (byte)0x38, (byte)0x8f, + (byte)0xa8, (byte)0x49, (byte)0x5d, (byte)0xe4, + (byte)0x0d, (byte)0xed, (byte)0xb9, (byte)0x92, + (byte)0xc4, (byte)0xd7, (byte)0x72, (byte)0xf2, + (byte)0x29, (byte)0x26, (byte)0x99, (byte)0x11, + (byte)0xac, (byte)0xa8, (byte)0x45, (byte)0xb1, + (byte)0x6b, (byte)0x5a, (byte)0x01, (byte)0xc4, + (byte)0xe0, (byte)0x08, (byte)0xbf, (byte)0xa1, + (byte)0x49, (byte)0x2a, (byte)0x9c, (byte)0x8c, + (byte)0x89, (byte)0x31, (byte)0x07, (byte)0x36, + (byte)0x7d, (byte)0xec, (byte)0xa3, (byte)0x9a, + (byte)0x1e, (byte)0xd6, (byte)0xc6, (byte)0x01, + (byte)0x0e, (byte)0xc8, (byte)0x85, (byte)0x55, + (byte)0x42, (byte)0xa4, (byte)0x87, (byte)0x58, + (byte)0xfa, (byte)0xec, (byte)0x71, (byte)0x2e, + (byte)0x4c, (byte)0x46, (byte)0xd2, (byte)0x19, + (byte)0x23, (byte)0x0a, (byte)0x59, (byte)0x1a, + (byte)0x56 }; private static final byte alicePrivKeyEnc[] = { - (byte)0x30, (byte)0x81, (byte)0xE3, (byte)0x02, - (byte)0x01, (byte)0x00, (byte)0x30, (byte)0x81, - (byte)0x99, (byte)0x06, (byte)0x09, (byte)0x2A, - (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xF7, - (byte)0x0D, (byte)0x01, (byte)0x03, (byte)0x01, - (byte)0x30, (byte)0x81, (byte)0x8B, (byte)0x02, - (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xF4, - (byte)0x88, (byte)0xFD, (byte)0x58, (byte)0x4E, - (byte)0x49, (byte)0xDB, (byte)0xCD, (byte)0x20, - (byte)0xB4, (byte)0x9D, (byte)0xE4, (byte)0x91, - (byte)0x07, (byte)0x36, (byte)0x6B, (byte)0x33, - (byte)0x6C, (byte)0x38, (byte)0x0D, (byte)0x45, - (byte)0x1D, (byte)0x0F, (byte)0x7C, (byte)0x88, - (byte)0xB3, (byte)0x1C, (byte)0x7C, (byte)0x5B, - (byte)0x2D, (byte)0x8E, (byte)0xF6, (byte)0xF3, - (byte)0xC9, (byte)0x23, (byte)0xC0, (byte)0x43, - (byte)0xF0, (byte)0xA5, (byte)0x5B, (byte)0x18, - (byte)0x8D, (byte)0x8E, (byte)0xBB, (byte)0x55, - (byte)0x8C, (byte)0xB8, (byte)0x5D, (byte)0x38, - (byte)0xD3, (byte)0x34, (byte)0xFD, (byte)0x7C, - (byte)0x17, (byte)0x57, (byte)0x43, (byte)0xA3, - (byte)0x1D, (byte)0x18, (byte)0x6C, (byte)0xDE, - (byte)0x33, (byte)0x21, (byte)0x2C, (byte)0xB5, - (byte)0x2A, (byte)0xFF, (byte)0x3C, (byte)0xE1, - (byte)0xB1, (byte)0x29, (byte)0x40, (byte)0x18, - (byte)0x11, (byte)0x8D, (byte)0x7C, (byte)0x84, - (byte)0xA7, (byte)0x0A, (byte)0x72, (byte)0xD6, - (byte)0x86, (byte)0xC4, (byte)0x03, (byte)0x19, - (byte)0xC8, (byte)0x07, (byte)0x29, (byte)0x7A, - (byte)0xCA, (byte)0x95, (byte)0x0C, (byte)0xD9, - (byte)0x96, (byte)0x9F, (byte)0xAB, (byte)0xD0, - (byte)0x0A, (byte)0x50, (byte)0x9B, (byte)0x02, - (byte)0x46, (byte)0xD3, (byte)0x08, (byte)0x3D, - (byte)0x66, (byte)0xA4, (byte)0x5D, (byte)0x41, - (byte)0x9F, (byte)0x9C, (byte)0x7C, (byte)0xBD, - (byte)0x89, (byte)0x4B, (byte)0x22, (byte)0x19, - (byte)0x26, (byte)0xBA, (byte)0xAB, (byte)0xA2, - (byte)0x5E, (byte)0xC3, (byte)0x55, (byte)0xE9, - (byte)0x2F, (byte)0x78, (byte)0xC7, (byte)0x02, - (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x02, - (byte)0x02, (byte)0x00, (byte)0x04, (byte)0x42, - (byte)0x02, (byte)0x40, (byte)0x36, (byte)0x4D, - (byte)0xD0, (byte)0x58, (byte)0x64, (byte)0x91, - (byte)0x78, (byte)0xA2, (byte)0x4B, (byte)0x79, - (byte)0x46, (byte)0xFE, (byte)0xC9, (byte)0xD9, - (byte)0xCA, (byte)0x5C, (byte)0xF9, (byte)0xFD, - (byte)0x6C, (byte)0x5D, (byte)0x76, (byte)0x3A, - (byte)0x41, (byte)0x6D, (byte)0x44, (byte)0x62, - (byte)0x75, (byte)0x93, (byte)0x81, (byte)0x93, - (byte)0x00, (byte)0x4C, (byte)0xB1, (byte)0xD8, - (byte)0x7D, (byte)0x9D, (byte)0xF3, (byte)0x16, - (byte)0x2C, (byte)0x6C, (byte)0x9F, (byte)0x7A, - (byte)0x84, (byte)0xA3, (byte)0x7A, (byte)0xC1, - (byte)0x4F, (byte)0x60, (byte)0xE3, (byte)0xB5, - (byte)0x86, (byte)0x28, (byte)0x08, (byte)0x4D, - (byte)0x94, (byte)0xB6, (byte)0x04, (byte)0x0D, - (byte)0xAC, (byte)0xBD, (byte)0x1F, (byte)0x42, - (byte)0x8F, (byte)0x1B + (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x3f, + (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30, + (byte)0x82, (byte)0x01, (byte)0x17, (byte)0x06, + (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, + (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, + (byte)0x03, (byte)0x01, (byte)0x30, (byte)0x82, + (byte)0x01, (byte)0x08, (byte)0x02, (byte)0x82, + (byte)0x01, (byte)0x01, (byte)0x00, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xad, + (byte)0xf8, (byte)0x54, (byte)0x58, (byte)0xa2, + (byte)0xbb, (byte)0x4a, (byte)0x9a, (byte)0xaf, + (byte)0xdc, (byte)0x56, (byte)0x20, (byte)0x27, + (byte)0x3d, (byte)0x3c, (byte)0xf1, (byte)0xd8, + (byte)0xb9, (byte)0xc5, (byte)0x83, (byte)0xce, + (byte)0x2d, (byte)0x36, (byte)0x95, (byte)0xa9, + (byte)0xe1, (byte)0x36, (byte)0x41, (byte)0x14, + (byte)0x64, (byte)0x33, (byte)0xfb, (byte)0xcc, + (byte)0x93, (byte)0x9d, (byte)0xce, (byte)0x24, + (byte)0x9b, (byte)0x3e, (byte)0xf9, (byte)0x7d, + (byte)0x2f, (byte)0xe3, (byte)0x63, (byte)0x63, + (byte)0x0c, (byte)0x75, (byte)0xd8, (byte)0xf6, + (byte)0x81, (byte)0xb2, (byte)0x02, (byte)0xae, + (byte)0xc4, (byte)0x61, (byte)0x7a, (byte)0xd3, + (byte)0xdf, (byte)0x1e, (byte)0xd5, (byte)0xd5, + (byte)0xfd, (byte)0x65, (byte)0x61, (byte)0x24, + (byte)0x33, (byte)0xf5, (byte)0x1f, (byte)0x5f, + (byte)0x06, (byte)0x6e, (byte)0xd0, (byte)0x85, + (byte)0x63, (byte)0x65, (byte)0x55, (byte)0x3d, + (byte)0xed, (byte)0x1a, (byte)0xf3, (byte)0xb5, + (byte)0x57, (byte)0x13, (byte)0x5e, (byte)0x7f, + (byte)0x57, (byte)0xc9, (byte)0x35, (byte)0x98, + (byte)0x4f, (byte)0x0c, (byte)0x70, (byte)0xe0, + (byte)0xe6, (byte)0x8b, (byte)0x77, (byte)0xe2, + (byte)0xa6, (byte)0x89, (byte)0xda, (byte)0xf3, + (byte)0xef, (byte)0xe8, (byte)0x72, (byte)0x1d, + (byte)0xf1, (byte)0x58, (byte)0xa1, (byte)0x36, + (byte)0xad, (byte)0xe7, (byte)0x35, (byte)0x30, + (byte)0xac, (byte)0xca, (byte)0x4f, (byte)0x48, + (byte)0x3a, (byte)0x79, (byte)0x7a, (byte)0xbc, + (byte)0x0a, (byte)0xb1, (byte)0x82, (byte)0xb3, + (byte)0x24, (byte)0xfb, (byte)0x61, (byte)0xd1, + (byte)0x08, (byte)0xa9, (byte)0x4b, (byte)0xb2, + (byte)0xc8, (byte)0xe3, (byte)0xfb, (byte)0xb9, + (byte)0x6a, (byte)0xda, (byte)0xb7, (byte)0x60, + (byte)0xd7, (byte)0xf4, (byte)0x68, (byte)0x1d, + (byte)0x4f, (byte)0x42, (byte)0xa3, (byte)0xde, + (byte)0x39, (byte)0x4d, (byte)0xf4, (byte)0xae, + (byte)0x56, (byte)0xed, (byte)0xe7, (byte)0x63, + (byte)0x72, (byte)0xbb, (byte)0x19, (byte)0x0b, + (byte)0x07, (byte)0xa7, (byte)0xc8, (byte)0xee, + (byte)0x0a, (byte)0x6d, (byte)0x70, (byte)0x9e, + (byte)0x02, (byte)0xfc, (byte)0xe1, (byte)0xcd, + (byte)0xf7, (byte)0xe2, (byte)0xec, (byte)0xc0, + (byte)0x34, (byte)0x04, (byte)0xcd, (byte)0x28, + (byte)0x34, (byte)0x2f, (byte)0x61, (byte)0x91, + (byte)0x72, (byte)0xfe, (byte)0x9c, (byte)0xe9, + (byte)0x85, (byte)0x83, (byte)0xff, (byte)0x8e, + (byte)0x4f, (byte)0x12, (byte)0x32, (byte)0xee, + (byte)0xf2, (byte)0x81, (byte)0x83, (byte)0xc3, + (byte)0xfe, (byte)0x3b, (byte)0x1b, (byte)0x4c, + (byte)0x6f, (byte)0xad, (byte)0x73, (byte)0x3b, + (byte)0xb5, (byte)0xfc, (byte)0xbc, (byte)0x2e, + (byte)0xc2, (byte)0x20, (byte)0x05, (byte)0xc5, + (byte)0x8e, (byte)0xf1, (byte)0x83, (byte)0x7d, + (byte)0x16, (byte)0x83, (byte)0xb2, (byte)0xc6, + (byte)0xf3, (byte)0x4a, (byte)0x26, (byte)0xc1, + (byte)0xb2, (byte)0xef, (byte)0xfa, (byte)0x88, + (byte)0x6b, (byte)0x42, (byte)0x38, (byte)0x61, + (byte)0x28, (byte)0x5c, (byte)0x97, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x02, + (byte)0x01, (byte)0x02, (byte)0x04, (byte)0x1f, + (byte)0x02, (byte)0x1d, (byte)0x00, (byte)0xc7, + (byte)0x06, (byte)0xe9, (byte)0x24, (byte)0xf8, + (byte)0xb1, (byte)0xdf, (byte)0x98, (byte)0x61, + (byte)0x34, (byte)0x7f, (byte)0xcf, (byte)0xf1, + (byte)0xcc, (byte)0xcd, (byte)0xc8, (byte)0xcc, + (byte)0xd9, (byte)0x6a, (byte)0xb8, (byte)0x7d, + (byte)0x72, (byte)0x4c, (byte)0x58, (byte)0x5a, + (byte)0x97, (byte)0x39, (byte)0x69 }; private static final byte bobPubKeyEnc[] = { - (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x23, - (byte)0x30, (byte)0x81, (byte)0x99, (byte)0x06, - (byte)0x09, (byte)0x2A, (byte)0x86, (byte)0x48, - (byte)0x86, (byte)0xF7, (byte)0x0D, (byte)0x01, - (byte)0x03, (byte)0x01, (byte)0x30, (byte)0x81, - (byte)0x8B, (byte)0x02, (byte)0x81, (byte)0x81, - (byte)0x00, (byte)0xF4, (byte)0x88, (byte)0xFD, - (byte)0x58, (byte)0x4E, (byte)0x49, (byte)0xDB, - (byte)0xCD, (byte)0x20, (byte)0xB4, (byte)0x9D, - (byte)0xE4, (byte)0x91, (byte)0x07, (byte)0x36, - (byte)0x6B, (byte)0x33, (byte)0x6C, (byte)0x38, - (byte)0x0D, (byte)0x45, (byte)0x1D, (byte)0x0F, - (byte)0x7C, (byte)0x88, (byte)0xB3, (byte)0x1C, - (byte)0x7C, (byte)0x5B, (byte)0x2D, (byte)0x8E, - (byte)0xF6, (byte)0xF3, (byte)0xC9, (byte)0x23, - (byte)0xC0, (byte)0x43, (byte)0xF0, (byte)0xA5, - (byte)0x5B, (byte)0x18, (byte)0x8D, (byte)0x8E, - (byte)0xBB, (byte)0x55, (byte)0x8C, (byte)0xB8, - (byte)0x5D, (byte)0x38, (byte)0xD3, (byte)0x34, - (byte)0xFD, (byte)0x7C, (byte)0x17, (byte)0x57, - (byte)0x43, (byte)0xA3, (byte)0x1D, (byte)0x18, - (byte)0x6C, (byte)0xDE, (byte)0x33, (byte)0x21, - (byte)0x2C, (byte)0xB5, (byte)0x2A, (byte)0xFF, - (byte)0x3C, (byte)0xE1, (byte)0xB1, (byte)0x29, - (byte)0x40, (byte)0x18, (byte)0x11, (byte)0x8D, - (byte)0x7C, (byte)0x84, (byte)0xA7, (byte)0x0A, - (byte)0x72, (byte)0xD6, (byte)0x86, (byte)0xC4, - (byte)0x03, (byte)0x19, (byte)0xC8, (byte)0x07, - (byte)0x29, (byte)0x7A, (byte)0xCA, (byte)0x95, - (byte)0x0C, (byte)0xD9, (byte)0x96, (byte)0x9F, - (byte)0xAB, (byte)0xD0, (byte)0x0A, (byte)0x50, - (byte)0x9B, (byte)0x02, (byte)0x46, (byte)0xD3, - (byte)0x08, (byte)0x3D, (byte)0x66, (byte)0xA4, - (byte)0x5D, (byte)0x41, (byte)0x9F, (byte)0x9C, - (byte)0x7C, (byte)0xBD, (byte)0x89, (byte)0x4B, - (byte)0x22, (byte)0x19, (byte)0x26, (byte)0xBA, - (byte)0xAB, (byte)0xA2, (byte)0x5E, (byte)0xC3, - (byte)0x55, (byte)0xE9, (byte)0x2F, (byte)0x78, - (byte)0xC7, (byte)0x02, (byte)0x01, (byte)0x02, - (byte)0x02, (byte)0x02, (byte)0x02, (byte)0x00, - (byte)0x03, (byte)0x81, (byte)0x84, (byte)0x00, - (byte)0x02, (byte)0x81, (byte)0x80, (byte)0x2C, - (byte)0x40, (byte)0xFA, (byte)0xF6, (byte)0xA6, - (byte)0xF8, (byte)0xAC, (byte)0xC2, (byte)0x4F, - (byte)0xCD, (byte)0xC7, (byte)0x37, (byte)0x93, - (byte)0xE5, (byte)0xE4, (byte)0x5E, (byte)0x18, - (byte)0x14, (byte)0xE6, (byte)0x50, (byte)0xDA, - (byte)0x55, (byte)0x38, (byte)0x5D, (byte)0x24, - (byte)0xF5, (byte)0x42, (byte)0x68, (byte)0x5F, - (byte)0xF5, (byte)0x15, (byte)0xC8, (byte)0x9B, - (byte)0x5D, (byte)0x06, (byte)0x3D, (byte)0xE1, - (byte)0x52, (byte)0x2F, (byte)0x98, (byte)0xFF, - (byte)0x37, (byte)0xBB, (byte)0x75, (byte)0x48, - (byte)0x48, (byte)0xE9, (byte)0x65, (byte)0x84, - (byte)0x37, (byte)0xBB, (byte)0xB3, (byte)0xE9, - (byte)0x36, (byte)0x01, (byte)0xB4, (byte)0x6A, - (byte)0x1C, (byte)0xB2, (byte)0x11, (byte)0x82, - (byte)0xCE, (byte)0x3D, (byte)0x65, (byte)0xE5, - (byte)0x3C, (byte)0x89, (byte)0xE9, (byte)0x52, - (byte)0x19, (byte)0xBD, (byte)0x58, (byte)0xF6, - (byte)0xA2, (byte)0x03, (byte)0xA8, (byte)0xB2, - (byte)0xA5, (byte)0xDB, (byte)0xEB, (byte)0xF5, - (byte)0x94, (byte)0xF9, (byte)0x46, (byte)0xBE, - (byte)0x45, (byte)0x4C, (byte)0x65, (byte)0xD2, - (byte)0xD1, (byte)0xCF, (byte)0xFF, (byte)0xFF, - (byte)0xFA, (byte)0x38, (byte)0xF1, (byte)0x72, - (byte)0xAB, (byte)0xB9, (byte)0x14, (byte)0x4E, - (byte)0xF5, (byte)0xF0, (byte)0x7A, (byte)0x8E, - (byte)0x45, (byte)0xFD, (byte)0x5B, (byte)0xF9, - (byte)0xA2, (byte)0x97, (byte)0x1B, (byte)0xAE, - (byte)0x2C, (byte)0x7B, (byte)0x6B, (byte)0x7C, - (byte)0x98, (byte)0xFE, (byte)0x58, (byte)0xDD, - (byte)0xBE, (byte)0xF6, (byte)0x1C, (byte)0x8E, - (byte)0xD0, (byte)0xA1, (byte)0x72 + (byte)0x30, (byte)0x82, (byte)0x02, (byte)0x25, + (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x17, + (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, + (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, + (byte)0x01, (byte)0x03, (byte)0x01, (byte)0x30, + (byte)0x82, (byte)0x01, (byte)0x08, (byte)0x02, + (byte)0x82, (byte)0x01, (byte)0x01, (byte)0x00, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xad, (byte)0xf8, (byte)0x54, (byte)0x58, + (byte)0xa2, (byte)0xbb, (byte)0x4a, (byte)0x9a, + (byte)0xaf, (byte)0xdc, (byte)0x56, (byte)0x20, + (byte)0x27, (byte)0x3d, (byte)0x3c, (byte)0xf1, + (byte)0xd8, (byte)0xb9, (byte)0xc5, (byte)0x83, + (byte)0xce, (byte)0x2d, (byte)0x36, (byte)0x95, + (byte)0xa9, (byte)0xe1, (byte)0x36, (byte)0x41, + (byte)0x14, (byte)0x64, (byte)0x33, (byte)0xfb, + (byte)0xcc, (byte)0x93, (byte)0x9d, (byte)0xce, + (byte)0x24, (byte)0x9b, (byte)0x3e, (byte)0xf9, + (byte)0x7d, (byte)0x2f, (byte)0xe3, (byte)0x63, + (byte)0x63, (byte)0x0c, (byte)0x75, (byte)0xd8, + (byte)0xf6, (byte)0x81, (byte)0xb2, (byte)0x02, + (byte)0xae, (byte)0xc4, (byte)0x61, (byte)0x7a, + (byte)0xd3, (byte)0xdf, (byte)0x1e, (byte)0xd5, + (byte)0xd5, (byte)0xfd, (byte)0x65, (byte)0x61, + (byte)0x24, (byte)0x33, (byte)0xf5, (byte)0x1f, + (byte)0x5f, (byte)0x06, (byte)0x6e, (byte)0xd0, + (byte)0x85, (byte)0x63, (byte)0x65, (byte)0x55, + (byte)0x3d, (byte)0xed, (byte)0x1a, (byte)0xf3, + (byte)0xb5, (byte)0x57, (byte)0x13, (byte)0x5e, + (byte)0x7f, (byte)0x57, (byte)0xc9, (byte)0x35, + (byte)0x98, (byte)0x4f, (byte)0x0c, (byte)0x70, + (byte)0xe0, (byte)0xe6, (byte)0x8b, (byte)0x77, + (byte)0xe2, (byte)0xa6, (byte)0x89, (byte)0xda, + (byte)0xf3, (byte)0xef, (byte)0xe8, (byte)0x72, + (byte)0x1d, (byte)0xf1, (byte)0x58, (byte)0xa1, + (byte)0x36, (byte)0xad, (byte)0xe7, (byte)0x35, + (byte)0x30, (byte)0xac, (byte)0xca, (byte)0x4f, + (byte)0x48, (byte)0x3a, (byte)0x79, (byte)0x7a, + (byte)0xbc, (byte)0x0a, (byte)0xb1, (byte)0x82, + (byte)0xb3, (byte)0x24, (byte)0xfb, (byte)0x61, + (byte)0xd1, (byte)0x08, (byte)0xa9, (byte)0x4b, + (byte)0xb2, (byte)0xc8, (byte)0xe3, (byte)0xfb, + (byte)0xb9, (byte)0x6a, (byte)0xda, (byte)0xb7, + (byte)0x60, (byte)0xd7, (byte)0xf4, (byte)0x68, + (byte)0x1d, (byte)0x4f, (byte)0x42, (byte)0xa3, + (byte)0xde, (byte)0x39, (byte)0x4d, (byte)0xf4, + (byte)0xae, (byte)0x56, (byte)0xed, (byte)0xe7, + (byte)0x63, (byte)0x72, (byte)0xbb, (byte)0x19, + (byte)0x0b, (byte)0x07, (byte)0xa7, (byte)0xc8, + (byte)0xee, (byte)0x0a, (byte)0x6d, (byte)0x70, + (byte)0x9e, (byte)0x02, (byte)0xfc, (byte)0xe1, + (byte)0xcd, (byte)0xf7, (byte)0xe2, (byte)0xec, + (byte)0xc0, (byte)0x34, (byte)0x04, (byte)0xcd, + (byte)0x28, (byte)0x34, (byte)0x2f, (byte)0x61, + (byte)0x91, (byte)0x72, (byte)0xfe, (byte)0x9c, + (byte)0xe9, (byte)0x85, (byte)0x83, (byte)0xff, + (byte)0x8e, (byte)0x4f, (byte)0x12, (byte)0x32, + (byte)0xee, (byte)0xf2, (byte)0x81, (byte)0x83, + (byte)0xc3, (byte)0xfe, (byte)0x3b, (byte)0x1b, + (byte)0x4c, (byte)0x6f, (byte)0xad, (byte)0x73, + (byte)0x3b, (byte)0xb5, (byte)0xfc, (byte)0xbc, + (byte)0x2e, (byte)0xc2, (byte)0x20, (byte)0x05, + (byte)0xc5, (byte)0x8e, (byte)0xf1, (byte)0x83, + (byte)0x7d, (byte)0x16, (byte)0x83, (byte)0xb2, + (byte)0xc6, (byte)0xf3, (byte)0x4a, (byte)0x26, + (byte)0xc1, (byte)0xb2, (byte)0xef, (byte)0xfa, + (byte)0x88, (byte)0x6b, (byte)0x42, (byte)0x38, + (byte)0x61, (byte)0x28, (byte)0x5c, (byte)0x97, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x03, + (byte)0x82, (byte)0x01, (byte)0x06, (byte)0x00, + (byte)0x02, (byte)0x82, (byte)0x01, (byte)0x01, + (byte)0x00, (byte)0x8d, (byte)0xb4, (byte)0x1c, + (byte)0xfc, (byte)0xc0, (byte)0x5f, (byte)0x38, + (byte)0x4c, (byte)0x7f, (byte)0x31, (byte)0xaa, + (byte)0x03, (byte)0x06, (byte)0xf0, (byte)0xec, + (byte)0xfd, (byte)0x45, (byte)0x8d, (byte)0x69, + (byte)0x8a, (byte)0xb6, (byte)0x60, (byte)0x2f, + (byte)0xa2, (byte)0xb4, (byte)0xda, (byte)0xc0, + (byte)0x2e, (byte)0xe1, (byte)0x31, (byte)0x12, + (byte)0x5a, (byte)0x49, (byte)0xef, (byte)0xf7, + (byte)0x17, (byte)0x77, (byte)0x26, (byte)0xa8, + (byte)0x91, (byte)0x0b, (byte)0xbc, (byte)0x84, + (byte)0x5c, (byte)0x20, (byte)0x84, (byte)0xd3, + (byte)0x38, (byte)0xc9, (byte)0xa1, (byte)0x5b, + (byte)0xad, (byte)0x84, (byte)0x83, (byte)0xb9, + (byte)0xe1, (byte)0x59, (byte)0x87, (byte)0xd9, + (byte)0x9b, (byte)0x36, (byte)0x6b, (byte)0x3c, + (byte)0xb6, (byte)0x3c, (byte)0x3a, (byte)0x0c, + (byte)0xf4, (byte)0x0b, (byte)0xad, (byte)0x23, + (byte)0x8d, (byte)0x5f, (byte)0x80, (byte)0x16, + (byte)0xa3, (byte)0x96, (byte)0xbd, (byte)0x28, + (byte)0x2f, (byte)0x9f, (byte)0xd1, (byte)0x7e, + (byte)0x13, (byte)0x86, (byte)0x6a, (byte)0x22, + (byte)0x26, (byte)0xdb, (byte)0x3b, (byte)0x42, + (byte)0xf0, (byte)0x21, (byte)0x7a, (byte)0x6c, + (byte)0xe3, (byte)0xb0, (byte)0x8d, (byte)0x9c, + (byte)0x3b, (byte)0xfb, (byte)0x17, (byte)0x27, + (byte)0xde, (byte)0xe4, (byte)0x82, (byte)0x2e, + (byte)0x6d, (byte)0x08, (byte)0xeb, (byte)0x2b, + (byte)0xb9, (byte)0xb0, (byte)0x94, (byte)0x0e, + (byte)0x56, (byte)0xc1, (byte)0xf2, (byte)0x54, + (byte)0xd8, (byte)0x94, (byte)0x21, (byte)0xc2, + (byte)0x2d, (byte)0x4d, (byte)0x28, (byte)0xf2, + (byte)0xc3, (byte)0x96, (byte)0x5b, (byte)0x24, + (byte)0xb6, (byte)0xee, (byte)0xa4, (byte)0xbf, + (byte)0x20, (byte)0x19, (byte)0x29, (byte)0x1a, + (byte)0x55, (byte)0x46, (byte)0x7a, (byte)0x2a, + (byte)0x14, (byte)0x12, (byte)0x4d, (byte)0xf4, + (byte)0xee, (byte)0xf5, (byte)0x6f, (byte)0x4f, + (byte)0xf7, (byte)0x99, (byte)0x1c, (byte)0xa3, + (byte)0x72, (byte)0x33, (byte)0x7d, (byte)0xfe, + (byte)0xae, (byte)0x0b, (byte)0xda, (byte)0x2c, + (byte)0xc7, (byte)0xf3, (byte)0xba, (byte)0xb7, + (byte)0x83, (byte)0x58, (byte)0x4c, (byte)0x93, + (byte)0x5d, (byte)0x90, (byte)0x65, (byte)0xc9, + (byte)0xb8, (byte)0x6d, (byte)0x2d, (byte)0xda, + (byte)0x10, (byte)0x55, (byte)0xe6, (byte)0x27, + (byte)0xb9, (byte)0x4b, (byte)0x75, (byte)0x30, + (byte)0xfa, (byte)0xe4, (byte)0xa3, (byte)0xff, + (byte)0xae, (byte)0xf9, (byte)0xfb, (byte)0xe4, + (byte)0x62, (byte)0x89, (byte)0x7c, (byte)0x7d, + (byte)0x20, (byte)0x50, (byte)0xf9, (byte)0xd1, + (byte)0xe2, (byte)0x0e, (byte)0x56, (byte)0xf6, + (byte)0x3c, (byte)0x8b, (byte)0x24, (byte)0x8a, + (byte)0x6d, (byte)0x92, (byte)0x3f, (byte)0x85, + (byte)0x7b, (byte)0x3b, (byte)0x49, (byte)0x21, + (byte)0x9d, (byte)0x26, (byte)0x1b, (byte)0x58, + (byte)0x08, (byte)0x9e, (byte)0x5f, (byte)0xea, + (byte)0x23, (byte)0x20, (byte)0xc2, (byte)0x3d, + (byte)0x87, (byte)0xbe, (byte)0x1a, (byte)0x17, + (byte)0x34, (byte)0xd8, (byte)0x10, (byte)0x0f, + (byte)0x81, (byte)0xb6, (byte)0xc7, (byte)0xa5, + (byte)0xe9, (byte)0x8b, (byte)0x21, (byte)0xab, + (byte)0x09, (byte)0x88, (byte)0x5e, (byte)0xbd, + (byte)0xa2, (byte)0x8a, (byte)0xc4, (byte)0xa8, + (byte)0x83 }; private static final byte bobPrivKeyEnc[] = { - (byte)0x30, (byte)0x81, (byte)0xE4, (byte)0x02, - (byte)0x01, (byte)0x00, (byte)0x30, (byte)0x81, - (byte)0x99, (byte)0x06, (byte)0x09, (byte)0x2A, - (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xF7, - (byte)0x0D, (byte)0x01, (byte)0x03, (byte)0x01, - (byte)0x30, (byte)0x81, (byte)0x8B, (byte)0x02, - (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xF4, - (byte)0x88, (byte)0xFD, (byte)0x58, (byte)0x4E, - (byte)0x49, (byte)0xDB, (byte)0xCD, (byte)0x20, - (byte)0xB4, (byte)0x9D, (byte)0xE4, (byte)0x91, - (byte)0x07, (byte)0x36, (byte)0x6B, (byte)0x33, - (byte)0x6C, (byte)0x38, (byte)0x0D, (byte)0x45, - (byte)0x1D, (byte)0x0F, (byte)0x7C, (byte)0x88, - (byte)0xB3, (byte)0x1C, (byte)0x7C, (byte)0x5B, - (byte)0x2D, (byte)0x8E, (byte)0xF6, (byte)0xF3, - (byte)0xC9, (byte)0x23, (byte)0xC0, (byte)0x43, - (byte)0xF0, (byte)0xA5, (byte)0x5B, (byte)0x18, - (byte)0x8D, (byte)0x8E, (byte)0xBB, (byte)0x55, - (byte)0x8C, (byte)0xB8, (byte)0x5D, (byte)0x38, - (byte)0xD3, (byte)0x34, (byte)0xFD, (byte)0x7C, - (byte)0x17, (byte)0x57, (byte)0x43, (byte)0xA3, - (byte)0x1D, (byte)0x18, (byte)0x6C, (byte)0xDE, - (byte)0x33, (byte)0x21, (byte)0x2C, (byte)0xB5, - (byte)0x2A, (byte)0xFF, (byte)0x3C, (byte)0xE1, - (byte)0xB1, (byte)0x29, (byte)0x40, (byte)0x18, - (byte)0x11, (byte)0x8D, (byte)0x7C, (byte)0x84, - (byte)0xA7, (byte)0x0A, (byte)0x72, (byte)0xD6, - (byte)0x86, (byte)0xC4, (byte)0x03, (byte)0x19, - (byte)0xC8, (byte)0x07, (byte)0x29, (byte)0x7A, - (byte)0xCA, (byte)0x95, (byte)0x0C, (byte)0xD9, - (byte)0x96, (byte)0x9F, (byte)0xAB, (byte)0xD0, - (byte)0x0A, (byte)0x50, (byte)0x9B, (byte)0x02, - (byte)0x46, (byte)0xD3, (byte)0x08, (byte)0x3D, - (byte)0x66, (byte)0xA4, (byte)0x5D, (byte)0x41, - (byte)0x9F, (byte)0x9C, (byte)0x7C, (byte)0xBD, - (byte)0x89, (byte)0x4B, (byte)0x22, (byte)0x19, - (byte)0x26, (byte)0xBA, (byte)0xAB, (byte)0xA2, - (byte)0x5E, (byte)0xC3, (byte)0x55, (byte)0xE9, - (byte)0x2F, (byte)0x78, (byte)0xC7, (byte)0x02, - (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x02, - (byte)0x02, (byte)0x00, (byte)0x04, (byte)0x43, - (byte)0x02, (byte)0x41, (byte)0x00, (byte)0xE0, - (byte)0x31, (byte)0xE7, (byte)0x77, (byte)0xB8, - (byte)0xD0, (byte)0x7E, (byte)0x0A, (byte)0x9B, - (byte)0x94, (byte)0xD5, (byte)0x3D, (byte)0x33, - (byte)0x62, (byte)0x32, (byte)0x51, (byte)0xCE, - (byte)0x74, (byte)0x5C, (byte)0xA5, (byte)0x72, - (byte)0xD9, (byte)0x36, (byte)0xF3, (byte)0x8A, - (byte)0x3F, (byte)0x8B, (byte)0xC6, (byte)0xFE, - (byte)0xEF, (byte)0x94, (byte)0x8B, (byte)0x50, - (byte)0x41, (byte)0x9B, (byte)0x14, (byte)0xC8, - (byte)0xE9, (byte)0x1F, (byte)0x24, (byte)0x1F, - (byte)0x65, (byte)0x8E, (byte)0xD3, (byte)0x85, - (byte)0xD0, (byte)0x68, (byte)0x6C, (byte)0xF1, - (byte)0x79, (byte)0x45, (byte)0xD0, (byte)0x06, - (byte)0xA4, (byte)0xB8, (byte)0xE0, (byte)0x64, - (byte)0xF5, (byte)0x38, (byte)0x72, (byte)0x97, - (byte)0x00, (byte)0x23, (byte)0x5F + (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x3f, + (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30, + (byte)0x82, (byte)0x01, (byte)0x17, (byte)0x06, + (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, + (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, + (byte)0x03, (byte)0x01, (byte)0x30, (byte)0x82, + (byte)0x01, (byte)0x08, (byte)0x02, (byte)0x82, + (byte)0x01, (byte)0x01, (byte)0x00, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xad, + (byte)0xf8, (byte)0x54, (byte)0x58, (byte)0xa2, + (byte)0xbb, (byte)0x4a, (byte)0x9a, (byte)0xaf, + (byte)0xdc, (byte)0x56, (byte)0x20, (byte)0x27, + (byte)0x3d, (byte)0x3c, (byte)0xf1, (byte)0xd8, + (byte)0xb9, (byte)0xc5, (byte)0x83, (byte)0xce, + (byte)0x2d, (byte)0x36, (byte)0x95, (byte)0xa9, + (byte)0xe1, (byte)0x36, (byte)0x41, (byte)0x14, + (byte)0x64, (byte)0x33, (byte)0xfb, (byte)0xcc, + (byte)0x93, (byte)0x9d, (byte)0xce, (byte)0x24, + (byte)0x9b, (byte)0x3e, (byte)0xf9, (byte)0x7d, + (byte)0x2f, (byte)0xe3, (byte)0x63, (byte)0x63, + (byte)0x0c, (byte)0x75, (byte)0xd8, (byte)0xf6, + (byte)0x81, (byte)0xb2, (byte)0x02, (byte)0xae, + (byte)0xc4, (byte)0x61, (byte)0x7a, (byte)0xd3, + (byte)0xdf, (byte)0x1e, (byte)0xd5, (byte)0xd5, + (byte)0xfd, (byte)0x65, (byte)0x61, (byte)0x24, + (byte)0x33, (byte)0xf5, (byte)0x1f, (byte)0x5f, + (byte)0x06, (byte)0x6e, (byte)0xd0, (byte)0x85, + (byte)0x63, (byte)0x65, (byte)0x55, (byte)0x3d, + (byte)0xed, (byte)0x1a, (byte)0xf3, (byte)0xb5, + (byte)0x57, (byte)0x13, (byte)0x5e, (byte)0x7f, + (byte)0x57, (byte)0xc9, (byte)0x35, (byte)0x98, + (byte)0x4f, (byte)0x0c, (byte)0x70, (byte)0xe0, + (byte)0xe6, (byte)0x8b, (byte)0x77, (byte)0xe2, + (byte)0xa6, (byte)0x89, (byte)0xda, (byte)0xf3, + (byte)0xef, (byte)0xe8, (byte)0x72, (byte)0x1d, + (byte)0xf1, (byte)0x58, (byte)0xa1, (byte)0x36, + (byte)0xad, (byte)0xe7, (byte)0x35, (byte)0x30, + (byte)0xac, (byte)0xca, (byte)0x4f, (byte)0x48, + (byte)0x3a, (byte)0x79, (byte)0x7a, (byte)0xbc, + (byte)0x0a, (byte)0xb1, (byte)0x82, (byte)0xb3, + (byte)0x24, (byte)0xfb, (byte)0x61, (byte)0xd1, + (byte)0x08, (byte)0xa9, (byte)0x4b, (byte)0xb2, + (byte)0xc8, (byte)0xe3, (byte)0xfb, (byte)0xb9, + (byte)0x6a, (byte)0xda, (byte)0xb7, (byte)0x60, + (byte)0xd7, (byte)0xf4, (byte)0x68, (byte)0x1d, + (byte)0x4f, (byte)0x42, (byte)0xa3, (byte)0xde, + (byte)0x39, (byte)0x4d, (byte)0xf4, (byte)0xae, + (byte)0x56, (byte)0xed, (byte)0xe7, (byte)0x63, + (byte)0x72, (byte)0xbb, (byte)0x19, (byte)0x0b, + (byte)0x07, (byte)0xa7, (byte)0xc8, (byte)0xee, + (byte)0x0a, (byte)0x6d, (byte)0x70, (byte)0x9e, + (byte)0x02, (byte)0xfc, (byte)0xe1, (byte)0xcd, + (byte)0xf7, (byte)0xe2, (byte)0xec, (byte)0xc0, + (byte)0x34, (byte)0x04, (byte)0xcd, (byte)0x28, + (byte)0x34, (byte)0x2f, (byte)0x61, (byte)0x91, + (byte)0x72, (byte)0xfe, (byte)0x9c, (byte)0xe9, + (byte)0x85, (byte)0x83, (byte)0xff, (byte)0x8e, + (byte)0x4f, (byte)0x12, (byte)0x32, (byte)0xee, + (byte)0xf2, (byte)0x81, (byte)0x83, (byte)0xc3, + (byte)0xfe, (byte)0x3b, (byte)0x1b, (byte)0x4c, + (byte)0x6f, (byte)0xad, (byte)0x73, (byte)0x3b, + (byte)0xb5, (byte)0xfc, (byte)0xbc, (byte)0x2e, + (byte)0xc2, (byte)0x20, (byte)0x05, (byte)0xc5, + (byte)0x8e, (byte)0xf1, (byte)0x83, (byte)0x7d, + (byte)0x16, (byte)0x83, (byte)0xb2, (byte)0xc6, + (byte)0xf3, (byte)0x4a, (byte)0x26, (byte)0xc1, + (byte)0xb2, (byte)0xef, (byte)0xfa, (byte)0x88, + (byte)0x6b, (byte)0x42, (byte)0x38, (byte)0x61, + (byte)0x28, (byte)0x5c, (byte)0x97, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x02, + (byte)0x01, (byte)0x02, (byte)0x04, (byte)0x1f, + (byte)0x02, (byte)0x1d, (byte)0x01, (byte)0x62, + (byte)0x8e, (byte)0xfc, (byte)0xf3, (byte)0x25, + (byte)0xf3, (byte)0x2a, (byte)0xf4, (byte)0x49, + (byte)0x20, (byte)0x83, (byte)0x61, (byte)0x7f, + (byte)0x97, (byte)0x8f, (byte)0x48, (byte)0xac, + (byte)0xf9, (byte)0xc3, (byte)0xad, (byte)0x3c, + (byte)0x56, (byte)0x95, (byte)0x1c, (byte)0x85, + (byte)0xd3, (byte)0x85, (byte)0xd6 }; } diff --git a/test/jdk/com/sun/crypto/provider/TLS/TestMasterSecret.java b/test/jdk/com/sun/crypto/provider/TLS/TestMasterSecret.java index 10f6ddc401901..f34bdff2ef791 100644 --- a/test/jdk/com/sun/crypto/provider/TLS/TestMasterSecret.java +++ b/test/jdk/com/sun/crypto/provider/TLS/TestMasterSecret.java @@ -49,7 +49,8 @@ public class TestMasterSecret extends Utils { private static int PREFIX_LENGTH = "m-premaster: ".length(); public static void main(String[] args) throws Exception { - Provider provider = Security.getProvider("SunJCE"); + Provider provider = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); InputStream in = new FileInputStream(new File(BASE, "masterdata.txt")); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); diff --git a/test/jdk/com/sun/crypto/provider/TLS/TestPRF.java b/test/jdk/com/sun/crypto/provider/TLS/TestPRF.java index 577927ea883a4..d35232431bff0 100644 --- a/test/jdk/com/sun/crypto/provider/TLS/TestPRF.java +++ b/test/jdk/com/sun/crypto/provider/TLS/TestPRF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, 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 @@ -47,7 +47,8 @@ public class TestPRF extends Utils { private static int PREFIX_LENGTH = "prf-output: ".length(); public static void main(String[] args) throws Exception { - Provider provider = Security.getProvider("SunJCE"); + Provider provider = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); InputStream in = new FileInputStream(new File(BASE, "prfdata.txt")); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); diff --git a/test/jdk/com/sun/crypto/provider/TLS/TestPRF12.java b/test/jdk/com/sun/crypto/provider/TLS/TestPRF12.java index dffda070e47c3..692fc630f9b98 100644 --- a/test/jdk/com/sun/crypto/provider/TLS/TestPRF12.java +++ b/test/jdk/com/sun/crypto/provider/TLS/TestPRF12.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 @@ -50,7 +50,8 @@ public class TestPRF12 extends Utils { private static int PREFIX_LENGTH = "prf-output: ".length(); public static void main(String[] args) throws Exception { - Provider provider = Security.getProvider("SunJCE"); + Provider provider = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); InputStream in = new FileInputStream(new File(BASE, "prf12data.txt")); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); diff --git a/test/jdk/com/sun/crypto/provider/TLS/TestPremaster.java b/test/jdk/com/sun/crypto/provider/TLS/TestPremaster.java index b95b0855dd033..096af76cfe402 100644 --- a/test/jdk/com/sun/crypto/provider/TLS/TestPremaster.java +++ b/test/jdk/com/sun/crypto/provider/TLS/TestPremaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, 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 @@ -41,7 +41,8 @@ public class TestPremaster { public static void main(String[] args) throws Exception { - Provider provider = Security.getProvider("SunJCE"); + Provider provider = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); KeyGenerator kg; diff --git a/test/jdk/com/sun/jdi/ClassesByName2Test.java b/test/jdk/com/sun/jdi/ClassesByName2Test.java index acc186e722566..b8f517d044876 100644 --- a/test/jdk/com/sun/jdi/ClassesByName2Test.java +++ b/test/jdk/com/sun/jdi/ClassesByName2Test.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 @@ -58,7 +58,8 @@ public static void main(String[] args){ Thread one = DebuggeeWrapper.newThread (() -> { try { java.security.KeyPairGenerator keyGen = - java.security.KeyPairGenerator.getInstance("DSA", "SUN"); + java.security.KeyPairGenerator.getInstance("DSA", + System.getProperty("test.provider.name", "SUN")); } catch (Exception e) { e.printStackTrace(); } diff --git a/test/jdk/com/sun/jdi/EATests.java b/test/jdk/com/sun/jdi/EATests.java index adeb21741438f..b2a2cad49db7f 100644 --- a/test/jdk/com/sun/jdi/EATests.java +++ b/test/jdk/com/sun/jdi/EATests.java @@ -158,6 +158,19 @@ * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks * -XX:LockingMode=0 * -XX:GuaranteedAsyncDeflationInterval=1000 + * + * @bug 8341819 + * @comment Regression test for re-locking racing with deflation with LM_LIGHTWEIGHT. + * @run driver EATests + * -XX:+UnlockDiagnosticVMOptions + * -Xms256m -Xmx256m + * -Xbootclasspath/a:. + * -XX:CompileCommand=dontinline,*::dontinline_* + * -XX:+WhiteBoxAPI + * -Xbatch + * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks + * -XX:LockingMode=2 + * -XX:GuaranteedAsyncDeflationInterval=1 */ /** diff --git a/test/jdk/com/sun/jdi/OnJcmdTest.java b/test/jdk/com/sun/jdi/OnJcmdTest.java deleted file mode 100644 index c7f93e6fb3167..0000000000000 --- a/test/jdk/com/sun/jdi/OnJcmdTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018 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. - */ - -/** - * @test - * @bug 8214892 - * @summary Test that the onjcmd option of the jdwp agent works. - * - * @author Ralf Schmelter - * - * @library /test/lib - * @run compile --add-exports java.base/jdk.internal.vm=ALL-UNNAMED -g OnJcmdTest.java - * @run main/othervm --add-exports java.base/jdk.internal.vm=ALL-UNNAMED -agentlib:jdwp=transport=dt_socket,address=localhost:0,onjcmd=y,server=y OnJcmdTest - */ - -import java.lang.reflect.Method; -import java.util.Properties; - -import jdk.internal.vm.VMSupport; -import jdk.test.lib.JDKToolFinder; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; - -public class OnJcmdTest { - - private static String getListenerAddress() throws Exception { - Properties props = VMSupport.getAgentProperties(); - return props.getProperty("sun.jdwp.listenerAddress", null); - } - - public static void main(String[] args) throws Throwable { - // First check if we get the expected errors. - OutputAnalyzer output = ProcessTools.executeTestJava( - "-agentlib:jdwp=transport=dt_socket,address=any,onjcmd=y"); - output.shouldContain("Can only use onjcmd with server=y"); - output.shouldHaveExitValue(1); - - output = ProcessTools.executeTestJava( - "-agentlib:jdwp=transport=dt_socket,address=any,onjcmd=y,onthrow=a,launch=a"); - output.shouldContain("Cannot combine onjcmd and launch suboptions"); - output.shouldHaveExitValue(1); - - // Make sure debugging is not yet started. - String prop = getListenerAddress(); - - if (prop != null) { - throw new RuntimeException("Listener address was set to " + prop); - } - - // Now start it (test that it is OK to do this more than once). - for (int i = 0; i < 3; ++i) { - String jcmd = JDKToolFinder.getJDKTool("jcmd"); - output = ProcessTools.executeProcess(jcmd, - Long.toString(ProcessTools.getProcessId()), - "VM.start_java_debugging"); - - String exp_str = i == 0 ? "Debugging has been started." : - "Debugging is already active."; - output.shouldContain(exp_str); - output.shouldContain("Transport : dt_socket"); - output.shouldHaveExitValue(0); - } - - // Now the property should be set, as the jdwp agent waits for a - // connection. - long t1 = System.currentTimeMillis(); - long t2 = t1; - - while(t2 - t1 < 4000) { - prop = getListenerAddress(); - - if (prop != null) { - if (prop.equals("localhost:0")) { - throw new RuntimeException("Port was not expanded"); - } else if (!prop.startsWith("dt_socket:")) { - throw new RuntimeException("Invalid transport prop " + prop); - } - - return; - } - - Thread.sleep(50); - t2 = System.currentTimeMillis(); - } - - throw new RuntimeException("Debugging backend didn't start"); - } -} diff --git a/test/jdk/com/sun/jndi/dns/ConfigTests/Timeout.java b/test/jdk/com/sun/jndi/dns/ConfigTests/Timeout.java index 90a2a7b981565..e03923b6c3442 100644 --- a/test/jdk/com/sun/jndi/dns/ConfigTests/Timeout.java +++ b/test/jdk/com/sun/jndi/dns/ConfigTests/Timeout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import java.net.InetSocketAddress; import java.net.SocketTimeoutException; import java.time.Duration; -import java.time.Instant; import jdk.test.lib.net.URIBuilder; @@ -40,7 +39,7 @@ * number of retries. * @library ../lib/ /test/lib * @modules java.base/sun.security.util - * @run main Timeout + * @run main/othervm Timeout */ public class Timeout extends DNSTestBase { @@ -48,8 +47,12 @@ public class Timeout extends DNSTestBase { private static final int TIMEOUT = 250; // try 5 times per server private static final int RETRIES = 5; + // DnsClient retries again with increased timeout if left + // timeout is less than this value, and max retry attempts + // is not reached + private static final int DNS_CLIENT_MIN_TIMEOUT = 0; - private Instant startTime; + private long startTime; public Timeout() { setLocalServer(false); @@ -81,7 +84,7 @@ public void runTest() throws Exception { setContext(new InitialDirContext(env())); // Any request should fail after timeouts have expired. - startTime = Instant.now(); + startTime = System.nanoTime(); context().getAttributes(""); throw new RuntimeException( @@ -92,28 +95,35 @@ public void runTest() throws Exception { @Override public boolean handleException(Exception e) { if (e instanceof CommunicationException) { - Duration elapsedTime = Duration.between(startTime, Instant.now()); + Duration elapsedTime = Duration.ofNanos(System.nanoTime() - startTime); if (!(((CommunicationException) e) .getRootCause() instanceof SocketTimeoutException)) { return false; } - Duration expectedTime = Duration.ofMillis(TIMEOUT) - .multipliedBy((1 << RETRIES) - 1); + Duration minAllowedTime = Duration.ofMillis(TIMEOUT) + .multipliedBy((1 << RETRIES) - 1) + .minus(Duration.ofMillis(DNS_CLIENT_MIN_TIMEOUT * RETRIES)); + Duration maxAllowedTime = Duration.ofMillis(TIMEOUT) + .multipliedBy((1 << RETRIES) - 1) + // max allowed timeout value is set to 2 * expected timeout + .multipliedBy(2); + DNSTestUtils.debug("Elapsed (ms): " + elapsedTime.toMillis()); - DNSTestUtils.debug("Expected (ms): " + expectedTime.toMillis()); + String expectedRangeMsg = "%s - %s" + .formatted(minAllowedTime.toMillis(), maxAllowedTime.toMillis()); + DNSTestUtils.debug("Expected range (ms): " + expectedRangeMsg); // Check that elapsed time is as long as expected, and - // not more than 50% greater. - if (elapsedTime.compareTo(expectedTime) >= 0 && - elapsedTime.multipliedBy(2) - .compareTo(expectedTime.multipliedBy(3)) <= 0) { + // not more than 2 times greater. + if (elapsedTime.compareTo(minAllowedTime) >= 0 && + elapsedTime.compareTo(maxAllowedTime) <= 0) { System.out.println("elapsed time is as long as expected."); return true; } throw new RuntimeException( - "Failed: timeout in " + elapsedTime.toMillis() - + " ms, expected" + expectedTime.toMillis() + "ms"); + "Failed: timeout in " + elapsedTime.toMillis() + + " ms, expected to be in a range (ms): " + expectedRangeMsg); } return super.handleException(e); diff --git a/test/jdk/com/sun/jndi/dns/ConfigTests/TimeoutWithEmptyDatagrams.java b/test/jdk/com/sun/jndi/dns/ConfigTests/TimeoutWithEmptyDatagrams.java new file mode 100644 index 0000000000000..9fb8954c99c54 --- /dev/null +++ b/test/jdk/com/sun/jndi/dns/ConfigTests/TimeoutWithEmptyDatagrams.java @@ -0,0 +1,196 @@ +/* + * 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 jdk.test.lib.net.URIBuilder; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.directory.InitialDirContext; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; +import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +/* + * @test + * @bug 8339538 + * @summary Tests that DnsClient correctly calculates left timeout in + * presence of empty datagram packets. + * @library ../lib /test/lib + * @modules java.base/sun.security.util + * @run main/othervm TimeoutWithEmptyDatagrams + */ + +public class TimeoutWithEmptyDatagrams extends DNSTestBase { + // initial timeout = 1/4 sec + private static final int TIMEOUT = 250; + // try 5 times per server + private static final int RETRIES = 5; + // DnsClient retries again with increased timeout if left + // timeout is less than this value, and max retry attempts + // is not reached + private static final int DNS_CLIENT_MIN_TIMEOUT = 0; + + public TimeoutWithEmptyDatagrams() { + setLocalServer(false); + } + + public static void main(String[] args) throws Exception { + new TimeoutWithEmptyDatagrams().run(args); + } + + /* + * Tests that we can set the initial UDP timeout interval and the + * number of retries. + */ + @Override + public void runTest() throws Exception { + // Create a DatagramSocket and bind it to the loopback address to simulate + // UDP DNS server that doesn't respond + try (DatagramSocket ds = new DatagramSocket(new InetSocketAddress( + InetAddress.getLoopbackAddress(), 0))) { + CountDownLatch gotClientAddress = new CountDownLatch(1); + AtomicReference clientAddress = new AtomicReference<>(); + AtomicBoolean stopTestThreads = new AtomicBoolean(); + + String allQuietUrl = URIBuilder.newBuilder() + .scheme("dns") + .loopback() + .port(ds.getLocalPort()) + .build() + .toString(); + + // Run a virtual thread that receives client request packets and extracts + // sender address from them. + Thread receiverThread = Thread.ofVirtual().start(() -> { + while (!stopTestThreads.get()) { + try { + DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); + ds.receive(packet); + System.err.println("Got packet from " + packet.getSocketAddress()); + boolean hasClientAddress = clientAddress.get() != null; + clientAddress.set(packet.getSocketAddress()); + if (!hasClientAddress) { + gotClientAddress.countDown(); + } + } catch (IOException e) { + if (!stopTestThreads.get()) { + throw new RuntimeException(e); + } else { + return; + } + } + } + }); + + // Run a virtual thread that will send an empty packets via server socket + // that should wake up the selector on a client side. + Thread wakeupThread = Thread.ofVirtual().start(() -> { + try { + long timeout = Math.max(1, TIMEOUT / 4); + // wait for a first packet on a server socket + gotClientAddress.await(); + + // Now start sending empty packets until we get a notification + // from client part to stop sending + while (!stopTestThreads.get()) { + System.err.println("Server timeout = " + timeout); + TimeUnit.MILLISECONDS.sleep(timeout); + System.err.println("Sending wakeup packet to " + clientAddress.get()); + var wakeupPacket = new DatagramPacket(new byte[0], 0); + wakeupPacket.setSocketAddress(clientAddress.get()); + ds.send(wakeupPacket); + timeout += Math.max(1, timeout / 2); + } + } catch (IOException ioe) { + throw new RuntimeException("Test machinery failure", ioe); + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted during wakeup packets sending"); + } finally { + System.err.println("Server thread exiting"); + } + }); + + long startTime = 0; + try { + env().put(Context.PROVIDER_URL, allQuietUrl); + env().put("com.sun.jndi.dns.timeout.initial", String.valueOf(TIMEOUT)); + env().put("com.sun.jndi.dns.timeout.retries", String.valueOf(RETRIES)); + setContext(new InitialDirContext(env())); + + startTime = System.nanoTime(); + context().getAttributes(""); + + // Any request should fail after timeouts have expired. + throw new RuntimeException("Failed: getAttributes succeeded unexpectedly"); + } catch (CommunicationException ce) { + // We need to catch CommunicationException outside the test framework + // flow because wakeupThread.join() can take some time that could + // increase measured timeout + long endTime = System.nanoTime(); + Duration elapsedTime = Duration.ofNanos(endTime - startTime); + if (ce.getRootCause() instanceof SocketTimeoutException) { + + Duration minAllowedTime = Duration.ofMillis(TIMEOUT) + .multipliedBy((1 << RETRIES) - 1) + .minus(Duration.ofMillis(DNS_CLIENT_MIN_TIMEOUT * RETRIES)); + Duration maxAllowedTime = Duration.ofMillis(TIMEOUT) + .multipliedBy((1 << RETRIES) - 1) + // max allowed timeout value is set to 2 * expected timeout + .multipliedBy(2); + + DNSTestUtils.debug("Elapsed (ms): " + elapsedTime.toMillis()); + String expectedRangeMsg = "%s - %s" + .formatted(minAllowedTime.toMillis(), maxAllowedTime.toMillis()); + DNSTestUtils.debug("Expected range (ms): " + expectedRangeMsg); + + // Check that elapsed time is as long as expected, and + // not more than 2 times greater. + if (elapsedTime.compareTo(minAllowedTime) >= 0 && + elapsedTime.compareTo(maxAllowedTime) <= 0) { + System.out.println("elapsed time is as long as expected."); + } else { + throw new RuntimeException( + "Failed: timeout in " + elapsedTime.toMillis() + + " ms, expected to be in a range (ms): " + expectedRangeMsg); + } + } else { + throw ce; + } + } finally { + stopTestThreads.set(true); + wakeupThread.join(); + ds.close(); + receiverThread.join(); + } + } + } +} diff --git a/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java b/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java index 3cc9f40b8957c..ba6fffd067025 100644 --- a/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java +++ b/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 7150256 + * @bug 7150256 8338603 * @summary Basic Test for the DiagnosticCommandMBean * @author Frederic Parain, Shanliang JIANG * @@ -68,10 +68,14 @@ public static void main(String[] args) throws Exception { System.out.println("Description:" + info.getDescription()); MBeanOperationInfo[] opInfo = info.getOperations(); System.out.println("Operations:"); + int operationFailures = 0; for (int i = 0; i < opInfo.length; i++) { - printOperation(opInfo[i]); + operationFailures += printOperation(opInfo[i]); System.out.println("\n@@@@@@\n"); } + if (operationFailures > 0) { + throw new RuntimeException("FAILED. " + operationFailures + " operations found with non-standard parameter types."); + } } finally { try { cc.close(); @@ -83,7 +87,12 @@ public static void main(String[] args) throws Exception { System.out.println("Test passed"); } - static void printOperation(MBeanOperationInfo info) { + /** + * Print an Operation, and check for any non-standard parameter types. + * Return the number of failed parameters, so the caller can signal to fail the test. + */ + static int printOperation(MBeanOperationInfo info) { + int failures = 0; System.out.println("Name: "+info.getName()); System.out.println("Description: "+info.getDescription()); System.out.println("Return Type: "+info.getReturnType()); @@ -100,8 +109,16 @@ static void printOperation(MBeanOperationInfo info) { Descriptor desc3 = (Descriptor)desc2.getFieldValue(desc2.getFieldNames()[j]); for(int k=0; k */ - permission java.io.FilePermission "<>", "read,write,delete"; + /* + * To read configuration file in META-INF/services, write/delete .attach_pid, + * and read symbolic link of /proc/self/ns/mnt. + */ + permission java.io.FilePermission "<>", "read,write,delete,readlink"; }; diff --git a/test/jdk/java/awt/Canvas/MultiDitherTest.java b/test/jdk/java/awt/Canvas/MultiDitherTest.java new file mode 100644 index 0000000000000..ab592280c80b4 --- /dev/null +++ b/test/jdk/java/awt/Canvas/MultiDitherTest.java @@ -0,0 +1,422 @@ +/* + * 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 6616089 + * @summary Displays a dithered Canvas on all available GraphicsConfigurations + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiDitherTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Label; +import java.awt.LayoutManager; +import java.awt.Panel; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.ColorModel; +import java.awt.image.MemoryImageSource; +import java.util.List; + +public class MultiDitherTest extends Panel implements Runnable { + final static int NOOP = 0; + final static int RED = 1; + final static int GREEN = 2; + final static int BLUE = 3; + final static int ALPHA = 4; + final static int SATURATION = 5; + final static String calcString = "Calculating..."; + static LayoutManager dcLayout = new FlowLayout(FlowLayout.CENTER, 10, 5); + Thread runner; + DitherControls XControls; + DitherControls YControls; + DitherCanvas canvas; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Depending on the GraphicsConfiguration, the dithering may be in + color or in grayscale and/or display at a lower bitdepth. + The number of GraphicsConfigurations will be printed in the + TextArea below as the test is starting up. + Ensure that there are as many Frames created as there are + available GraphicsConfigurations. + Examine each Frame to ensure it displays the dither pattern. + If all Canvases display correctly, the test PASSES. + Otherwise, the test FAILS. + The GC button runs the garbage collector. + This button can be ignored for now. + + """; + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .build(); + + EventQueue.invokeAndWait(() -> { + for (Frame frame : MultiDitherTest.initialize()) { + PassFailJFrame.addTestWindow(frame); + frame.setVisible(true); + } + }); + passFailJFrame.awaitAndCheck(); + } + + public MultiDitherTest(GraphicsConfiguration gc) { + String xSpec, ySpec; + int[] xValues = new int[2]; + int[] yValues = new int[2]; + + xSpec = "red"; + ySpec = "blue"; + int xMethod = colorMethod(xSpec, xValues); + int yMethod = colorMethod(ySpec, yValues); + + setLayout(new BorderLayout()); + XControls = new DitherControls(this, xValues[0], xValues[1], + xMethod, false); + YControls = new DitherControls(this, yValues[0], yValues[1], + yMethod, true); + YControls.addRenderButton(); + YControls.addGCButton(); + add("North", XControls); + add("South", YControls); + add("Center", canvas = new DitherCanvas(gc)); + } + + private static List initialize() { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] gds = ge.getScreenDevices(); + Frame[] frames = new Frame[0]; + System.out.println(gds.length + " screens detected"); + + for (int j = 0; j < gds.length; j++) { + + GraphicsDevice gd = gds[j]; + GraphicsConfiguration[] gcs = gd.getConfigurations(); + frames = new Frame[gcs.length]; + System.out.println(gcs.length + " GraphicsConfigurations available on screen " + j); + for (int i = 0; i < gcs.length; i++) { + Frame f = new Frame("MultiDitherTest " + (i + 1), gcs[i]); + f.setLayout(new BorderLayout()); + f.setLocation(gcs[i].getBounds().x + 100 + (i * 10), + gcs[i].getBounds().y + 100 + (i * 10)); + MultiDitherTest ditherTest = new MultiDitherTest(gcs[i]); + f.add("Center", ditherTest); + f.pack(); + f.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + ev.getWindow().dispose(); + } + }); + f.setVisible(true); + ditherTest.start(); + frames[i] = f; + } + + } + return List.of(frames); + } + + int colorMethod(String s, int[] values) { + int method = NOOP; + + if (s == null) { + s = ""; + } + + String lower = s.toLowerCase(); + if (lower.startsWith("red")) { + method = RED; + lower = lower.substring(3); + } else if (lower.startsWith("green")) { + method = GREEN; + lower = lower.substring(5); + } else if (lower.startsWith("blue")) { + method = BLUE; + lower = lower.substring(4); + } else if (lower.startsWith("alpha")) { + method = ALPHA; + lower = lower.substring(4); + } else if (lower.startsWith("saturation")) { + method = SATURATION; + lower = lower.substring(10); + } + + if (method == NOOP) { + values[0] = 0; + values[1] = 0; + return method; + } + + int begval = 0; + int endval = 255; + + try { + int dash = lower.indexOf('-'); + if (dash < 0) { + begval = endval = Integer.parseInt(lower); + } else { + begval = Integer.parseInt(lower.substring(0, dash)); + endval = Integer.parseInt(lower.substring(dash + 1)); + } + } catch (Exception e) { + } + + if (begval < 0) { + begval = 0; + } + if (endval < 0) { + endval = 0; + } + if (begval > 255) { + begval = 255; + } + if (endval > 255) { + endval = 255; + } + + values[0] = begval; + values[1] = endval; + + return method; + } + + public void start() { + runner = new Thread(this); + runner.start(); + } + + public void stop() { + runner = null; + } + + public void destroy() { + remove(XControls); + remove(YControls); + remove(canvas); + } + + void applyMethod(int[] c, int method, int step, int total, int[] values) { + if (method == NOOP) { + return; + } + int val = ((total < 2) + ? values[0] + : values[0] + ((values[1] - values[0]) * step / (total - 1))); + switch (method) { + case RED: + c[0] = val; + break; + case GREEN: + c[1] = val; + break; + case BLUE: + c[2] = val; + break; + case ALPHA: + c[3] = val; + break; + case SATURATION: + int max = Math.max(Math.max(c[0], c[1]), c[2]); + int min = max * (255 - val) / 255; + if (c[0] == 0) c[0] = min; + if (c[1] == 0) c[1] = min; + if (c[2] == 0) c[2] = min; + break; + } + } + + public void run() { + canvas.setImage(null); + Image img = calculateImage(); + synchronized (this) { + if (img != null && runner == Thread.currentThread()) { + canvas.setImage(img); + } + } + } + + /** + * Calculates and returns the image. Halts the calculation and returns + * null if the Application is stopped during the calculation. + */ + Image calculateImage() { + Thread me = Thread.currentThread(); + + int width = canvas.getSize().width; + int height = canvas.getSize().height; + int[] xValues = new int[2]; + int[] yValues = new int[2]; + int xMethod = XControls.getParams(xValues); + int yMethod = YControls.getParams(yValues); + int[] pixels = new int[width * height]; + int[] c = new int[4]; + int index = 0; + + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + c[0] = c[1] = c[2] = 0; + c[3] = 255; + if (xMethod < yMethod) { + applyMethod(c, xMethod, i, width, xValues); + applyMethod(c, yMethod, j, height, yValues); + } else { + applyMethod(c, yMethod, j, height, yValues); + applyMethod(c, xMethod, i, width, xValues); + } + pixels[index++] = ((c[3] << 24) | + (c[0] << 16) | + (c[1] << 8) | + (c[2] << 0)); + } + // Poll once per row to see if we've been told to stop. + if (runner != me) { + return null; + } + } + + return createImage(new MemoryImageSource(width, height, + ColorModel.getRGBdefault(), pixels, 0, width)); + } + + static class DitherCanvas extends Canvas { + Image img; + GraphicsConfiguration mGC; + + public DitherCanvas(GraphicsConfiguration gc) { + super(gc); + mGC = gc; + } + + public GraphicsConfiguration getGraphicsConfig() { + return mGC; + } + + public void paint(Graphics g) { + int w = getSize().width; + int h = getSize().height; + if (img == null) { + super.paint(g); + g.setColor(Color.black); + FontMetrics fm = g.getFontMetrics(); + int x = (w - fm.stringWidth(calcString)) / 2; + int y = h / 2; + g.drawString(calcString, x, y); + } else { + g.drawImage(img, 0, 0, w, h, this); + } + } + + public void update(Graphics g) { + paint(g); + } + + public Dimension getMinimumSize() { + return new Dimension(20, 20); + } + + public Dimension getPreferredSize() { + return new Dimension(200, 200); + } + + public Image getImage() { + return img; + } + + public void setImage(Image img) { + this.img = img; + paint(getGraphics()); + } + } + + static class DitherControls extends Panel implements ActionListener { + TextField start; + TextField end; + Button button; + Choice choice; + MultiDitherTest panel; + Button gc; + + public DitherControls(MultiDitherTest app, int s, int e, int type, + boolean vertical) { + panel = app; + setLayout(dcLayout); + add(new Label(vertical ? "Vertical" : "Horizontal")); + add(choice = new Choice()); + choice.addItem("Noop"); + choice.addItem("Red"); + choice.addItem("Green"); + choice.addItem("Blue"); + choice.addItem("Alpha"); + choice.addItem("Saturation"); + choice.select(type); + add(start = new TextField(Integer.toString(s), 4)); + add(end = new TextField(Integer.toString(e), 4)); + } + + public void addRenderButton() { + add(button = new Button("New Image")); + button.addActionListener(this); + } + + public void addGCButton() { + add(gc = new Button("GC")); + gc.addActionListener(this); + } + + public int getParams(int[] values) { + values[0] = Integer.parseInt(start.getText()); + values[1] = Integer.parseInt(end.getText()); + return choice.getSelectedIndex(); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == button) { + panel.start(); + } else if (e.getSource() == gc) { + System.gc(); + } + } + } +} \ No newline at end of file diff --git a/test/jdk/java/awt/Canvas/MultiGraphicsTest.java b/test/jdk/java/awt/Canvas/MultiGraphicsTest.java new file mode 100644 index 0000000000000..c38d6041c2b77 --- /dev/null +++ b/test/jdk/java/awt/Canvas/MultiGraphicsTest.java @@ -0,0 +1,139 @@ +/* + * 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 6616089 + * @summary Display an image in all available GraphicsConfigurations + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiGraphicsTest + */ + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.net.URL; +import java.util.List; + +public class MultiGraphicsTest extends Canvas { + final static String IMAGEFILE = "duke_404.gif"; + static Image jim; + MediaTracker tracker; + int w, h; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test displays several Windows containing an image, + one Window for each available GraphicsConfiguration. + Depending on the GraphicsConfiguration, images may be + displayed in color or in grayscale and/or displayed at a + lower bitdepth. + The number of GraphicsConfigurations will be printed below + as the test is starting up. + Ensure that there are as many Windows created as there are + available GraphicsConfigurations. + Examine each Window to ensure it displays Duke_404. + If all Canvases display correctly, the test PASSES. + Otherwise, the test FAILS." + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public MultiGraphicsTest(GraphicsConfiguration gc) { + super(gc); + tracker = new MediaTracker(this); + tracker.addImage(jim, 0); + try { + tracker.waitForAll(); + } catch (java.lang.InterruptedException e) { + System.err.println(e); + } + w = jim.getWidth(this); + h = jim.getHeight(this); + } + + private static List initialize() { + URL imgURL; + imgURL = MultiGraphicsTest.class.getResource(IMAGEFILE); + if (imgURL == null) { + System.err.println("Unable to locate " + IMAGEFILE); + return null; + } + jim = Toolkit.getDefaultToolkit().getImage(imgURL); + + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration[] gc = gd.getConfigurations(); + Frame[] frames = new Frame[gc.length]; + System.out.println(gc.length + " available GraphicsConfigurations"); + for (int i = 0; i < gc.length; i++) { + Frame f = new Frame("GraphicsTest " + (i + 1)); + f.setLayout(new BorderLayout()); + f.setLocation(100 + (i * 10), 100 + (i * 10)); + MultiGraphicsTest gcTest = new MultiGraphicsTest(gc[i]); + f.add("Center", gcTest); + f.pack(); + f.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + ev.getWindow().setVisible(false); + } + }); + frames[i] = f; + } + return List.of(frames); + } + + public void paint(Graphics g) { + g.drawImage(jim, 0, 0, w, h, this); + } + + public void update(Graphics g) { + paint(g); + } + + public Dimension getMinimumSize() { + return new Dimension(w, h); + } + + public Dimension getPreferredSize() { + return new Dimension(w, h); + } +} diff --git a/test/jdk/java/awt/Canvas/NoEventsLeakTest.java b/test/jdk/java/awt/Canvas/NoEventsLeakTest.java new file mode 100644 index 0000000000000..4768775224a58 --- /dev/null +++ b/test/jdk/java/awt/Canvas/NoEventsLeakTest.java @@ -0,0 +1,96 @@ +/* + * 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 4250354 + * @key headful + * @summary tests that JNI global refs are cleaned up correctly + * @run main/timeout=600 NoEventsLeakTest + */ + +import java.awt.Canvas; +import java.awt.EventQueue; +import java.awt.Frame; + +public class NoEventsLeakTest extends Frame { + static final int nLoopCount = 1000; + + private static void initialize() { + NoEventsLeakTest app = new NoEventsLeakTest(); + boolean result = app.run(); + if (result) { + throw new RuntimeException("Memory leak in Component"); + } + System.out.println("Test Passed"); + } + + public boolean run() { + setSize(10, 10); + addNotify(); + for (int i = 0; i < nLoopCount; i++) { + Canvas panel = new TestCanvas(); + add(panel, 0); + remove(0); + panel = null; + System.gc(); + } + try { + Thread.currentThread().sleep(1000); + } catch (InterruptedException e) { + } + System.gc(); + System.out.println("Checking"); + return ((TestCanvas.created - TestCanvas.finalized) > 800); + } + + public static void main(String[] args) throws Exception { + EventQueue.invokeAndWait(NoEventsLeakTest::initialize); + } +} + +class TestCanvas extends Canvas { + static int finalized = 0; + static int created = 0; + static final int nLoopPrint = 100; + + public TestCanvas() { + if (created % nLoopPrint == 0) { + System.out.println("Created " + getClass() + " " + created); + } + created++; + } + + @SuppressWarnings("removal") + protected void finalize() { + try { + super.finalize(); + if (finalized % nLoopPrint == 0) { + System.out.println("Finalized " + getClass() + " " + finalized); + } + finalized++; + } catch (Throwable t) { + System.out.println("Exception in " + getClass() + ": " + t); + } + } +} diff --git a/test/jdk/java/awt/Canvas/duke_404.gif b/test/jdk/java/awt/Canvas/duke_404.gif new file mode 100644 index 0000000000000..4958e0d0dfa8c Binary files /dev/null and b/test/jdk/java/awt/Canvas/duke_404.gif differ diff --git a/test/jdk/java/awt/CardLayout/RemoveComponentTest/RemoveComponentTest.java b/test/jdk/java/awt/CardLayout/RemoveComponentTest/RemoveComponentTest.java new file mode 100644 index 0000000000000..0a23a98953302 --- /dev/null +++ b/test/jdk/java/awt/CardLayout/RemoveComponentTest/RemoveComponentTest.java @@ -0,0 +1,166 @@ +/* + * 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 4546123 + * @summary CardLayout becomes unusable after deleting an element + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RemoveComponentTest + */ + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +public class RemoveComponentTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + You should see a frame titled "Test Frame For + RemoveComponentTest". Try to select a few different panels from + the second menu. Make sure your last choice is the red panel. + Then click close (in first menu). After that you should be able + to select any panels except red one. + If that is the case, the test passes. Otherwise, the test failed. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(RemoveComponentTest::createUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + TestFrame frame = new TestFrame(); + frame.setSize(200, 200); + return frame; + } +} + +class TestFrame extends Frame implements ActionListener { + public Panel aPanel; + public TestPanel pageRed; + public TestPanel pageGreen; + public TestPanel pageBlue; + public String currentSelection = ""; + + public MenuItem mi; + public CardLayout theCardLayout; + + + public TestFrame() { + super("Test Frame For RemoveComponentTest"); + + setBackground(Color.black); + setLayout(new BorderLayout(5, 5)); + + MenuBar mb = new MenuBar(); + + Menu fileMenu = new Menu("File"); + Menu pageMenu = new Menu("Pages"); + + mi = new MenuItem("Close"); + mi.addActionListener(this); + fileMenu.add(mi); + + mi = new MenuItem("Red"); + mi.addActionListener(this); + pageMenu.add(mi); + + mi = new MenuItem("Green"); + mi.addActionListener(this); + pageMenu.add(mi); + + mi = new MenuItem("Blue"); + mi.addActionListener(this); + pageMenu.add(mi); + + mb.add(fileMenu); + mb.add(pageMenu); + + setMenuBar(mb); + + aPanel = new Panel(); + theCardLayout = new CardLayout(); + + aPanel.setLayout(theCardLayout); + + pageRed = new TestPanel("PageRed", Color.red); + pageGreen = new TestPanel("PageGreen", Color.green); + pageBlue = new TestPanel("PageBlue", Color.blue); + + aPanel.add("PageRed", pageRed); + aPanel.add("PageGreen", pageGreen); + aPanel.add("PageBlue", pageBlue); + + add("Center", aPanel); + setSize(getPreferredSize()); + } + + public Insets getInsets() { + return new Insets(47, 9, 9, 9); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Red")) { + theCardLayout.show(aPanel, "PageRed"); + currentSelection = "PageRed"; + } else if (e.getActionCommand().equals("Green")) { + theCardLayout.show(aPanel, "PageGreen"); + } else if (e.getActionCommand().equals("Blue")) { + theCardLayout.show(aPanel, "PageBlue"); + } else if (e.getActionCommand().equals("Close")) { + PassFailJFrame.log("Closing"); + + if (currentSelection.equals("PageRed")) { + PassFailJFrame.log("Remove page red"); + theCardLayout.removeLayoutComponent(pageRed); + } + } + } +} + +class TestPanel extends JPanel { + private String pageName; + + TestPanel(String pageName, Color color) { + setBackground(color); + add(new JLabel(pageName)); + } +} diff --git a/test/jdk/java/awt/Checkbox/AppearanceIfLargeFont.java b/test/jdk/java/awt/Checkbox/AppearanceIfLargeFont.java new file mode 100644 index 0000000000000..7995b43ed18d5 --- /dev/null +++ b/test/jdk/java/awt/Checkbox/AppearanceIfLargeFont.java @@ -0,0 +1,84 @@ +/* + * 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 + * 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.CheckboxMenuItem; +import java.awt.Frame; +import java.awt.PopupMenu; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6401956 + * @summary The right mark of the CheckboxMenu item is broken + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AppearanceIfLargeFont + */ + +public class AppearanceIfLargeFont extends Frame { + private static final String INSTRUCTIONS = """ + 1) Make sure that font-size is large. + You could change this using 'Appearance' dialog. + 2) Press button 'Press' + You will see a menu item with check-mark. + 3) If check-mark is correctly painted then the test passed. + Otherwise, test failed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("AppearanceIfLargeFont") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(AppearanceIfLargeFont::new) + .build() + .awaitAndCheck(); + } + + public AppearanceIfLargeFont() { + createComponents(); + + setSize(200, 200); + validate(); + } + + void createComponents() { + final Button press = new Button("Press"); + final PopupMenu popup = new PopupMenu(); + press.add(popup); + add(press); + + CheckboxMenuItem item = new CheckboxMenuItem("CheckboxMenuItem", true); + popup.add(item); + + press.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent ae) { + popup.show(press, press.getSize().width, 0); + } + } + ); + } +} diff --git a/test/jdk/java/awt/Checkbox/CheckboxBoxSizeTest.java b/test/jdk/java/awt/Checkbox/CheckboxBoxSizeTest.java new file mode 100644 index 0000000000000..0d500e5daa16d --- /dev/null +++ b/test/jdk/java/awt/Checkbox/CheckboxBoxSizeTest.java @@ -0,0 +1,71 @@ +/* + * 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.Checkbox; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; + +/* + * @test + * @bug 4410522 + * @requires (os.family == "windows") + * @summary The box size of the Checkbox control should be the same as + * in Windows native applications. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckboxBoxSizeTest + */ + +public class CheckboxBoxSizeTest { + private static final String INSTRUCTIONS = """ + This test must be run at UI Scale of 100% AND + 150% or greater. + Compare the size of box to any of native apps on Windows + (Eg. Font Dialog Settings on Word). + They should be the same. + + If the sizes are same Press PASS, else Press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("CheckboxBoxSizeTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(CheckboxBoxSizeTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("CheckboxBoxSizeTest"); + Panel panel = new Panel(new FlowLayout()); + Checkbox checkbox = new Checkbox("Compare the box size"); + panel.add(checkbox); + frame.add(panel); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/Checkbox/CheckboxIndicatorSizeTest.java b/test/jdk/java/awt/Checkbox/CheckboxIndicatorSizeTest.java new file mode 100644 index 0000000000000..3456e7e040d17 --- /dev/null +++ b/test/jdk/java/awt/Checkbox/CheckboxIndicatorSizeTest.java @@ -0,0 +1,168 @@ +/* + * 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. + */ + +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4090493 + * @summary Test for Checkbox indicator size + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckboxIndicatorSizeTest + */ + +public class CheckboxIndicatorSizeTest implements ActionListener { + private static final String INSTRUCTIONS = """ + Indicator size of Checkbox depends + on the platform font used to render the label. + + In the frame you can see a group of checkboxes + and radio buttons. + Verify that all checkboxes and radio buttons have + indicators of the same size and proportional to + the uiScale and/or font-size. + + Use menu to change the font size and the indicators + should scale proportionally. + + If there is a bug, the checkbox/radiobutton with + dingbats label will have a smaller indicator. + + Press PASS if the above conditions are true else Press FAIL. + """; + private static Frame frame; + private static Panel testPanel; + + public static void main(String[] args) throws Exception { + + CheckboxIndicatorSizeTest obj = new CheckboxIndicatorSizeTest(); + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 3) + .columns(60) + .testUI(obj::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private Frame createAndShowUI() { + frame = new Frame("CheckboxIndicatorSizeTest"); + + testPanel = new Panel(new GridLayout(0, 1)); + testPanel.setFont(new Font("Dialog", Font.PLAIN, 12)); + frame.add(testPanel); + + MenuBar menuBar = new MenuBar(); + Menu fontSizeMenu = new Menu("FontSize"); + + MenuItem size10 = new MenuItem("10"); + size10.addActionListener(this); + fontSizeMenu.add(size10); + + MenuItem size12 = new MenuItem("12"); + size12.addActionListener(this); + fontSizeMenu.add(size12); + + MenuItem size14 = new MenuItem("14"); + size14.addActionListener(this); + fontSizeMenu.add(size14); + + MenuItem size18 = new MenuItem("18"); + size18.addActionListener(this); + fontSizeMenu.add(size18); + + MenuItem size24 = new MenuItem("24"); + size24.addActionListener(this); + fontSizeMenu.add(size24); + + MenuItem size36 = new MenuItem("36"); + size36.addActionListener(this); + fontSizeMenu.add(size36); + + menuBar.add(fontSizeMenu); + frame.setMenuBar(menuBar); + + Checkbox cbEnglishOnly + = new Checkbox("Toggle", true); + Checkbox cbDingbatsOnly + = new Checkbox("\u274a\u274b\u274c\u274d", true); + Checkbox cbEnglishDingbats + = new Checkbox("Toggle \u274a\u274d", true); + Checkbox cbDingbatsEnglish + = new Checkbox("\u274a\u274d toggle", true); + + CheckboxGroup radioGroup = new CheckboxGroup(); + Checkbox rbEnglishOnly + = new Checkbox("Radio", true, radioGroup); + Checkbox rbDingbatsOnly + = new Checkbox("\u274a\u274b\u274c\u274d", false, radioGroup); + Checkbox rbEnglishDingbats + = new Checkbox("Radio \u274a\u274d", false, radioGroup); + Checkbox rbDingbatsEnglish + = new Checkbox("\u274a\u274d radio", false, radioGroup); + + Label cbLabel = new Label("Checkboxes"); + cbLabel.setBackground(Color.YELLOW); + testPanel.add(cbLabel); + testPanel.add(cbEnglishOnly); + testPanel.add(cbDingbatsOnly); + testPanel.add(cbEnglishDingbats); + testPanel.add(cbDingbatsEnglish); + + Label rbLabel = new Label("Radio buttons"); + rbLabel.setBackground(Color.YELLOW); + testPanel.add(rbLabel); + testPanel.add(rbEnglishOnly); + testPanel.add(rbDingbatsOnly); + testPanel.add(rbEnglishDingbats); + testPanel.add(rbDingbatsEnglish); + + frame.pack(); + return frame; + } + + @Override + public void actionPerformed(ActionEvent e) { + String sizeStr = e.getActionCommand(); + int size = Integer.parseInt(sizeStr); + Font oldFont = testPanel.getFont(); + Font newFont = new Font(oldFont.getName(), oldFont.getStyle(), size); + testPanel.setFont(newFont); + frame.pack(); + frame.setVisible(true); + } +} diff --git a/test/jdk/java/awt/Checkbox/CheckboxMenuItemEventsTest.java b/test/jdk/java/awt/Checkbox/CheckboxMenuItemEventsTest.java new file mode 100644 index 0000000000000..425c24ba7ef42 --- /dev/null +++ b/test/jdk/java/awt/Checkbox/CheckboxMenuItemEventsTest.java @@ -0,0 +1,120 @@ +/* + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.CheckboxMenuItem; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +/* + * @test + * @bug 4814163 5005195 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Tests events fired by CheckboxMenuItem + * @run main/manual CheckboxMenuItemEventsTest +*/ + +public class CheckboxMenuItemEventsTest extends Frame implements ActionListener { + Button trigger; + PopupMenu popup; + TextArea ta; + + class Listener implements ItemListener, ActionListener { + public void itemStateChanged(ItemEvent e) { + ta.append("CORRECT: ItemEvent fired\n"); + } + + public void actionPerformed(ActionEvent e) { + ta.append("ERROR: ActionEvent fired\n"); + } + } + + Listener listener = new Listener(); + + private static final String INSTRUCTIONS = """ + Press button to invoke popup menu + When you press checkbox menu item + Item state should toggle (on/off). + ItemEvent should be displayed in log below. + And ActionEvent should not be displayed + Press PASS if ItemEvents are generated + and ActionEvents are not, FAIL Otherwise. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("CheckboxMenuItemEventsTest") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(CheckboxMenuItemEventsTest::new) + .build() + .awaitAndCheck(); + } + + public CheckboxMenuItemEventsTest() { + CheckboxMenuItem i1 = new CheckboxMenuItem("CheckBoxMenuItem 1"); + CheckboxMenuItem i2 = new CheckboxMenuItem("CheckBoxMenuItem 2"); + Panel p1 = new Panel(); + Panel p2 = new Panel(); + + setLayout(new BorderLayout()); + ta = new TextArea(); + p2.add(ta); + + trigger = new Button("menu"); + trigger.addActionListener(this); + + popup = new PopupMenu(); + + i1.addItemListener(listener); + i1.addActionListener(listener); + popup.add(i1); + i2.addItemListener(listener); + i2.addActionListener(listener); + popup.add(i2); + + trigger.add(popup); + + p1.add(trigger); + + add(p1, BorderLayout.NORTH); + add(p2, BorderLayout.SOUTH); + + pack(); + validate(); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == (Object) trigger) { + popup.show(trigger, trigger.getSize().width, 0); + } + } +} diff --git a/test/jdk/java/awt/Checkbox/CheckboxNullLabelTest.java b/test/jdk/java/awt/Checkbox/CheckboxNullLabelTest.java new file mode 100644 index 0000000000000..c5cb7c278297a --- /dev/null +++ b/test/jdk/java/awt/Checkbox/CheckboxNullLabelTest.java @@ -0,0 +1,95 @@ +/* + * 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 + * 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.CheckboxGroup; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Panel; + +/* + * @test + * @bug 4383735 + * @summary Checkbox buttons are too small with java 1.3 and 1.4 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckboxNullLabelTest + */ + +public class CheckboxNullLabelTest { + private static final String INSTRUCTIONS = """ + Please look at the frame titled 'CheckboxNullLabelTest'. + Check if all the check boxes in each group + (of 3 check boxes) have the same size. + + If the size of labeled check box is NOT the same as + the size of non-labeled Press FAIL otherwise Press PASS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(35) + .testUI(CheckboxNullLabelTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame f = new Frame("CheckboxNullLabelTest"); + f.setLayout(new BorderLayout()); + f.add(new CheckboxTest(Color.gray, new Font(null, 0, 12)), "North"); + f.add(new CheckboxTest(Color.green, new Font(null, 0, 18)), "South"); + f.add(new CheckboxTest(Color.red, new Font(null, 0, 24)), "East"); + f.add(new CheckboxTest(Color.white, new Font(null, 0, 30)), "West"); + f.add(new CheckboxTest(f.getBackground(), new Font(null, 0, 36)), "Center"); + f.setSize(600, 450); + return f; + } + + private static class CheckboxTest extends Panel { + Checkbox cb1, cb2, cb3; + + CheckboxTest(Color background, Font font) { + setBackground(background); + CheckboxGroup cbg = new CheckboxGroup(); + + cb1 = new Checkbox(null, cbg, true); + cb1.setFont(font); + + cb2 = new Checkbox("", cbg, true); + cb2.setFont(font); + + cb3 = new Checkbox("Label", cbg, false); + cb3.setFont(font); + + add(cb1); + add(cb2); + add(cb3); + } + } +} diff --git a/test/jdk/java/awt/Checkbox/CheckboxPreferredSizeTest.java b/test/jdk/java/awt/Checkbox/CheckboxPreferredSizeTest.java new file mode 100644 index 0000000000000..dd61b52aaedbe --- /dev/null +++ b/test/jdk/java/awt/Checkbox/CheckboxPreferredSizeTest.java @@ -0,0 +1,67 @@ +/* + * 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 + * 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.Checkbox; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; + +/* + * @test + * @bug 4304049 + * @summary tests that Checkbox fits into its preferred size entirely + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckboxPreferredSizeTest + */ + +public class CheckboxPreferredSizeTest { + private static final String INSTRUCTIONS = """ + As the test starts, ensure that the + whole checkbox with all its text is visible. + If the checkbox is entirely visible, press PASS else, + press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(35) + .testUI(CheckboxPreferredSizeTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame frame = new Frame("Checkbox Preferred Size Test"); + frame.setBackground(Color.BLUE); + Checkbox box = new Checkbox("Checkbox_With_Some_Size"); + box.setFont(new Font("Helvetica", Font.PLAIN, 36)); + box.setBackground(Color.RED); + frame.add(box); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/Checkbox/DynamicChangeTest/DynamicChangeTest.java b/test/jdk/java/awt/Checkbox/DynamicChangeTest/DynamicChangeTest.java new file mode 100644 index 0000000000000..b62255efa4589 --- /dev/null +++ b/test/jdk/java/awt/Checkbox/DynamicChangeTest/DynamicChangeTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6225679 + * @summary Tests that checkbox changes into radiobutton dynamically + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DynamicChangeTest + */ + +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Frame; +import java.awt.GridLayout; + +public class DynamicChangeTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test is primarily for Windows platform, but should pass + on other platforms as well. Ensure that 'This is checkbox' is + checkbox, and 'This is radiobutton' is radiobutton. + If it is so, press pass else fail. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(DynamicChangeTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Dynamic Change Checkbox Test"); + f.setSize(200, 200); + + f.setLayout(new GridLayout(2, 1)); + Checkbox ch1 = new Checkbox("This is checkbox", + new CheckboxGroup(), true); + f.add(ch1); + Checkbox ch2 = new Checkbox("This is radiobutton", null, true); + f.add(ch2); + + ch1.setCheckboxGroup(null); + ch2.setCheckboxGroup(new CheckboxGroup()); + return f; + } +} diff --git a/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java b/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java new file mode 100644 index 0000000000000..dde773f19289c --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java @@ -0,0 +1,210 @@ +/* + * 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 + * 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 6251983 6722236 + * @summary MouseDragged events not triggered for Choice when dragging it with left mouse button + * @key headful + * @run main ChoiceDragEventsInside + */ + +import java.awt.Choice; +import java.awt.Color; +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.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.lang.reflect.InvocationTargetException; + +public class ChoiceDragEventsInside extends Frame { + Robot robot; + Choice choice1; + Point pt; + Dimension size; + volatile boolean mouseDragged = false; + volatile boolean mouseDraggedOutside = false; + + public void setupUI() { + setTitle("Choce Drag Events Inside"); + choice1 = new Choice(); + for (int i = 1; i < 50; i++) { + choice1.add("item-0" + i); + } + choice1.setForeground(Color.red); + choice1.setBackground(Color.red); + choice1.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseMoved(MouseEvent me) { + System.out.println(me); + } + + public void mouseDragged(MouseEvent me) { + System.out.println(me); + mouseDragged = true; + if (me.getY() < 0) { + mouseDraggedOutside = true; + } + } + } + ); + add(choice1); + setLayout(new FlowLayout()); + setSize(200, 200); + setLocationRelativeTo(null); + setVisible(true); + validate(); + } + + public void start() { + try { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(50); + robot.delay(100); + EventQueue.invokeAndWait(() -> { + pt = choice1.getLocationOnScreen(); + size = choice1.getSize(); + }); + testDragInsideChoice(InputEvent.BUTTON1_MASK); + testDragInsideChoiceList(InputEvent.BUTTON1_MASK); + testDragOutsideChoice(InputEvent.BUTTON1_MASK); + } catch (Throwable e) { + throw new RuntimeException("Test failed. Exception thrown: " + e); + } + } + + public void testDragInsideChoice(int button) { + robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2); + robot.delay(100); + robot.mousePress(button); + robot.mouseRelease(button); + robot.delay(200); + robot.mousePress(button); + robot.mouseRelease(button); + robot.delay(200); + + //close opened choice + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + + robot.mouseMove(pt.x + size.width / 4, pt.y + size.height / 2); + robot.mousePress(button); + + dragMouse(pt.x + size.width / 4, pt.y + size.height / 2, + pt.x + size.width * 3 / 4, pt.y + size.height / 2); + robot.mouseRelease(button); + robot.delay(200); + if (!mouseDragged) { + throw new RuntimeException("Test failed. Choice should generate MouseDragged events inside Choice itself"); + } else { + System.out.println("Stage 1 passed. Choice generates MouseDragged events inside Choice itself"); + } + mouseDragged = false; + //close opened choice + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + } + + public void testDragInsideChoiceList(int button) { + robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2); + robot.delay(100); + robot.mousePress(button); + robot.mouseRelease(button); + robot.delay(200); + + robot.mouseMove(pt.x + size.width / 2, pt.y + 5 * size.height); + robot.delay(200); + robot.mousePress(button); + + dragMouse(pt.x + size.width / 2, pt.y + 5 * size.height, + pt.x + size.width / 2, pt.y + 8 * size.height); + robot.mouseRelease(button); + robot.delay(200); + if (mouseDragged) { + throw new RuntimeException("Test failed. Choice shouldn't generate MouseDragged events inside Choice's list"); + } else { + System.out.println("Stage 2 passed. Choice doesn't generate MouseDragged events inside Choice's list"); + } + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + mouseDragged = false; + } + + public void testDragOutsideChoice(int button) { + pt = choice1.getLocationOnScreen(); + robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2); + robot.delay(100); + + robot.mousePress(button); + //drag mouse outside of Choice + dragMouse(pt.x + size.width / 2, pt.y + size.height / 2, + pt.x + size.width / 2, pt.y - 3 * size.height); + robot.mouseRelease(button); + robot.delay(200); + if (!mouseDragged || !mouseDraggedOutside) { + throw new RuntimeException("Test failed. Choice should generate MouseDragged events outside Choice"); + } else { + System.out.println("Stage 3 passed. Choice generates MouseDragged events outside Choice"); + } + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + mouseDragged = false; + } + + public void dragMouse(int x0, int y0, int x1, int y1) { + int curX = x0; + int curY = y0; + int dx = x0 < x1 ? 1 : -1; + int dy = y0 < y1 ? 1 : -1; + + while (curX != x1) { + curX += dx; + robot.mouseMove(curX, curY); + } + while (curY != y1) { + curY += dy; + robot.mouseMove(curX, curY); + } + } + + public static void main(final String[] args) throws InterruptedException, + InvocationTargetException { + ChoiceDragEventsInside app = new ChoiceDragEventsInside(); + try { + EventQueue.invokeAndWait(app::setupUI); + app.start(); + } finally { + EventQueue.invokeAndWait(app::dispose); + } + } +} diff --git a/test/jdk/java/awt/Choice/ChoiceInLWTest/ChoiceInLWTest.java b/test/jdk/java/awt/Choice/ChoiceInLWTest/ChoiceInLWTest.java new file mode 100644 index 0000000000000..9d1ad19549189 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceInLWTest/ChoiceInLWTest.java @@ -0,0 +1,96 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4130788 + * @summary Choice components move unexpectedly when in lightweight containers + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ChoiceInLWTest + */ + +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +public class ChoiceInLWTest extends Frame implements Runnable { + private final Choice choices; + static final String INSTRUCTIONS = """ + After test starts wait for two seconds and open a choice. + If choice's popup obscures the label above it press Fail. + Otherwise press Pass. + """; + + public ChoiceInLWTest() { + setLayout(new BorderLayout()); + Container lwCont = new Container(); + lwCont.setLayout(new FlowLayout()); + choices = new Choice(); + choices.add("This is just a token item to get a nice width."); + lwCont.add(choices); + add("Center", lwCont); + Label label = new Label("You should see an unobscured Choice below."); + label.setAlignment(Label.CENTER); + add("North", label); + addChoiceItem(); + addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + super.windowOpened(e); + new Thread(ChoiceInLWTest.this).start(); + } + }); + pack(); + } + + private void addChoiceItem() { + choices.add("Adding an item used to move the Choice!"); + } + + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException ignore) { + } + addChoiceItem(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Choice in LW Container Test") + .testUI(ChoiceInLWTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + + } +} diff --git a/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java b/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java new file mode 100644 index 0000000000000..9603d5c763de4 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java @@ -0,0 +1,123 @@ +/* + * 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 + * 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 4319246 + * @summary Tests that MouseReleased, MouseClicked and MouseDragged are triggered on choice + * @key headful + * @run main ChoiceMouseEventTest + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; + + +public class ChoiceMouseEventTest extends Frame { + static volatile boolean mousePressed = false; + static volatile boolean mouseReleased = false; + static volatile boolean mouseClicked = false; + Choice choice = new Choice(); + static Point location; + static Dimension size; + + public void setupGUI() { + setTitle("Choice Mouse Event Test"); + this.setLayout(new BorderLayout()); + choice.add("item-1"); + choice.add("item-2"); + choice.add("item-3"); + choice.add("item-4"); + add("Center", choice); + choice.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + mouseClicked = true; + } + + @Override + public void mousePressed(MouseEvent e) { + mousePressed = true; + } + + @Override + public void mouseReleased(MouseEvent e) { + mouseReleased = true; + } + }); + setLocationRelativeTo(null); + setSize(400, 200); + setVisible(true); + } + + public Point _location() { + return choice.getLocationOnScreen(); + } + + public Dimension _size() { + return choice.getSize(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + ChoiceMouseEventTest test = new ChoiceMouseEventTest(); + try { + EventQueue.invokeAndWait(test::setupGUI); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.delay(1000); + robot.waitForIdle(); + EventQueue.invokeAndWait(() -> { + location = test._location(); + size = test._size(); + }); + robot.waitForIdle(); + robot.mouseMove(location.x + size.width - 10, location.y + (size.height / 2)); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(2000); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(2000); + robot.waitForIdle(); + if (!mouseClicked || !mousePressed || !mouseReleased) { + throw new RuntimeException(String.format("One of the events not arrived: " + + "mouseClicked = %b, mousePressed = %b, mouseReleased = %b", + mouseClicked, mousePressed, mouseReleased)); + } + } finally { + if (test != null) { + EventQueue.invokeAndWait(test::dispose); + } + } + } +} + diff --git a/test/jdk/java/awt/Choice/ChoiceRemoveTest.java b/test/jdk/java/awt/Choice/ChoiceRemoveTest.java new file mode 100644 index 0000000000000..6de66db936276 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceRemoveTest.java @@ -0,0 +1,111 @@ +/* + * 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 4079027 + * @summary Removing an item dynamically from a Choice object breaks lower items. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ChoiceRemoveTest + */ + +import java.awt.Choice; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Panel; +import java.awt.event.ItemEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +public class ChoiceRemoveTest extends Frame { + Choice selector; + static final String INSTRUCTIONS = """ + After window 'Choice Remove Test' appears wait for three seconds + and then click on the choice. In popup there should be no + 'Choice A' variant. Try selecting each variant with mouse + and verify by the log that the correct variant gets selected. + If after selecting item in the list the correct item gets selected + and correct item name appears in the log press Pass otherwise press Fail. + """; + + public static void main(String[] argv) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Test Instructions") + .testUI(ChoiceRemoveTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } + + public ChoiceRemoveTest() { + super("Choice Remove Test"); + Panel p; + Label prompt; + + addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + super.windowOpened(e); + new Thread(() -> { + try { + Thread.sleep(2000); + } catch (InterruptedException ignore) { + } + removeFirst(); + }).start(); + } + }); + + setLayout(new GridLayout()); + p = new Panel(); + + prompt = new Label("Select different items including the last one"); + p.add(prompt); + + selector = new Choice(); + selector.add("Choice A"); + selector.add("Choice B"); + selector.add("Choice C"); + selector.add("Choice D"); + selector.add("Choice E"); + selector.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + Object selected = e.getItem(); + PassFailJFrame.log(selected.toString()); + } + }); + p.add(selector); + add(p); + pack(); + } + + public void removeFirst() { + selector.remove("Choice A"); + } +} diff --git a/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_DragOut.java b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_DragOut.java new file mode 100644 index 0000000000000..aed1543774575 --- /dev/null +++ b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_DragOut.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6367251 + * @summary 2 items are highlighted when pressing, dragging the mouse inside the choice, XToolkit + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiItemSelected_DragOut + */ + +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; + +public class MultiItemSelected_DragOut extends Frame { + static final String INSTRUCTIONS = """ + 1) Open Choice. + 2) Start drag from first item to second or third one. + 3) Without releasing left mouse button + press and release right mouse button. + 4) Release left mouse button. + 5) Open choice again. + 6) If there is only one selection cursor + in the dropdown list press Pass otherwise press Fail. + """; + + public MultiItemSelected_DragOut() { + Choice choice = new Choice(); + + for (int i = 1; i < 10; i++) { + choice.add("item " + i); + } + add(choice); + choice.addItemListener(ie -> System.out.println(ie)); + + setLayout(new FlowLayout()); + setSize(200, 200); + validate(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("MultiItemSelected Drag Out Test") + .testUI(MultiItemSelected_DragOut::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_KeySelect.java b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_KeySelect.java new file mode 100644 index 0000000000000..9e930f9923b81 --- /dev/null +++ b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_KeySelect.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6367251 + * @summary 2 items are highlighted when dragging inside and press ESC or ENTER + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiItemSelected_KeySelect + */ + +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; + +public class MultiItemSelected_KeySelect extends Frame { + static final String INSTRUCTIONS = """ + 1) Open Choice. + 2) Start drag from first item to another one. + 3) Without releasing the mouse button press ESC key. + 4) Open choice again. + 5) Verify that there is only one + selection cursor in the dropdown list. + 6) Repeat steps 2-5 once again but this time + press ENTER key instead of ESC. + 7) If in both scenarios there is only one selection cursor + press Pass otherwise press Fail. + """; + + public MultiItemSelected_KeySelect() { + Choice choice = new Choice(); + + for (int i = 1; i < 10; i++) { + choice.add("item " + i); + } + add(choice); + choice.addItemListener(ie -> System.out.println(ie)); + setLayout(new FlowLayout()); + setSize(200, 200); + validate(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("MultiItemSelected Key Select Test") + .testUI(MultiItemSelected_KeySelect::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_UpDown.java b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_UpDown.java new file mode 100644 index 0000000000000..5904d98a9081f --- /dev/null +++ b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_UpDown.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6367251 + * @summary 2 items are highlighted when dragging outside and press UP or DOWN + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiItemSelected_UpDown + */ + +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; + +public class MultiItemSelected_UpDown extends Frame { + static final String INSTRUCTIONS = """ + 1) Open Choice. + 2) Start drag from first item to another one. + 3) Without interrupting drag + move mouse cursor outside the choice popup. + 4) Press UP, DOWN key several times to position + selection cursor to a different item. + 5) Release mouse button. + 6) If popup is closed upon mouse button release open Choice again. + 7) Verify that there is only one + selection cursor in the dropdown list. + 8) If true then press Pass, otherwise press Fail. + """; + + public MultiItemSelected_UpDown() { + Choice choice = new Choice(); + + for (int i = 1; i < 20; i++) { + choice.add(" item " + i); + } + add(choice); + choice.addItemListener(ie -> System.out.println(ie)); + setLayout(new FlowLayout()); + setSize(200, 200); + validate(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("MultiItemSelected Up/Down Test") + .testUI(MultiItemSelected_UpDown::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java b/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java new file mode 100644 index 0000000000000..2a56d7281ee44 --- /dev/null +++ b/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6240046 + * @summary REG:Choice's Drop-down does not disappear when clicking somewhere, after popup menu is disposed-XTkt + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PopupMenuOnChoiceArea + */ + + +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.PopupMenu; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; + +public class PopupMenuOnChoiceArea extends Frame { + static final String INSTRUCTIONS = """ + You would see a window named 'Popup menu on choice area' + with Choice in it. Move the mouse pointer to the choice. + Click right mouse button on it. + You should see a popup menu with 'File' in it. + Close this popup menu by pressing Esc. + Click the left mouse button on the Choice. + You should see a Choice drop-down menu. + Move mouse pointer into drop-down menu. + Click right mouse button on any item in it. + If you see a 'File' popup menu press Fail. + If Choice drop-down closes instead press Pass. + """; + + public PopupMenuOnChoiceArea() { + super("Popup menu on choice area"); + this.setLayout(new FlowLayout()); + Choice choice = new Choice(); + choice.add("item-1"); + choice.add("item-2"); + choice.add("item-3"); + choice.add("item-4"); + add("Center", choice); + Menu fileMenu = new Menu("File"); + Menu open = new Menu("Open"); + Menu save = new Menu("save"); + CheckboxMenuItem exit = new CheckboxMenuItem("Exit"); + fileMenu.add(open); + fileMenu.add(save); + fileMenu.add(exit); + final PopupMenu pop = new PopupMenu(); + pop.setLabel("This is a popup menu"); + pop.setName("a menu"); + pop.add(fileMenu); + choice.add(pop); + choice.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent me) { + if (me.isPopupTrigger()) { + pop.show(me.getComponent(), me.getX(), me.getY()); + } + } + + public void mouseReleased(MouseEvent me) { + if (me.isPopupTrigger()) { + pop.show(me.getComponent(), me.getX(), me.getY()); + } + } + }); + setSize(200, 200); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Test Instructions") + .testUI(PopupMenuOnChoiceArea::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Choice/RepaintAfterRemoveLastItemTest/RepaintAfterRemoveLastItemTest.java b/test/jdk/java/awt/Choice/RepaintAfterRemoveLastItemTest/RepaintAfterRemoveLastItemTest.java new file mode 100644 index 0000000000000..20acc66b6bda1 --- /dev/null +++ b/test/jdk/java/awt/Choice/RepaintAfterRemoveLastItemTest/RepaintAfterRemoveLastItemTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6292186 + * @summary Choice is not refreshed properly when the last item gets removed + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RepaintAfterRemoveLastItemTest + */ + +import java.awt.Button; +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.lang.reflect.InvocationTargetException; + +public class RepaintAfterRemoveLastItemTest extends Frame implements ActionListener { + Choice ch = new Choice(); + + static final String INSTRUCTIONS = """ + Press on the 'remove' button after that if the choice does not display + 'only item' press Pass. If 'only item' is still displayed press Fail. + """; + + public RepaintAfterRemoveLastItemTest() { + ch.add("only item"); + add(ch); + + Button b = new Button("remove"); + add(b); + b.addActionListener(this); + setLayout(new FlowLayout()); + setSize(200, 200); + validate(); + } + + public void actionPerformed(ActionEvent ae) { + if (ch.getItemCount() != 0) { + ch.remove(0); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Repaint After Remove Test") + .testUI(RepaintAfterRemoveLastItemTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Choice/ScrollbarFlickers.java b/test/jdk/java/awt/Choice/ScrollbarFlickers.java new file mode 100644 index 0000000000000..c35d4900134fa --- /dev/null +++ b/test/jdk/java/awt/Choice/ScrollbarFlickers.java @@ -0,0 +1,85 @@ +/* + * 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 + * 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 6405707 + * @summary Choice popup & scrollbar gets Flickering when mouse is pressed & drag on the scrollbar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollbarFlickers + */ + +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; + +public class ScrollbarFlickers extends Frame { + static final String INSTRUCTIONS = """ + Open the choice popup. Select any item in it and + drag it with the mouse above or below the choice. + Keep the choice opened. + Continue dragging the mouse outside of the choice + making content of the popup scroll. + If you see that scrollbar flickers press Fail. + Otherwise press Pass. + """; + + public ScrollbarFlickers() { + super("Scrollbar Flickering Test"); + Choice ch = new Choice(); + setLayout(new BorderLayout()); + ch.add("Praveen"); + ch.add("Mohan"); + ch.add("Rakesh"); + ch.add("Menon"); + ch.add("Girish"); + ch.add("Ramachandran"); + ch.add("Elancheran"); + ch.add("Subramanian"); + ch.add("Raju"); + ch.add("Pallath"); + ch.add("Mayank"); + ch.add("Joshi"); + ch.add("Sundar"); + ch.add("Srinivas"); + ch.add("Mandalika"); + ch.add("Suresh"); + ch.add("Chandar"); + add(ch); + setSize(200, 200); + validate(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Test Instructions") + .testUI(ScrollbarFlickers::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Component/PaintGlitchTest/PaintGlitchTest.java b/test/jdk/java/awt/Component/PaintGlitchTest/PaintGlitchTest.java new file mode 100644 index 0000000000000..867d82d326297 --- /dev/null +++ b/test/jdk/java/awt/Component/PaintGlitchTest/PaintGlitchTest.java @@ -0,0 +1,225 @@ +/* + * 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 + * 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 4045781 + * @summary Exposed/damaged canvases don't always update correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PaintGlitchTest + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import javax.swing.JTextArea; +import javax.swing.JTextField; + +public class PaintGlitchTest extends Frame { + static final String INSTRUCTIONS = """ + 1. Click on the 'Painting Glitch Test' window and select from + its menu a content type (text, gradient, fill, + AWT components, Swing components etc.). + 2. Select 'Modal Dialog...' to create a dialog. + 3. Drag the dialog over the content very fast + for 10 seconds or so - make sure you + keep dragging while the content is painting. + 4. Verify that the area exposed by the drag (the damaged regions) + always update properly no white areas or bits of the dialog + should be left after the drag operation is + completed (i.e. after you let go of the mouse). + 5. Repeat for all other content types. + 6. If for any content type the damaged dialog is not properly + repainted press Fail. Otherwise press Pass. + """; + + public PaintGlitchTest() { + super("Painting Glitch Test"); + + TextPanel textPanel = new TextPanel(); + GradientPanel gradientPanel = new GradientPanel(); + ComponentPanel componentPanel = new ComponentPanel(); + SwingPanel swingPanel = new SwingPanel(); + + add(textPanel); + + MenuBar menubar = new MenuBar(); + Menu testMenu = new Menu("Test"); + testMenu.add(makeContentItem("Text Lines", textPanel) ); + testMenu.add(makeContentItem("Gradient Fill", gradientPanel) ); + testMenu.add(makeContentItem("AWT Components", componentPanel) ); + testMenu.add(makeContentItem("Swing Components", swingPanel) ); + testMenu.addSeparator(); + MenuItem dialogItem = new MenuItem("Modal Dialog..."); + dialogItem.addActionListener(ev -> new ObscuringDialog(PaintGlitchTest.this).show()); + testMenu.add(dialogItem); + testMenu.addSeparator(); + menubar.add(testMenu); + + setMenuBar(menubar); + setSize(400,300); + } + + public static void main(String args[]) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Repaint Glitch") + .testUI(PaintGlitchTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } + + public MenuItem makeContentItem(String title, final Component content) { + MenuItem menuItem = new MenuItem(title); + menuItem.addActionListener( + ev -> { + remove(0); + add(content); + validate(); + } + ); + + return menuItem; + } +} + +class GradientPanel extends Canvas { + public void paint(Graphics g) { + long ms = System.currentTimeMillis(); + // just paint something that'll take a while + int x, y; + int width = getSize().width; + int height = getSize().height; + int step = 8; + + for (x = 0; x < width; x += step) { + for (y = 0; y < height; y += step) { + int red = (255 * y) / height; + int green = (255 * x * y) / (width * height); + int blue = (255 * x) / width; + + Color color = new Color(red, green, blue); + g.setColor(color); + g.fillRect(x, y, step, step); + } + } + long time = System.currentTimeMillis() - ms; + PassFailJFrame.log("GradientPanel paint took " + time + " ms"); + } + + public Dimension getPreferredSize() { + return new Dimension(200,1000); + } +} + +class TextPanel extends Canvas { + public void paint(Graphics g) { + long ms = System.currentTimeMillis(); + Font font = new Font("SanSerif", Font.ITALIC, 12); + + g.setFont(font); + // just paint something that'll take a while + int x, y; + int height = getHeight(); + int step = 16; + + for (x = y = 0; y < height; y += step) { + g.drawString(y + " : The quick brown fox jumps over the lazy dog. " + + "The rain in Spain falls mainly on the plain.", x, y); + } + long time = System.currentTimeMillis() - ms; + PassFailJFrame.log("TextPanel paint took " + time + " ms"); + } + + public Dimension getPreferredSize() { + return new Dimension(640,1000); + } +} + +class ComponentPanel extends Panel { + ComponentPanel() { + add(new Label("Label")); + add(new Button("Button")); + add(new Checkbox("Checkbox")); + Choice c = new Choice(); + c.add("choice"); + java.awt.List l = new java.awt.List(); + l.add("list"); + add(new Scrollbar()); + add(new TextField("TextField")); + add(new TextArea("TextArea")); + add(new Panel()); + add(new Canvas()); + } +} + +class SwingPanel extends JPanel { + SwingPanel() { + add(new JLabel("JLabel")); + add(new JButton("JButton")); + add(new JCheckBox("JCheckBox")); + JComboBox c = new JComboBox(); + JList l = new JList(); + add(new JScrollBar()); + add(new JTextField("This is a JTextField with some text in it to make it longer.")); + add(new JTextArea("This is a JTextArea with some text in it to make it longer.")); + } +} + +class ObscuringDialog extends Dialog { + ObscuringDialog(Frame f) { + super(f, "Obscuring Dialog"); + Button ok = new Button("OK, go away"); + ok.addActionListener(ev -> dispose()); + add(ok); + pack(); + } +} diff --git a/test/jdk/java/awt/Component/ProcessEvent/ProcessEvent.java b/test/jdk/java/awt/Component/ProcessEvent/ProcessEvent.java new file mode 100644 index 0000000000000..3dfd5a0403804 --- /dev/null +++ b/test/jdk/java/awt/Component/ProcessEvent/ProcessEvent.java @@ -0,0 +1,455 @@ +/* + * 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 4292099 + * @summary AWT Event delivery to processEvent + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ProcessEvent + */ + +import java.awt.AWTEvent; +import java.awt.AWTEventMulticaster; +import java.awt.Adjustable; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.ItemSelectable; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.TextEvent; +import java.awt.event.TextListener; +import java.lang.reflect.InvocationTargetException; + +public class ProcessEvent extends Frame { + + static final String INSTRUCTIONS = """ + Press each of the four buttons for ActionEvent, AdjustmentEvent, + ItemEvent and TextEvent. If a message for each corresponding event + appears in the log area and says the event listener was + called, then press Pass otherwise press Fail. + """; + ActionBtn af; + AdjustmentBtn adjf; + ItemBtn itf; + TextBtn txtf; + + public ProcessEvent() { + setLayout(new FlowLayout()); + add(af = new ActionBtn()); + af.setBackground(Color.green); + + add(adjf = new AdjustmentBtn()); + adjf.setBackground(Color.green); + + add(itf = new ItemBtn()); + itf.setBackground(Color.green); + + add(txtf = new TextBtn()); + txtf.setBackground(Color.green); + + // These action listeners simply provide feedback of when + // the event is delivered properly. + af.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + PassFailJFrame.log(af.getText() + + ": action listener called: " + + ae.toString()); + } + }); + + adjf.addAdjustmentListener(new AdjustmentListener() { + public void adjustmentValueChanged(AdjustmentEvent ae) { + PassFailJFrame.log(adjf.getText() + + ": adjustment listener called: " + + ae.toString()); + } + }); + + itf.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + PassFailJFrame.log(itf.getText() + + ": item listener called: " + + e.toString()); + } + }); + + txtf.addTextListener(new TextListener() { + public void textValueChanged(TextEvent e) { + PassFailJFrame.log(txtf.getText() + + ": text listener called: " + + e.toString()); + } + }); + + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Process Events Test") + .testUI(ProcessEvent::new) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} + +class ButtonComponent extends Component implements ItemSelectable, Adjustable { + + transient protected TextListener textListener; + transient ActionListener actionListener; + transient AdjustmentListener adjustmentListener; + transient ItemListener itemListener; + String actionCommand = null; + + String text = null; + + public ButtonComponent(String label) { + super(); + text = label; + } + + public String getText() { + return text; + } + + public Dimension getPreferredSize() { + return new Dimension(200, 30); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public String getActionCommand() { + if (actionCommand == null) + return getText(); + else + return actionCommand; + } + + public void setActionCommand(String ac) { + actionCommand = ac; + } + + // ActionEvent listener support + + public synchronized void addActionListener(ActionListener l) { + if (l == null) { + return; + } + enableEvents(AWTEvent.ACTION_EVENT_MASK); + actionListener = AWTEventMulticaster.add(actionListener, l); + } + + public synchronized void removeActionListener(ActionListener l) { + if (l == null) { + return; + } + actionListener = AWTEventMulticaster.remove(actionListener, l); + } + + // AdjustmentEvent listener support + + public synchronized void addAdjustmentListener(AdjustmentListener l) { + if (l == null) { + return; + } + enableEvents(AWTEvent.ADJUSTMENT_EVENT_MASK); + adjustmentListener = AWTEventMulticaster.add(adjustmentListener, l); + } + + public synchronized void removeAdjustmentListener(AdjustmentListener l) { + if (l == null) { + return; + } + adjustmentListener = AWTEventMulticaster.remove(adjustmentListener, l); + } + + // ItemEvent listener support + + public synchronized void addItemListener(ItemListener l) { + if (l == null) { + return; + } + enableEvents(AWTEvent.ITEM_EVENT_MASK); + itemListener = AWTEventMulticaster.add(itemListener, l); + } + + public synchronized void removeItemListener(ItemListener l) { + if (l == null) { + return; + } + itemListener = AWTEventMulticaster.remove(itemListener, l); + } + + // TextEvent listener support + + public synchronized void addTextListener(TextListener l) { + if (l == null) { + return; + } + enableEvents(AWTEvent.TEXT_EVENT_MASK); + textListener = AWTEventMulticaster.add(textListener, l); + } + + public synchronized void removeTextListener(TextListener l) { + if (l == null) { + return; + } + textListener = AWTEventMulticaster.remove(textListener, l); + } + + // Implement the processEvent and processXXXEvent methods to + // handle reception and processing of the event types. + + protected void processEvent(AWTEvent e) { + if (e instanceof ActionEvent) { + processActionEvent((ActionEvent) e); + return; + } + if (e instanceof AdjustmentEvent) { + processAdjustmentEvent((AdjustmentEvent) e); + return; + } + if (e instanceof ItemEvent) { + processItemEvent((ItemEvent) e); + return; + } + if (e instanceof TextEvent) { + processTextEvent((TextEvent) e); + return; + } + super.processEvent(e); + } + + protected void processActionEvent(ActionEvent e) { + if (actionListener != null) { + actionListener.actionPerformed(e); + } + } + + protected void processAdjustmentEvent(AdjustmentEvent e) { + if (adjustmentListener != null) { + adjustmentListener.adjustmentValueChanged(e); + } + } + + protected void processItemEvent(ItemEvent e) { + if (itemListener != null) { + itemListener.itemStateChanged(e); + } + } + + protected void processTextEvent(TextEvent e) { + if (textListener != null) { + textListener.textValueChanged(e); + } + } + + public void paint(Graphics g) { + Dimension dim = getSize(); + g.clearRect(0, 0, dim.width, dim.height); + g.setColor(getForeground()); + g.drawString(text, 2, dim.height - 2); + } + + /** + * Returns the selected items or null if no items are selected. + */ + public Object[] getSelectedObjects() { + return null; + } + + /** + * Gets the orientation of the adjustable object. + */ + public int getOrientation() { + return 0; + } + + /** + * Gets the minimum value of the adjustable object. + */ + public int getMinimum() { + return 0; + } + + /** + * Sets the minimum value of the adjustable object. + * + * @param min the minimum value + */ + public void setMinimum(int min) { + } + + /** + * Gets the maximum value of the adjustable object. + */ + public int getMaximum() { + return 0; + } + + /** + * Sets the maximum value of the adjustable object. + * + * @param max the maximum value + */ + public void setMaximum(int max) { + } + + /** + * Gets the unit value increment for the adjustable object. + */ + public int getUnitIncrement() { + return 0; + } + + /** + * Sets the unit value increment for the adjustable object. + * + * @param u the unit increment + */ + public void setUnitIncrement(int u) { + } + + /** + * Gets the block value increment for the adjustable object. + */ + public int getBlockIncrement() { + return 0; + } + + /** + * Sets the block value increment for the adjustable object. + * + * @param b the block increment + */ + public void setBlockIncrement(int b) { + } + + /** + * Gets the length of the propertional indicator. + */ + public int getVisibleAmount() { + return 0; + } + + /** + * Sets the length of the proportionl indicator of the + * adjustable object. + * + * @param v the length of the indicator + */ + public void setVisibleAmount(int v) { + } + + /** + * Gets the current value of the adjustable object. + */ + public int getValue() { + return 0; + } + + /** + * Sets the current value of the adjustable object. This + * value must be within the range defined by the minimum and + * maximum values for this object. + * + * @param v the current value + */ + public void setValue(int v) { + } + +} + +class ActionBtn extends ButtonComponent { + public ActionBtn() { + super("ActionEvent"); + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + ActionEvent ae = new ActionEvent(e.getSource(), + ActionEvent.ACTION_PERFORMED, + getActionCommand()); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae); + } + }); + } +} + +class AdjustmentBtn extends ButtonComponent { + public AdjustmentBtn() { + super("AdjustmentEvent"); + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + AdjustmentEvent ae = new AdjustmentEvent((Adjustable) e.getSource(), + AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + 1, 1); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae); + } + }); + } +} + +class ItemBtn extends ButtonComponent { + public ItemBtn() { + super("ItemEvent"); + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + ItemEvent ae = new ItemEvent((ItemSelectable) e.getSource(), + ItemEvent.ITEM_STATE_CHANGED, + e.getSource(), 1); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae); + } + }); + } +} + +class TextBtn extends ButtonComponent { + public TextBtn() { + super("TextEvent"); + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + TextEvent ae = new TextEvent(e.getSource(), + TextEvent.TEXT_VALUE_CHANGED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae); + } + }); + } +} diff --git a/test/jdk/java/awt/Component/SetFontOrBackground/SetBgrFnt.java b/test/jdk/java/awt/Component/SetFontOrBackground/SetBgrFnt.java new file mode 100644 index 0000000000000..02707ad578475 --- /dev/null +++ b/test/jdk/java/awt/Component/SetFontOrBackground/SetBgrFnt.java @@ -0,0 +1,123 @@ +/* + * 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 4906548 4921849 + * @summary Checks that setFont and setBackground have immediate effect + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetBgrFnt + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.lang.reflect.InvocationTargetException; + +public class SetBgrFnt extends Frame { + static final String INSTRUCTIONS = """ + 1. Press a button marked 'Switch fonts' + fonts in three components below (a Button, a Checkbox + and a Label) must change immediately. + + 2. Press a button marked 'Switch background' + background of three components and canvas must change. + MacOS is an exception - AWT buttons on macOS so not + change color so on macOS only canvas, checkbox + and a label should change background. + + If this is the behavior that you observe press Pass, + otherwise press Fail. + """; + Label la; + Button bu, bu1, bu2; + Checkbox cb; + Font font1, font2; + Canvas ca; + boolean bToggleFont = true; + boolean bToggleBg = true; + + public SetBgrFnt() { + bu = new Button("Switch fonts"); + bu1 = new Button("Switch background"); + bu2 = new Button("I'm a button"); + cb = new Checkbox("Checkbox I am"); + la = new Label("I am a label"); + ca = new Canvas(); + font1 = new Font("Serif", Font.ITALIC, 22); + font2 = new Font("SansSerif", Font.PLAIN, 10); + la.setFont(font1); + cb.setFont(font1); + bu2.setFont(font1); + bu.addActionListener(ae -> { + if (bToggleFont) { + la.setFont(font2); + cb.setFont(font2); + bu2.setFont(font2); + } else { + la.setFont(font1); + cb.setFont(font1); + bu2.setFont(font1); + } + bToggleFont = !bToggleFont; + }); + + bu1.addActionListener(ae -> { + if (bToggleBg) { + ca.setBackground(Color.YELLOW); + setBackground(Color.YELLOW); + } else { + ca.setBackground(Color.GREEN); + setBackground(Color.GREEN); + } + bToggleBg = !bToggleBg; + }); + + setLayout(new GridLayout(8, 1)); + add(bu); + add(bu1); + add(new Label()); + add("South", la); + add("South", bu2); + add("South", cb); + add("South", ca); + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Set Font and Background Test") + .testUI(SetBgrFnt::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Container/ActivateOnFocusTest.java b/test/jdk/java/awt/Container/ActivateOnFocusTest.java new file mode 100644 index 0000000000000..ee60f985e9894 --- /dev/null +++ b/test/jdk/java/awt/Container/ActivateOnFocusTest.java @@ -0,0 +1,141 @@ +/* + * 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.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +/* + * @test + * @bug 4111098 + * @key headful + * @summary Test for no window activation on control requestFocus() + * @run main/timeout=30 ActivateOnFocusTest + */ + +public class ActivateOnFocusTest { + static MyFrame mf1; + static Point p; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(() -> { + mf1 = new MyFrame(); + mf1.setBounds(100, 100, 300, 300); + mf1.mc1.requestFocusInWindow(); + }); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + p = mf1.mb.getLocationOnScreen(); + }); + + robot.waitForIdle(); + + robot.mouseMove(p.x + 5, p.y + 5); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(250); + + } finally { + if (mf1 != null) { + EventQueue.invokeAndWait(mf1::dispose); + } + } + } +} + +class MyFrame extends Frame implements ActionListener { + public Button mb; + public MyComponent mc1; + public MyComponent mc2; + + public MyFrame() { + super(); + setTitle("ActivateOnFocusTest"); + setLayout(new FlowLayout()); + mb = new Button("Pull"); + mb.addActionListener(this); + add(mb); + mc1 = new MyComponent(Color.red); + add(mc1); + mc2 = new MyComponent(Color.blue); + add(mc2); + addWindowListener(new WindowAdapter() { + @Override + public void windowActivated(WindowEvent e) { + mc1.requestFocusInWindow(); + } + @Override + public void windowDeactivated(WindowEvent e) { + mc2.requestFocusInWindow(); + } + }); + setVisible(true); + } + + public void actionPerformed(ActionEvent e) { + MyFrame mf2 = new MyFrame(); + mf2.setBounds(200, 200, 300, 300); + mf2.setVisible(true); + mf2.mc1.requestFocusInWindow(); + } +} + +class MyComponent extends Component { + public MyComponent(Color c) { + super(); + setBackground(c); + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(getBackground()); + g.fillRect(0, 0, d.width, d.height); + } + + public boolean isFocusTraversable() { + return true; + } + + public Dimension getPreferredSize() { + return new Dimension(50, 50); + } +} diff --git a/test/jdk/java/awt/Container/MouseEnteredTest.java b/test/jdk/java/awt/Container/MouseEnteredTest.java new file mode 100644 index 0000000000000..3bd5d3e4778e2 --- /dev/null +++ b/test/jdk/java/awt/Container/MouseEnteredTest.java @@ -0,0 +1,244 @@ +/* + * 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.Component; +import java.awt.EventQueue; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import javax.swing.ButtonGroup; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.JTextArea; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +/* + * @test + * @bug 4159745 + * @key headful + * @summary Mediumweight popup dragging broken + * @run main MouseEnteredTest + */ + +public class MouseEnteredTest extends JFrame implements ActionListener { + static volatile MouseEnteredTest test; + static volatile Point p; + static volatile Point p2; + + static String strMotif = "Motif"; + static String motifClassName = "com.sun.java.swing.plaf.motif.MotifLookAndFeel"; + static char cMotif = 'o'; + + static String strWindows = "Windows"; + static String windowsClassName = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"; + static char cWindows = 'W'; + + static String strMetal = "Metal"; + static String metalClassName = "javax.swing.plaf.metal.MetalLookAndFeel"; + static char cMetal = 'M'; + + static JMenu m; + static JMenu menu; + + static MouseListener ml = new MouseEnteredTest.MouseEventListener(); + + public MouseEnteredTest() { + setTitle("MouseEnteredTest"); + JPopupMenu.setDefaultLightWeightPopupEnabled(false); + setJMenuBar(getMyMenuBar()); + getContentPane().add("Center", new JTextArea()); + setSize(400, 500); + setLocationRelativeTo(null); + setVisible(true); + } + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(() -> { + test = new MouseEnteredTest(); + }); + + Robot robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + p = m.getLocationOnScreen(); + p2 = menu.getLocationOnScreen(); + }); + robot.waitForIdle(); + robot.delay(250); + robot.mouseMove(p.x + 5, p.y + 10); + robot.waitForIdle(); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (int i = p.x; i < p2.x + 10; i = i + 2) { + robot.mouseMove(i, p2.y + 10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(2000); + + if (m.isPopupMenuVisible()) { + throw new RuntimeException("First menu is showing. Test Failed."); + } + } finally { + if (test != null) { + EventQueue.invokeAndWait(test::dispose); + } + } + } + + public JMenuBar getMyMenuBar() { + JMenuBar menubar; + JMenuItem menuItem; + + menubar = GetLNFMenuBar(); + + menu = menubar.add(new JMenu("Test")); + menu.setName("Test"); + menu.addMouseListener(ml); + menu.setMnemonic('T'); + menuItem = menu.add(new JMenuItem("Menu Item")); + menuItem.addActionListener(this); + menuItem.setMnemonic('M'); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.ALT_MASK)); + + JRadioButtonMenuItem mi = new JRadioButtonMenuItem("Radio Button"); + mi.addActionListener(this); + mi.setMnemonic('R'); + mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK)); + menu.add(mi); + + JCheckBoxMenuItem mi1 = new JCheckBoxMenuItem("Check Box"); + mi1.addActionListener(this); + mi1.setMnemonic('C'); + mi1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.ALT_MASK)); + menu.add(mi1); + return menubar; + } + + public void actionPerformed(ActionEvent e) { + String str = e.getActionCommand(); + if (str.equals(metalClassName) || str.equals(windowsClassName) || str.equals(motifClassName)) { + changeLNF(str); + } else { + System.out.println("ActionEvent: " + str); + } + } + + public void changeLNF(String str) { + System.out.println("Changing LNF to " + str); + try { + UIManager.setLookAndFeel(str); + SwingUtilities.updateComponentTreeUI(this); + pack(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public JMenuBar GetLNFMenuBar() { + JMenuBar mbar = new JMenuBar(); + m = new JMenu("Look and Feel"); + m.setName("Look and Feel"); + m.addMouseListener(ml); + m.setMnemonic('L'); + ButtonGroup bg = new ButtonGroup(); + + JRadioButtonMenuItem mi; + + mi = new JRadioButtonMenuItem(strMetal); + mi.addActionListener(this); + mi.setActionCommand(metalClassName); + mi.setMnemonic(cMetal); + mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK)); + mi.setSelected(true); + bg.add(mi); + m.add(mi); + + mi = new JRadioButtonMenuItem(strWindows); + mi.addActionListener(this); + mi.setActionCommand(windowsClassName); + mi.setMnemonic(cWindows); + mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_2, ActionEvent.ALT_MASK)); + bg.add(mi); + m.add(mi); + + mi = new JRadioButtonMenuItem(strMotif); + mi.addActionListener(this); + mi.setActionCommand(motifClassName); + mi.setMnemonic(cMotif); + mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_3, ActionEvent.ALT_MASK)); + bg.add(mi); + m.add(mi); + + mbar.add(m); + return mbar; + } + + static class MouseEventListener implements MouseListener, MouseMotionListener { + public void mouseClicked(MouseEvent e) { + System.out.println("In mouseClicked for " + e.getComponent().getName()); + } + + public void mousePressed(MouseEvent e) { + Component c = e.getComponent(); + System.out.println("In mousePressed for " + c.getName()); + } + + public void mouseReleased(MouseEvent e) { + System.out.println("In mouseReleased for " + e.getComponent().getName()); + } + + public void mouseEntered(MouseEvent e) { + System.out.println("In mouseEntered for " + e.getComponent().getName()); + System.out.println("MouseEvent:" + e.getComponent()); + } + + public void mouseExited(MouseEvent e) { + System.out.println("In mouseExited for " + e.getComponent().getName()); + } + + public void mouseDragged(MouseEvent e) { + System.out.println("In mouseDragged for " + e.getComponent().getName()); + } + + public void mouseMoved(MouseEvent e) { + System.out.println("In mouseMoved for " + e.getComponent().getName()); + } + } +} diff --git a/test/jdk/java/awt/Container/ValidateTest.java b/test/jdk/java/awt/Container/ValidateTest.java new file mode 100644 index 0000000000000..935766094cf75 --- /dev/null +++ b/test/jdk/java/awt/Container/ValidateTest.java @@ -0,0 +1,78 @@ +/* + * 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.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; + +/* + * @test + * @bug 4136190 + * @requires (os.family == "windows") + * @summary Recursive validation calls would cause major USER resource leakage + * @key headful + * @run main/timeout=30 ValidateTest + */ + +public class ValidateTest { + static Frame frame; + + public static void main(String args[]) throws Exception { + try { + EventQueue.invokeAndWait(() -> { + createGUI(); + }); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createGUI() { + frame = new Frame("Test for 4136190 : JVM and win95 resource leakage issues"); + frame.setLayout(new GridLayout(1, 1)); + MyPanel panel = new MyPanel(); + frame.add(panel); + frame.invalidate(); + frame.validate(); + frame.setSize(500, 400); + frame.setVisible(true); + } + + static class MyPanel extends Panel { + int recurseCounter = 0; + + public void validate() { + recurseCounter++; + if (recurseCounter >= 100) { + return; + } + getParent().validate(); + super.validate(); + } + } +} \ No newline at end of file diff --git a/test/jdk/java/awt/Cursor/BlockedWindowTest/BlockedWindowTest.java b/test/jdk/java/awt/Cursor/BlockedWindowTest/BlockedWindowTest.java new file mode 100644 index 0000000000000..f1313dbb74246 --- /dev/null +++ b/test/jdk/java/awt/Cursor/BlockedWindowTest/BlockedWindowTest.java @@ -0,0 +1,105 @@ +/* + * 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 + * 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 6391547 + * @summary Test if the JTextField's cursor is changed when there is a modal dialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BlockedWindowTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Cursor; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +class MyDialog extends Dialog implements ActionListener { + MyDialog(Frame owner) { + super(owner, "Modal dialog", true); + setBounds(owner.getX() + 150, owner.getY() + 150, 100, 100); + setLayout(new BorderLayout()); + Button b = new Button("Close"); + add(b, "South"); + b.addActionListener(this); + setVisible(true); + } + + public void actionPerformed(ActionEvent ae) { + setVisible(false); + this.dispose(); + } +} + +class MyFrame extends Frame implements ActionListener { + Dialog d; + + public MyFrame() { + super("ManualYesNoTest"); + Button b = new Button("Click here"); + TextField tf = new TextField("A text field"); + b.addActionListener(this); + setLayout(new BorderLayout()); + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + add(b, "South"); + add(tf, "North"); + setSize(300, 300); + } + + public void actionPerformed(ActionEvent ae) { + d = new MyDialog(this); + } +} + +public class BlockedWindowTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Verify that the hand cursor is displayed over the window and + text cursor over TextField. + Click the button in the window to display a modal dialog. + Verify that default cursor is displayed over the window + and over TextField now. + Then close modal dialog and verify that hand cursor is + displayed over window and text cursor over TextField. + If so, press PASS, else press FAIL. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(BlockedWindowTest::createUI) + .build() + .awaitAndCheck(); + } + + public static MyFrame createUI() { + MyFrame f = new MyFrame(); + return f; + } +} diff --git a/test/jdk/java/awt/Cursor/CursorDragTest/ListDragCursor.java b/test/jdk/java/awt/Cursor/CursorDragTest/ListDragCursor.java new file mode 100644 index 0000000000000..32923f1d78b0a --- /dev/null +++ b/test/jdk/java/awt/Cursor/CursorDragTest/ListDragCursor.java @@ -0,0 +1,84 @@ +/* + * 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 + * 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 4313052 + * @summary Test cursor changes after mouse dragging ends + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ListDragCursor + */ + +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.List; +import java.awt.Panel; +import java.awt.TextArea; + +public class ListDragCursor { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Move mouse to the TextArea. + 2. Press the left mouse button. + 3. Drag mouse to the list. + 4. Release the left mouse button. + + If the mouse cursor starts as a Text Line Cursor and changes + to a regular Pointer Cursor, then Hand Cursor when hovering + the list, pass the test. This test fails if the cursor does + not update at all when pointing over the different components. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ListDragCursor::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame frame = new Frame("Cursor change after drag"); + Panel panel = new Panel(); + + List list = new List(2); + list.add("List1"); + list.add("List2"); + list.add("List3"); + list.add("List4"); + list.setCursor(new Cursor(Cursor.HAND_CURSOR)); + + TextArea textArea = new TextArea(3, 5); + textArea.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + + panel.add(textArea); + panel.add(list); + + frame.add(panel); + frame.setBounds(300, 100, 300, 150); + return frame; + } +} diff --git a/test/jdk/java/awt/Cursor/CursorUpdateTest/CursorUpdateTest.java b/test/jdk/java/awt/Cursor/CursorUpdateTest/CursorUpdateTest.java new file mode 100644 index 0000000000000..33e2a3cb166a1 --- /dev/null +++ b/test/jdk/java/awt/Cursor/CursorUpdateTest/CursorUpdateTest.java @@ -0,0 +1,118 @@ +/* + * 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 + * 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 5097531 + * @summary Make sure the cursor updates correctly under certain + * circumstances even when the EDT is busy + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CursorUpdateTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; + +public class CursorUpdateTest { + final static String progress = "|/-\\"; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Check the following: + 1. Cursor must be crosshair when hovering the mouse over the + blue square. + 2. Crosshair cursor must not flicker. + 3. The cursor must be "I-beam" when hovering the mouse over the + button. + 4. Click the button - it will display "Busy" message and a + rotating bar for 5 seconds. The cursor must change to + hourglass. + 5. (Windows only) While the cursor is on the button, press Alt. + The cursor must change to normal shape. Pressing Alt again + must revert it back to I-beam. + 6. Move the mouse out of the button and back onto it. The cursor + must update correctly (hourglass over the button, normal + over the frame) even when the button displays "busy". + Do not try to check (1) or (5) when the button displays + "Busy" - this is not required. + Pass if all the steps are as behave as described. Otherwise, + fail this test. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(CursorUpdateTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame(); + f.setLayout(new FlowLayout()); + Button b = new Button("Button"); + f.add(b); + b.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + Component c = new MyComponent(); + f.add(c); + c.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); + b.addActionListener(e -> { + String oldLabel = b.getLabel(); + Cursor oldCursor = b.getCursor(); + b.setCursor(new Cursor(Cursor.WAIT_CURSOR)); + try { + for (int i = 0; i < 50; i++) { + b.setLabel("Busy " + progress.charAt(i % 4)); + Thread.sleep(100); + } + } catch (InterruptedException ex) { + } + b.setCursor(oldCursor); + b.setLabel(oldLabel); + }); + return f; + } +} + +class MyComponent extends Component { + public void paint(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, getSize().width, getSize().height); + } + + public MyComponent() { + setBackground(Color.blue); + } + + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } +} diff --git a/test/jdk/java/awt/Cursor/CustomCursorTest/CustomCursorTest.java b/test/jdk/java/awt/Cursor/CustomCursorTest/CustomCursorTest.java new file mode 100644 index 0000000000000..32c1fdc150622 --- /dev/null +++ b/test/jdk/java/awt/Cursor/CustomCursorTest/CustomCursorTest.java @@ -0,0 +1,137 @@ +/* + * 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 4174035 4106384 4205805 + * @summary Test for functionality of Custom Cursor + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CustomCursorTest + */ + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Toolkit; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JLabel; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +public class CustomCursorTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test is for switching between a custom cursor and the + system cursor. + + 1. Click on the test window panel to change from the default + system cursor to the custom red square cursor + 2. Verify that the square cursor shows when the panel is clicked + 3. Verify that the square cursor is colored red + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(CustomCursorTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + JFrame f = new JFrame("Custom Cursor Test"); + CustomCursorPanel c = null; + try { + c = new CustomCursorPanel(); + } catch (IOException e) { + e.printStackTrace(); + } + + f.setIconImage(c.getImage()); + f.getContentPane().add(c); + f.setSize(400, 400); + return f; + } +} + +class CustomCursorPanel extends Panel { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + Image image; + Cursor cursor; + boolean flip = false; + + public CustomCursorPanel() throws IOException { + generateRedSquareCursor(); + + image = toolkit.getImage(System.getProperty("test.classes", ".") + + java.io.File.separator + "square_cursor.gif"); + + setBackground(Color.green); + cursor = toolkit.createCustomCursor(image, new Point(0, 0), "custom"); + + JLabel c = (JLabel) add(new JLabel("click to switch between " + + "red square and default cursors")); + c.setBackground(Color.white); + c.setForeground(Color.red); + + addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent me) { + if (!flip) { + setCursor(cursor); + flip = true; + } else { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + flip = false; + } + } + }); + } + + public Image getImage() { + return image; + } + + private static void generateRedSquareCursor() throws IOException { + Path p = Path.of(System.getProperty("test.classes", ".")); + BufferedImage bImg = new BufferedImage(35, 34, TYPE_INT_ARGB); + Graphics2D cg = bImg.createGraphics(); + cg.setColor(Color.RED); + cg.fillRect(0, 0, 35, 34); + ImageIO.write(bImg, "png", new File(p + java.io.File.separator + + "square_cursor.gif")); + } +} diff --git a/test/jdk/java/awt/Cursor/HiddenDialogParentTest/HiddenDialogParentTest.java b/test/jdk/java/awt/Cursor/HiddenDialogParentTest/HiddenDialogParentTest.java new file mode 100644 index 0000000000000..7450f4ec3bb77 --- /dev/null +++ b/test/jdk/java/awt/Cursor/HiddenDialogParentTest/HiddenDialogParentTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5079694 + * @summary Test if JDialog respects setCursor + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HiddenDialogParentTest + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Cursor; + +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.border.LineBorder; + +public class HiddenDialogParentTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + You can see a label area in the center of JDialog. + Verify that the cursor is a hand cursor in this area. + If so, press pass, else press fail. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(HiddenDialogParentTest::createUI) + .build() + .awaitAndCheck(); + } + + public static JDialog createUI() { + JDialog dialog = new JDialog(); + dialog.setTitle("JDialog Cursor Test"); + dialog.setLayout(new BorderLayout()); + JLabel centerLabel = new JLabel("Cursor should be a hand in this " + + "label area"); + centerLabel.setBorder(new LineBorder(Color.BLACK)); + centerLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + dialog.add(centerLabel, BorderLayout.CENTER); + dialog.setSize(300, 200); + + return dialog; + } +} diff --git a/test/jdk/java/awt/Cursor/InvalidImageCustomCursorTest/InvalidImageCustomCursorTest.java b/test/jdk/java/awt/Cursor/InvalidImageCustomCursorTest/InvalidImageCustomCursorTest.java new file mode 100644 index 0000000000000..9877df342ec60 --- /dev/null +++ b/test/jdk/java/awt/Cursor/InvalidImageCustomCursorTest/InvalidImageCustomCursorTest.java @@ -0,0 +1,95 @@ +/* + * 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 4212593 + * @summary The Toolkit.createCustomCursor does not check absence of the + * image of cursor + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual InvalidImageCustomCursorTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Toolkit; + +public class InvalidImageCustomCursorTest { + static Cursor cursor; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Press 'Hide' button to hide (set transparent) cursor for the + green panel. Move the pointer over the green panel - pointer + should disappear. Press 'Default' button to set default cursor + for the green panel. + + If you see any exceptions or cursor is not transparent, + test failed, otherwise it passed. + """; + + Toolkit tk = Toolkit.getDefaultToolkit(); + Image image = tk.getImage("NON_EXISTING_FILE.gif"); + Point p = new Point(0, 0); + + cursor = tk.createCustomCursor(image, p, "Test"); + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(InvalidImageCustomCursorTest::createUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Invalid Cursor Image Test"); + f.setLayout(new BorderLayout()); + f.setSize(200, 200); + + Button def = new Button("Default"); + Button hide = new Button("Hide"); + Panel panel = new Panel(); + + def.addActionListener(e -> panel.setCursor(Cursor.getDefaultCursor())); + hide.addActionListener(e -> panel.setCursor(cursor)); + + panel.setBackground(Color.green); + panel.setSize(100, 100); + f.add("Center", panel); + f.add("North", hide); + f.add("South", def); + + return f; + } +} diff --git a/test/jdk/java/awt/Cursor/JPanelCursorTest/JPanelCursorTest.java b/test/jdk/java/awt/Cursor/JPanelCursorTest/JPanelCursorTest.java new file mode 100644 index 0000000000000..8acd622e59212 --- /dev/null +++ b/test/jdk/java/awt/Cursor/JPanelCursorTest/JPanelCursorTest.java @@ -0,0 +1,122 @@ +/* + * 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 4114073 + * @summary Test for setCursor in a JPanel when added to a JFrame's contentPane + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual JPanelCursorTest + */ + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.border.BevelBorder; + +public class JPanelCursorTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test checks for setCursor in a JPanel when added to a + JFrame's contentPane. + + 1. Verify that the cursor in the left side of the test window + is a default cursor. + 2. Verify that the cursor changes to the crosshair cursor when + pointing over the button. + 3. Verify that the cursor changes to the hand cursor when in + the right side of the splitpane (and not on the button). + + If true, then pass the test. Otherwise, fail this test. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(JPanelCursorTest::createUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createUI() { + JFrame frame = new JFrame(); + + JSplitPane j = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); + ExtJComponent pane = new ExtJComponent(); + + CursorBugPanel panel = new CursorBugPanel(); + + j.setLeftComponent(pane); + j.setRightComponent(panel); + j.setContinuousLayout(true); + + frame.getContentPane().add("Center", j); + pane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + frame.pack(); + return frame; + } +} + +class ExtJComponent extends JComponent { + public ExtJComponent() { + super(); + setOpaque(true); + setBackground(Color.green); + setForeground(Color.red); + setBorder(new BevelBorder(BevelBorder.RAISED)); + } + public void paintComponent(Graphics g) { + g.drawString("Default", 20, 30); + } + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } +} + +class CursorBugPanel extends JPanel { + public CursorBugPanel () { + // BUG: fails to set cursor for panel + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + + // Create a button + JButton button = new JButton("Crosshair"); + + // Sets cursor for button, no problem + button.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); + add(button); + } + + public void paintComponent(Graphics g) { + g.drawString("Hand", 20, 60); + } +} diff --git a/test/jdk/java/awt/Cursor/NullCursorTest/NullCursorTest.java b/test/jdk/java/awt/Cursor/NullCursorTest/NullCursorTest.java new file mode 100644 index 0000000000000..c2398a80eb2b2 --- /dev/null +++ b/test/jdk/java/awt/Cursor/NullCursorTest/NullCursorTest.java @@ -0,0 +1,154 @@ +/* + * 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 4111379 + * @summary Test for setting cursor to null for lightweight components + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NullCursorTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class NullCursorTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Hover over each colored area as described: + Green area shows a CrossCursor. + Red area shows a TextCursor. + Yellow area shows a HandCursor. + 2. Click once in red area, then: + Green area shows a HandCursor. + Red area shows a BusyCursor. + Yellow area shows a HandCursor. + 3. Click again in red area, then: + Green area shows a CrossCursor. + Red area shows a HandCursor. + Yellow area shows a HandCursor. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(NullCursorTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Null Cursor Test Frame"); + f.setSize(200, 200); + final Container p = f; + p.setName("parent"); + p.setLayout(null); + + final Component green = p.add(new Component() { + public void paint(Graphics g) { + Rectangle r = getBounds(); + g.setColor(Color.green); + g.fillRect(0, 0, r.width, r.height); + } + }); + green.setName("green"); + green.setBackground(Color.red); + green.setBounds(50, 50, 75, 75); + green.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); + + Container h = new Container() { + public void paint(Graphics g) { + Rectangle r = getBounds(); + g.setColor(Color.yellow); + g.fillRect(0, 0, r.width, r.height); + super.paint(g); + } + }; + h.setBounds(15, 25, 150, 150); + h.setName("container"); + h.setBackground(Color.yellow); + h.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + final Component red = new Component() { + public void paint(Graphics g) { + Rectangle r = getBounds(); + Color c = getBackground(); + g.setColor(c); + g.fillRect(0, 0, r.width, r.height); + super.paint(g); + } + }; + red.setName("red"); + red.setBackground(Color.red); + red.setBounds(10, 10, 120, 120); + red.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); + + final Button b = (Button)h.add(new Button("Test")); + b.setBounds(10, 10, 40, 20); + h.add(red); + p.add(h); + + b.addActionListener(new ActionListener() { + boolean f = false; + public void actionPerformed(ActionEvent e) { + if (f) { + b.setCursor(null); + } else { + b.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + f = !f; + } + }); + red.addMouseListener(new MouseAdapter() { + boolean f = true; + + public void mouseClicked(MouseEvent e) { + Component c = (Component)e.getSource(); + if (f) { + c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + p.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); + green.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + f = false; + } else { + c.setCursor(null); + p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + green.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); + f = true; + } + } + }); + return f; + } +} diff --git a/test/jdk/java/awt/Cursor/SetCursorTest/SetCursorTest.java b/test/jdk/java/awt/Cursor/SetCursorTest/SetCursorTest.java new file mode 100644 index 0000000000000..87f028eb4f617 --- /dev/null +++ b/test/jdk/java/awt/Cursor/SetCursorTest/SetCursorTest.java @@ -0,0 +1,82 @@ +/* + * 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 4160080 + * @summary Test setCursor() on lightweight components when event is generated + * by a button + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetCursorTest + */ + +import java.awt.Cursor; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; + + +public class SetCursorTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test checks for the behavior of setCursor() when called in + a JFrame's JButton action event. + + 1. Click the "OK" button in the test window. + 2. Verify that the cursor changes to the waiting cursor instead + of the default system cursor. + + If true, then pass the test. Otherwise, fail this test. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(SetCursorTest::createUI) + .build() + .awaitAndCheck(); + } + + public static myFrame createUI() { + myFrame f = new myFrame(); + return f; + } +} + +class myFrame extends JFrame { + public myFrame() { + super("SetCursor With Button Test"); + setSize(200, 200); + + final JPanel p = new JPanel(); + final JButton okButton = new JButton("OK"); + okButton.addActionListener(e -> + setCursor(new Cursor(Cursor.WAIT_CURSOR))); + + p.add(okButton); + getContentPane().add(p); + } +} diff --git a/test/jdk/java/awt/Desktop/ActionSupportTest.java b/test/jdk/java/awt/Desktop/ActionSupportTest.java new file mode 100644 index 0000000000000..e5cdec0e42246 --- /dev/null +++ b/test/jdk/java/awt/Desktop/ActionSupportTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6255196 + * @key headful + * @summary Verifies the supported actions on different platforms. + * @library /test/lib + * @run main/othervm ActionSupportTest + */ + +import java.awt.Desktop; +import java.io.File; +import java.net.URI; +import javax.swing.JMenuBar; +import jtreg.SkippedException; + +import static java.awt.desktop.QuitStrategy.NORMAL_EXIT; + +public class ActionSupportTest { + + public static void main(String[] args) { + final File file = new File("nonExistentFile"); + final URI uri = URI.create("nonExistentSchema:anything"); + final StringBuilder error = new StringBuilder(); + + if (!Desktop.isDesktopSupported()) { + throw new SkippedException("Class java.awt.Desktop is not supported on " + + "current platform. Farther testing will not be performed"); + } + + Desktop desktop = Desktop.getDesktop(); + for (Desktop.Action action : Desktop.Action.values()) { + boolean supported = desktop.isSupported(action); + + try { + switch (action) { + case OPEN: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.open(file); + break; + case EDIT: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.edit(file); + break; + case PRINT: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.print(file); + break; + case MAIL: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.mail(uri); + break; + case BROWSE: + if (supported) { + continue; // prevent native message about strange schema + } + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.browse(uri); + break; + case APP_EVENT_FOREGROUND: + case APP_EVENT_HIDDEN: + case APP_EVENT_REOPENED: + case APP_EVENT_SCREEN_SLEEP: + case APP_EVENT_SYSTEM_SLEEP: + case APP_EVENT_USER_SESSION: + continue; // Has no effect if SystemEventListener's sub-type + // is unsupported on the current platform. + case APP_ABOUT: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setAboutHandler(e -> { + }); + break; + case APP_PREFERENCES: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setPreferencesHandler(e -> { + }); + break; + case APP_OPEN_FILE: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setOpenFileHandler(e -> { + }); + break; + case APP_PRINT_FILE: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setPrintFileHandler(e -> { + }); + break; + case APP_OPEN_URI: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setOpenURIHandler(e -> { + }); + break; + case APP_QUIT_HANDLER: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setQuitHandler((e, response) -> { + }); + break; + case APP_QUIT_STRATEGY: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setQuitStrategy(NORMAL_EXIT); + break; + case APP_SUDDEN_TERMINATION: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.enableSuddenTermination(); + break; + case APP_REQUEST_FOREGROUND: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.requestForeground(true); + break; + case APP_HELP_VIEWER: + if (supported) { + continue; // prevent open separate window + } + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.openHelpViewer(); + break; + case APP_MENU_BAR: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setDefaultMenuBar(new JMenuBar()); + break; + case BROWSE_FILE_DIR: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.browseFileDirectory(file); + break; + case MOVE_TO_TRASH: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.moveToTrash(file); + break; + } + // no exception has been thrown. + if (!supported) { + error.append("Action " + action.name() + " is an " + + "unsupported operation, but no exception has been thrown\n"); + } + } catch (UnsupportedOperationException uoe) { + if (!supported) { + System.out.println("Action " + action.name() + "is not supported."); + } else { + error.append("Action " + action.name() + " is a " + + "supported operation, " + + "but UnsupportedOperationException has been thrown\n"); + } + } catch (Exception e) { + if (supported) { + System.out.println("Action " + action.name() + "supported."); + } else { + error.append("Action " + action.name() + " is an " + + "unsupported operation, but " + + "UnsupportedOperationException has not been thrown\n"); + } + } + } + + if (!error.isEmpty()) { + System.err.println(error); + throw new RuntimeException("One or more tests failed. " + + "Look at the error output for details"); + } + System.out.println("Test completed"); + } +} diff --git a/test/jdk/java/awt/Desktop/BrowseTest.java b/test/jdk/java/awt/Desktop/BrowseTest.java new file mode 100644 index 0000000000000..1bdccace3fc87 --- /dev/null +++ b/test/jdk/java/awt/Desktop/BrowseTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6255196 + * @summary Verifies the function of method browse(java.net.URI uri). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BrowseTest + */ + +import java.awt.Desktop; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import javax.swing.JPanel; + +public class BrowseTest extends JPanel { + static final String INSTRUCTIONS = """ + This test could launch default file manager to open user's home + directory, and default web browser to show the URL of java vendor. + After test execution close the native file manager and web browser + windows if they were launched by test. + Also check output for any unexpected EXCEPTIONS, + if you see any failure messages press Fail otherwise press Pass. + """; + + public BrowseTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Farther testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + + URI dirURI = new File(System.getProperty("user.home")).toURI(); + URI webURI = URI.create(System.getProperty("java.vendor.url", "http://www.java.com")); + boolean failed = false; + try { + PassFailJFrame.log("Try to browse " + dirURI + " ..."); + desktop.browse(dirURI); + PassFailJFrame.log("Succeed.\n"); + } catch (Exception e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + try { + PassFailJFrame.log("Try to browse " + webURI + " ..."); + desktop.browse(webURI); + PassFailJFrame.log("Succeed.\n"); + } catch (Exception e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Browser Test") + .splitUI(BrowseTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Desktop/DesktopSupportTest.java b/test/jdk/java/awt/Desktop/DesktopSupportTest.java new file mode 100644 index 0000000000000..ec8b82ba5ef21 --- /dev/null +++ b/test/jdk/java/awt/Desktop/DesktopSupportTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6255196 + * @key headful + * @summary Verifies if class Desktop is supported on current platform. + * @run main DesktopSupportTest + */ + +import java.awt.Desktop; + +public class DesktopSupportTest { + public static void main(String[] args) { + boolean supported = Desktop.isDesktopSupported(); + try { + Desktop desktop = Desktop.getDesktop(); + if (!supported) { + throw new RuntimeException("UnsupportedOperationException " + + "should be thrown, as this class is not supported " + + "on current platform."); + } + } catch (UnsupportedOperationException uoe) { + if (supported) { + throw new RuntimeException("UnsupportedOperationException " + + "should NOT be thrown, as this class is supported " + + "on current platform."); + } + } catch (Exception e) { + if (!supported) { + throw new RuntimeException("UnsupportedOperationException " + + "should be thrown, as this class is not supported " + + "on current platform. But " + e.getClass().getName() + + " has been thrown instead."); + } + } + } +} diff --git a/test/jdk/java/awt/Desktop/MailTest.java b/test/jdk/java/awt/Desktop/MailTest.java new file mode 100644 index 0000000000000..15e5c0769a0dc --- /dev/null +++ b/test/jdk/java/awt/Desktop/MailTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6255196 + * @summary Verifies the function of methods mail() and mail(java.net.URI uri). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MailTest + */ + +import java.awt.Desktop; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import javax.swing.JPanel; + +public class MailTest extends JPanel { + + static final String INSTRUCTIONS = """ + This test could launch the mail client to compose mail + with and without filling the message fields. + After test execution close the mail composing windows if they + were launched by test. + If you see any unexpected EXCEPTION messages in the output + press Fail. Otherwise press Pass. + """; + + private MailTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Farther testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + if (!desktop.isSupported(Desktop.Action.MAIL)) { + PassFailJFrame.log("Action.MAIL is not supported."); + PassFailJFrame.forcePass(); + } + + /* + * Part 1: launch the mail composing window without a mailto URI. + */ + try { + desktop.mail(); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + /* + * Part 2: launch the mail composing window with a mailto URI. + */ + URI testURI = null; + try { + testURI = new URI("mailto", "foo@bar.com?subject=test subject" + + "&cc=foocc@bar.com&body=test body", null); + desktop.mail(testURI); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } catch (java.net.URISyntaxException use) { + // Should not reach here. + PassFailJFrame.log("EXCEPTION: " + use.getMessage()); + } + + /* + * Part 3: try to launch the mail composing window with a URI with a + * scheme which is not "mailto": + * http://java.net. + * An IOException should be thrown in this case. + */ + try { + testURI = URI.create("http://java.com"); + PassFailJFrame.log("Try to mail: " + testURI); + desktop.mail(testURI); + } catch (IllegalArgumentException e) { + PassFailJFrame.log("Caught expected IllegalArgumentException"); + } catch (IOException ioe) { + PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Mail Test") + .splitUI(MailTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Desktop/OpenTest.java b/test/jdk/java/awt/Desktop/OpenTest.java new file mode 100644 index 0000000000000..1ed29067d50e1 --- /dev/null +++ b/test/jdk/java/awt/Desktop/OpenTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6255196 + * @summary Verifies the function of method open(java.io.File file). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual/othervm OpenTest + */ + +import java.awt.Desktop; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JPanel; + +public class OpenTest extends JPanel { + + static final String INSTRUCTIONS = """ + This test could open the user's home directory and a .txt file. + After test execution, close the native application windows that + are used to open the directory and .txt file if they were launched + by the test. + If you see any unexpected EXCEPTION messages in the output press Fail. + Otherwise press Pass. + """; + + public OpenTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Further testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + + /* + * Part 1: open a directory, which should launch the system default + * file explorer. + * + * On Windows platforms, the default file explorer is explorer; + * on UNIX platforms with Gnome installed and running, the default + * file explorer is Nautilus. + */ + File userHome = new File(System.getProperty("user.home")); + + try { + PassFailJFrame.log("Try to open " + userHome); + desktop.open(userHome); + PassFailJFrame.log("Succeed."); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + /* + * Part 2: open a normal .txt file, which should launch the registered + * application for .txt files. + */ + // Create a temp .txt file for test. + File testFile = null; + try { + PassFailJFrame.log("Creating temporary file"); + testFile = File.createTempFile("JDIC-test", ".txt", + new File(System.getProperty("java.io.tmpdir"))); + testFile.deleteOnExit(); + } catch (java.io.IOException ioe) { + PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); + PassFailJFrame.log("Failed to create test file"); + } + + try { + PassFailJFrame.log("Try to open " + testFile); + desktop.open(testFile); + PassFailJFrame.log("Succeed."); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Mail Test") + .splitUI(OpenTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Dialog/ChoiceModalDialogTest.java b/test/jdk/java/awt/Dialog/ChoiceModalDialogTest.java new file mode 100644 index 0000000000000..97ce5a83a96b7 --- /dev/null +++ b/test/jdk/java/awt/Dialog/ChoiceModalDialogTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6213128 + * @key headful + * @summary Tests that choice is releasing input capture when a modal + * dialog is shown + * @run main ChoiceModalDialogTest + */ + +import java.awt.Choice; +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class ChoiceModalDialogTest { + static Frame f; + static Dialog d; + static volatile boolean keyOK; + static volatile boolean mouseOK; + static TextField tf; + static Choice c; + + public static void main(String[] args) throws Exception { + Robot r; + try { + r = new Robot(); + r.setAutoDelay(100); + EventQueue.invokeAndWait(() -> { + f = new Frame("Frame"); + c = new Choice(); + f.setBounds(100, 300, 300, 200); + f.setLayout(new FlowLayout()); + tf = new TextField(3); + f.add(tf); + + c.add("1"); + c.add("2"); + c.add("3"); + c.add("4"); + f.add(c); + + tf.addFocusListener(new FocusAdapter() { + public void focusLost(FocusEvent ev) { + d = new Dialog(f, "Dialog", true); + d.setBounds(300, 300, 200, 150); + d.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent ev) { + keyOK = true; + } + }); + d.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent ev) { + mouseOK = true; + } + }); + d.setVisible(true); + } + }); + + f.setVisible(true); + f.toFront(); + }); + r.waitForIdle(); + r.delay(1000); + EventQueue.invokeAndWait(() -> { + r.mouseMove(tf.getLocationOnScreen().x + tf.getSize().width / 2, + tf.getLocationOnScreen().y + tf.getSize().height / 2); + }); + r.waitForIdle(); + r.delay(500); + EventQueue.invokeAndWait(() -> { + r.mouseMove(c.getLocationOnScreen().x + c.getSize().width - 4, + c.getLocationOnScreen().y + c.getSize().height / 2); + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + }); + r.waitForIdle(); + r.delay(500); + EventQueue.invokeAndWait(() -> { + r.mouseMove(d.getLocationOnScreen().x + d.getSize().width / 2, + d.getLocationOnScreen().y + d.getSize().height / 2); + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + r.keyPress(KeyEvent.VK_A); + r.keyRelease(KeyEvent.VK_A); + }); + r.waitForIdle(); + r.delay(500); + if (!mouseOK) { + throw new RuntimeException("Test Failed due to Mouse release failure!"); + } + if (!keyOK) { + throw new RuntimeException("Test Failed due to Key release failure!"); + } + System.out.println("Test Passed!"); + } finally { + EventQueue.invokeAndWait(() -> { + if (d != null) { + d.dispose(); + } + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/java/awt/Dialog/ClosingParentTest.java b/test/jdk/java/awt/Dialog/ClosingParentTest.java new file mode 100644 index 0000000000000..9b2750ab95fa2 --- /dev/null +++ b/test/jdk/java/awt/Dialog/ClosingParentTest.java @@ -0,0 +1,100 @@ +/* + * 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 + * 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.Dialog; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowAdapter; + +/* + * @test + * @bug 4336913 + * @summary On Windows, disable parent window controls while modal dialog is being created. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ClosingParentTest + */ + +public class ClosingParentTest { + + static String instructions = """ + When the test starts, you will see a Frame with a Button + titled 'Show modal dialog with delay'. Press this button + and before the modal Dialog is shown, try to close the + Frame using X button or system menu for windowing systems + which don't provide X button in Window decorations. The + delay before Dialog showing is 5 seconds. + If in test output you see message about WINDOW_CLOSING + being dispatched, then test fails. If no such message + is printed, the test passes. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ClosingParentTest") + .instructions(instructions) + .testTimeOut(5) + .rows(10) + .columns(35) + .testUI(ClosingParentTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Frame frame = new Frame("Main Frame"); + Dialog dialog = new Dialog(frame, true); + + Button button = new Button("Show modal dialog with delay"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + try { + Thread.currentThread().sleep(5000); + } catch (InterruptedException x) { + x.printStackTrace(); + } + + dialog.setVisible(true); + } + }); + frame.add(button); + frame.pack(); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + System.out.println("WINDOW_CLOSING dispatched on the frame"); + } + }); + + dialog.setSize(100, 100); + dialog.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + dialog.dispose(); + } + }); + + return frame; + } +} diff --git a/test/jdk/java/awt/Dialog/DefaultIconTest.java b/test/jdk/java/awt/Dialog/DefaultIconTest.java new file mode 100644 index 0000000000000..8d2ec8c406f0a --- /dev/null +++ b/test/jdk/java/awt/Dialog/DefaultIconTest.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +import java.awt.Dialog; +import java.awt.Frame; + +/* + * @test + * @bug 4964237 + * @requires (os.family == "windows") + * @summary Win: Changing theme changes java dialogs title icon + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DefaultIconTest + */ + +public class DefaultIconTest { + static String instructions = """ + This test shows frame and two dialogs + Change windows theme. Resizable dialog should retain default icon + Non-resizable dialog should retain no icon + Press PASS if icons look correct, FAIL otherwise + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ShownModalDialogSerializationTest Instructions") + .instructions(instructions) + .testTimeOut(5) + .rows(10) + .columns(35) + .testUI(DefaultIconTest::createGUIs) + .build() + .awaitAndCheck(); + } + + public static Frame createGUIs() { + Frame f = new Frame("DefaultIconTest"); + f.setSize(200, 100); + Dialog d1 = new Dialog(f, "Resizable Dialog, should show default icon"); + d1.setSize(200, 100); + d1.setVisible(true); + d1.setLocation(0, 150); + Dialog d2 = new Dialog(f, "Non-resizable dialog, should have no icon"); + d2.setSize(200, 100); + d2.setVisible(true); + d2.setResizable(false); + d2.setLocation(0, 300); + return f; + } +} diff --git a/test/jdk/java/awt/Dialog/DialogBackgroundTest.java b/test/jdk/java/awt/Dialog/DialogBackgroundTest.java new file mode 100644 index 0000000000000..793782fc43be8 --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogBackgroundTest.java @@ -0,0 +1,153 @@ +/* + * 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 4255230 4191946 + * @summary Tests to verify Dialog inherits background from its owner + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogBackgroundTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.TextField; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +public class DialogBackgroundTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Perform the following steps: + 1) Select "New Frame" from the "File" menu of the + "TreeCopy Frame #1" frame. + 2) Select "Configure" from the "File" menu in the + *new* frame. + If label text "This is a label:" in the appeared + "Configuration Dialog" dialog has a grey background + test PASSES, otherwise it FAILS + """; + TreeCopy treeCopy = new TreeCopy(++TreeCopy.windowCount, null); + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(treeCopy) + .logArea(8) + .build() + .awaitAndCheck(); + } +} + +class TreeCopy extends Frame implements ActionListener { + TextField tfRoot; + ConfigDialog configDlg; + MenuItem miConfigure = new MenuItem("Configure..."); + MenuItem miNewWindow = new MenuItem("New Frame"); + static int windowCount = 0; + Window parent; + + public TreeCopy(int windowNum, Window myParent) { + super(); + setTitle("TreeCopy Frame #" + windowNum); + MenuBar mb = new MenuBar(); + Menu m = new Menu("File"); + configDlg = new ConfigDialog(this); + parent = myParent; + + m.add(miConfigure); + m.add(miNewWindow); + miConfigure.addActionListener(this); + miNewWindow.addActionListener(this); + mb.add(m); + setMenuBar(mb); + m.addActionListener(this); + + tfRoot = new TextField(); + tfRoot.setEditable(false); + add(tfRoot); + + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent we) { + dispose(); + } + }); + + setSize(200, 100); + setLocationRelativeTo(parent); + } + + public void actionPerformed(ActionEvent ae) { + Object source = ae.getSource(); + + if (source == miConfigure) { + configDlg.setVisible(true); + if (configDlg.getBackground() != configDlg.labelColor) + PassFailJFrame.log("FAIL: Test failed!!!"); + } else if (source == miNewWindow) { + new TreeCopy(++windowCount, this).setVisible(true); + } + } +} + +class ConfigDialog extends Dialog implements ActionListener { + public Button okButton; + public Button cancelButton; + public Label l2; + public Color labelColor; + + public ConfigDialog(Frame parent) { + super(parent, "Configuration Dialog"); + okButton = new Button("OK"); + cancelButton = new Button("Cancel"); + l2 = new Label("This is a label:"); + + setLayout(new FlowLayout()); + add(l2); + add(okButton); + add(cancelButton); + + okButton.addActionListener(this); + cancelButton.addActionListener(this); + + pack(); + labelColor = l2.getBackground(); + } + + public void actionPerformed(ActionEvent ae) { + dispose(); + } +} diff --git a/test/jdk/java/awt/Dialog/DialogDisposeLeak.java b/test/jdk/java/awt/Dialog/DialogDisposeLeak.java new file mode 100644 index 0000000000000..9d581519de365 --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogDisposeLeak.java @@ -0,0 +1,200 @@ +/* + * 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.AWTEvent; +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Label; +import java.awt.Toolkit; +import java.awt.event.MouseEvent; +import java.awt.event.FocusEvent; +import java.awt.event.MouseAdapter; + +/* + * @test + * @bug 4193022 + * @summary Test for bug(s): 4193022, disposing dialog leaks memory + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogDisposeLeak + */ + +public class DialogDisposeLeak { + private static final String INSTRUCTIONS = """ + Click on the Dialog... button in the frame that appears. + Now dismiss the dialog by clicking on the label in the dialog. + + Repeat this around 10 times. At some point the label in the frame should change + to indicated that the dialog has been garbage collected and the test passed. + """; + + public static void main(String args[]) throws Exception { + Frame frame = new DisposeFrame(); + PassFailJFrame.builder() + .title("DialogDisposeLeak") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(frame) + .build() + .awaitAndCheck(); + } +} + +class DisposeFrame extends Frame { + Label label = new Label("Test not passed yet"); + + DisposeFrame() { + super("DisposeLeak test"); + setLayout(new FlowLayout()); + Button btn = new Button("Dialog..."); + add(btn); + btn.addActionListener(ev -> { + Dialog dlg = new DisposeDialog(DisposeFrame.this); + dlg.setVisible(true); + } + ); + add(label); + pack(); + } + + public void testOK() { + label.setText("Test has passed. Dialog finalized."); + } +} + +class DisposeDialog extends Dialog { + DisposeDialog(Frame frame) { + super(frame, "DisposeDialog", true); + setLocation(frame.getX(), frame.getY()); + + setLayout(new FlowLayout()); + LightweightComp lw = new LightweightComp("Click here to dispose"); + lw.addMouseListener( + new MouseAdapter() { + public void mouseEntered(MouseEvent ev) { + System.out.println("Entered lw"); + } + + public void mouseExited(MouseEvent ev) { + System.out.println("Exited lw"); + } + + public void mouseReleased(MouseEvent ev) { + System.out.println("Released lw"); + DisposeDialog.this.dispose(); + // try to force GC and finalization + for (int n = 0; n < 100; n++) { + byte[] bytes = new byte[1024 * 1024 * 8]; + System.gc(); + } + } + } + ); + add(lw); + pack(); + } + + public void finalize() { + ((DisposeFrame) getParent()).testOK(); + } +} + +// simple lightweight component, focus traversable, highlights upon focus +class LightweightComp extends Component { + FontMetrics fm; + String label; + private static final int FOCUS_GONE = 0; + private static final int FOCUS_TEMP = 1; + private static final int FOCUS_HAVE = 2; + int focusLevel = FOCUS_GONE; + public static int nameCounter = 0; + + public LightweightComp(String lwLabel) { + label = lwLabel; + enableEvents(AWTEvent.FOCUS_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK); + setName("lw" + nameCounter++); + } + + public Dimension getPreferredSize() { + if (fm == null) fm = Toolkit.getDefaultToolkit().getFontMetrics(getFont()); + return new Dimension(fm.stringWidth(label) + 2, fm.getHeight() + 2); + } + + public void paint(Graphics g) { + Dimension s = getSize(); + + // erase the background + g.setColor(getBackground()); + g.fillRect(0, 0, s.width, s.height); + + g.setColor(getForeground()); + + // draw the string + g.drawString(label, 2, fm.getHeight()); + + // draw a focus rectangle + if (focusLevel > FOCUS_GONE) { + if (focusLevel == FOCUS_TEMP) { + g.setColor(Color.gray); + } else { + g.setColor(Color.blue); + } + } else { + g.setColor(Color.black); + } + g.drawRect(1, 1, s.width - 2, s.height - 2); + } + + public boolean isFocusTraversable() { + return true; + } + + protected void processFocusEvent(FocusEvent e) { + super.processFocusEvent(e); + if (e.getID() == FocusEvent.FOCUS_GAINED) { + focusLevel = FOCUS_HAVE; + } else { + if (e.isTemporary()) { + focusLevel = FOCUS_TEMP; + } else { + focusLevel = FOCUS_GONE; + } + } + repaint(); + } + + protected void processMouseEvent(MouseEvent e) { + if (e.getID() == MouseEvent.MOUSE_PRESSED) { + requestFocus(); + } + super.processMouseEvent(e); + } +} + diff --git a/test/jdk/java/awt/Dialog/DialogIconTest/DialogIconTest.java b/test/jdk/java/awt/Dialog/DialogIconTest/DialogIconTest.java new file mode 100644 index 0000000000000..06debe28fc551 --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogIconTest/DialogIconTest.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Label; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.awt.Window; +import java.util.List; + +/* + * @test + * @bug 4779641 + * @summary Test to verify that Non-resizable dialogs should not show icons + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogIconTest + */ + +public class DialogIconTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. This is a Windows-only test of Dialog icons + 2. You can see a frame with a swing icon and two dialogs that it + owns. The resizable dialog should have the same icon as the + frame. The non-resizable dialog should have no icon at all + 3. Press PASS if this is true, press FAIL otherwise + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static List initialize() { + Frame f = new Frame("Parent frame"); + f.setBounds(50, 50, 200, 200); + + Dialog dr = new Dialog(f, "Resizable Dialog"); + dr.setLocation(100, 100); + dr.add(new Label("Should inherit icon from parent")); + dr.pack(); + + Dialog dn = new Dialog(f, "NON Resizable Dialog"); + dn.setLocation(150, 150); + dn.add(new Label("Should have no icon")); + dn.pack(); + dn.setResizable(false); + + String fileName = System.getProperty("test.src") + + System.getProperty("file.separator") + "swing.small.gif"; + + Image icon = Toolkit.getDefaultToolkit().createImage(fileName); + MediaTracker tracker = new MediaTracker(f); + tracker.addImage(icon, 0); + try { + tracker.waitForAll(); + } catch (InterruptedException ie) { + throw new RuntimeException("MediaTracker addImage Interrupted!"); + } + f.setIconImage(icon); + return List.of(f, dn, dr); + } +} diff --git a/test/jdk/java/awt/Dialog/DialogIconTest/swing.small.gif b/test/jdk/java/awt/Dialog/DialogIconTest/swing.small.gif new file mode 100644 index 0000000000000..14a489ff4e7df Binary files /dev/null and b/test/jdk/java/awt/Dialog/DialogIconTest/swing.small.gif differ diff --git a/test/jdk/java/awt/Dialog/DialogInitialResizability.java b/test/jdk/java/awt/Dialog/DialogInitialResizability.java new file mode 100644 index 0000000000000..7ecde39c4add1 --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogInitialResizability.java @@ -0,0 +1,96 @@ +/* + * 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. + */ + +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; + +/* + * @test + * @bug 4912551 + * @summary Checks that with resizable set to false before show() + * dialog can not be resized. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogInitialResizability + */ + +public class DialogInitialResizability { + static String instructions = """ + When this test is run a dialog will display (setResizable Test). + This dialog should not be resizable. + + Additionally ensure that there are NO componentResized events in the log section. + If the above conditions are true, then Press PASS else FAIL. + """; + + private static final Dimension INITIAL_SIZE = new Dimension(400, 150); + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("DialogInitialResizability") + .instructions(instructions) + .testTimeOut(5) + .rows((int) instructions.lines().count() + 2) + .columns(40) + .testUI(DialogInitialResizability::createGUI) + .logArea() + .build() + .awaitAndCheck(); + } + + public static MyDialog createGUI() { + Frame f = new Frame("invisible dialog owner"); + + MyDialog ld = new MyDialog(f); + ld.setBounds(100, 100, INITIAL_SIZE.width, INITIAL_SIZE.height); + ld.setResizable(false); + + PassFailJFrame.log("Dialog isResizable is set to: " + ld.isResizable()); + PassFailJFrame.log("Dialog Initial Size " + ld.getSize()); + return ld; + } + + private static class MyDialog extends Dialog implements ComponentListener { + public MyDialog(Frame f) { + super(f, "setResizable test", false); + this.addComponentListener(this); + } + + public void componentResized(ComponentEvent e) { + if (!e.getComponent().getSize().equals(INITIAL_SIZE)) { + PassFailJFrame.log("Component Resized. Test Failed!!"); + } + } + + public void componentMoved(ComponentEvent e) { + } + + public void componentShown(ComponentEvent e) { + } + + public void componentHidden(ComponentEvent e) { + } + } +} diff --git a/test/jdk/java/awt/Dialog/DialogModalityTest.java b/test/jdk/java/awt/Dialog/DialogModalityTest.java new file mode 100644 index 0000000000000..d8ac9e4620b42 --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogModalityTest.java @@ -0,0 +1,114 @@ +/* + * 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.BorderLayout; +import java.awt.Button; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Event; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Window; +import java.util.List; + +/* + * @test + * @bug 4058370 + * @summary Test to verify Modality of Dialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogModalityTest + */ + +public class DialogModalityTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. When the test is running, there will be a Frame, a Modal Dialog + and a Window that is Modal Dialog's parent. + 2. Verify that it is impossible to bring up the menu in Frame before + closing the Modal Dialog. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static List initialize() { + Frame f = new Frame("Parent Frame"); + DialogTest dlg = new DialogTest(f, "Modal Dialog"); + f.add(new Button("push me")); + f.setSize(200, 200); + f.setLocation(210, 1); + dlg.setBounds(210, 203, 200, 200); + return List.of(f, dlg); + } +} + +class DialogTest extends Dialog { + Button closeButton; + Frame parent; + + public DialogTest(Frame parent, String title) { + this(parent, title, true); + } + + public DialogTest(Frame parent, String title, boolean modal) { + super(parent, title, modal); + this.parent = parent; + setLayout(new BorderLayout()); + Panel buttonPanel = new Panel(); + closeButton = new Button("Close"); + buttonPanel.add(closeButton); + add("Center", buttonPanel); + pack(); + } + + public boolean action(Event e, Object arg) { + if (e.target == closeButton) { + Dialog dialog = null; + Component c = (Component) e.target; + + while (c != null && !(c instanceof Dialog)) { + c = c.getParent(); + } + + if (c != null) { + dialog = (Dialog) c; + } + + if (dialog == null) { + return false; + } + + dialog.setVisible(false); + dialog.dispose(); + return true; + } + return false; + } +} diff --git a/test/jdk/java/awt/Dialog/DialogResizeTest.java b/test/jdk/java/awt/Dialog/DialogResizeTest.java new file mode 100644 index 0000000000000..e57a529806872 --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogResizeTest.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +import java.awt.Checkbox; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.lang.Exception; +import java.lang.String; +import java.lang.System; + +/* + * @test + * @bug 4115213 + * @summary Test to verify Checks that with resizable set to false, + * dialog can not be resized + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogResizeTest + */ + +public class DialogResizeTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. When this test is run a dialog will display (setResizable Test) + Click on the checkbox to change the dialog resizable state + 2. For both dialog resizable states (resizable, non-resizable) try to + change the size of the dialog. When isResizable is true the dialog + is resizable. When isResizable is false the dialog is non-resizable + 3. If this is the behavior that you observe, the test has passed, Press + the Pass button. Otherwise the test has failed, Press the Fail button + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(initialize()) + .logArea(8) + .build() + .awaitAndCheck(); + } + + public static Dialog initialize() { + Frame f = new Frame("Owner Frame"); + MyDialog ld = new MyDialog(f); + ld.setBounds(100, 100, 400, 150); + ld.setResizable(false); + System.out.println("isResizable is set to: " + ld.isResizable()); + return ld; + } +} + +class MyDialog extends Dialog implements ItemListener { + String sText = "Tests java.awt.Dialog.setResizable method"; + TextArea ta = new TextArea(sText, 2, 40, TextArea.SCROLLBARS_NONE); + + public MyDialog(Frame f) { + + super(f, "setResizable test", false); + + Panel cbPanel = new Panel(); + cbPanel.setLayout(new FlowLayout()); + + Panel taPanel = new Panel(); + taPanel.setLayout(new FlowLayout()); + taPanel.add(ta); + + Checkbox cb = new Checkbox("Check this box to change the dialog's " + + "resizable state", null, isResizable()); + cb.setState(false); + cb.addItemListener(this); + cbPanel.add(cb); + + add("North", taPanel); + add("South", cbPanel); + pack(); + } + + public void itemStateChanged(ItemEvent evt) { + setResizable(evt.getStateChange() == ItemEvent.SELECTED); + + boolean bResizeState = isResizable(); + PassFailJFrame.log("isResizable is set to: " + bResizeState); + + if (isResizable()) { + ta.setText("dialog is resizable (isResizable = " + bResizeState + ")"); + } else { + ta.setText("dialog is NOT resizable (isResizable = " + bResizeState + ")"); + } + } +} diff --git a/test/jdk/java/awt/Dialog/DialogResizeTest2.java b/test/jdk/java/awt/Dialog/DialogResizeTest2.java new file mode 100644 index 0000000000000..3124719637a1d --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogResizeTest2.java @@ -0,0 +1,105 @@ +/* + * 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.Button; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.GridLayout; + +/* + * @test + * @bug 4172302 + * @summary Test to make sure non-resizable Dialogs can be resized with the + * setSize() method. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogResizeTest2 + */ + +public class DialogResizeTest2 { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This tests the programmatic resizability of non-resizable Dialogs + Even when a Dialog is set to be non-resizable, it should be + programmatically resizable using the setSize() method. + + 1. Initially the Dialog will be resizable. Try using the \\"Smaller\\" + and \\"Larger\\" buttons to verify that the Dialog resizes correctly + 2. Then, click the \\"Toggle\\" button to make the Dialog non-resizable + 3. Again, verify that clicking the \\"Larger\\" and \\"Smaller\\" buttons + causes the Dialog to get larger and smaller. If the Dialog does + not change size, or does not re-layout correctly, the test FAILS + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(8) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("Parent Frame"); + frame.add(new Button("Button")); + frame.setSize(100, 100); + new dlg(frame).setVisible(true); + return frame; + } + + static class dlg extends Dialog { + public dlg(Frame f_) { + super(f_, "Dialog", false); + setSize(200, 200); + Button bLarger = new Button("Larger"); + bLarger.addActionListener(e -> setSize(400, 400)); + Button bSmaller = new Button("Smaller"); + bSmaller.addActionListener(e -> setSize(200, 100)); + Button bCheck = new Button("Resizable?"); + bCheck.addActionListener(e -> { + if (isResizable()) { + PassFailJFrame.log("Dialog is resizable"); + } else { + PassFailJFrame.log("Dialog is not resizable"); + } + }); + Button bToggle = new Button("Toggle"); + bToggle.addActionListener(e -> { + if (isResizable()) { + setResizable(false); + PassFailJFrame.log("Dialog is now not resizable"); + } else { + setResizable(true); + PassFailJFrame.log("Dialog is now resizable"); + } + }); + setLayout(new GridLayout(1, 4)); + add(bSmaller); + add(bLarger); + add(bCheck); + add(bToggle); + } + } +} diff --git a/test/jdk/java/awt/Dialog/DialogSystemMenu/DialogSystemMenu.java b/test/jdk/java/awt/Dialog/DialogSystemMenu/DialogSystemMenu.java new file mode 100644 index 0000000000000..3f1639e90a41e --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogSystemMenu/DialogSystemMenu.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.event.WindowListener; +import java.util.List; + +/* + * @test + * @bug 4058953 4094035 + * @summary Test to verify system menu of a dialog on win32 + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogSystemMenu + */ + +public class DialogSystemMenu { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Check the following on the first dialog window: + Right-clicking on the title bar + should bring up a system menu. + The system menu should not allow any + of the Maximize, Minimize and + Restore actions + + 2. The second dialog should be non-resizable + and have no application icon. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static List initialize() { + Frame frame = new java.awt.Frame("Parent Frame"); + String txt = """ + This is a resizable dialog + Right-clicking on the title bar + should bring up a system menu + The system menu should not + allow any + of the Maximize, Minimize and + Restore actions + """; + String txt_non = """ + This is a non-resizable dialog + It should be really non-resizable + and have no application icon + """; + TestApp resizable = new TestApp(frame, "Test for 4058953", txt, true); + resizable.setLocation(0, 0); + + TestApp non_resizable = new TestApp(frame, "Test for 4094035", txt_non, false); + non_resizable.setLocation(320, 0); + return List.of(resizable, non_resizable); + } +} + + +class TestApp extends Dialog implements WindowListener { + public TestApp(java.awt.Frame parent, String title, String txt, boolean resize) { + super(parent, title, false); + + java.awt.TextArea ta = new java.awt.TextArea(txt); + ta.setEditable(false); + this.add(ta, "Center"); + this.addWindowListener(this); + this.setSize(300, 200); + this.setResizable(resize); + } + + + public void windowOpened(java.awt.event.WindowEvent myEvent) { + } + + public void windowClosed(java.awt.event.WindowEvent myEvent) { + } + + public void windowIconified(java.awt.event.WindowEvent myEvent) { + } + + public void windowDeiconified(java.awt.event.WindowEvent myEvent) { + } + + public void windowActivated(java.awt.event.WindowEvent myEvent) { + } + + public void windowDeactivated(java.awt.event.WindowEvent myEvent) { + } + + public void windowClosing(java.awt.event.WindowEvent myEvent) { + this.dispose(); + } +} diff --git a/test/jdk/java/awt/Dialog/DialogSystemMenu/icon24x24.gif b/test/jdk/java/awt/Dialog/DialogSystemMenu/icon24x24.gif new file mode 100644 index 0000000000000..dfb9987339745 Binary files /dev/null and b/test/jdk/java/awt/Dialog/DialogSystemMenu/icon24x24.gif differ diff --git a/test/jdk/java/awt/Dialog/DialogSystemMenu/iconone.gif b/test/jdk/java/awt/Dialog/DialogSystemMenu/iconone.gif new file mode 100644 index 0000000000000..698ba29d839e0 Binary files /dev/null and b/test/jdk/java/awt/Dialog/DialogSystemMenu/iconone.gif differ diff --git a/test/jdk/java/awt/Dialog/DialogSystemMenu/icontwo.gif b/test/jdk/java/awt/Dialog/DialogSystemMenu/icontwo.gif new file mode 100644 index 0000000000000..7f344ed1df07e Binary files /dev/null and b/test/jdk/java/awt/Dialog/DialogSystemMenu/icontwo.gif differ diff --git a/test/jdk/java/awt/Dialog/EnabledResetTest.java b/test/jdk/java/awt/Dialog/EnabledResetTest.java new file mode 100644 index 0000000000000..d71c9b1801b22 --- /dev/null +++ b/test/jdk/java/awt/Dialog/EnabledResetTest.java @@ -0,0 +1,145 @@ +/* + * 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 4232374 + * @summary Tests that dismissing a modal dialog does not enable + * disabled components + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual EnabledResetTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class EnabledResetTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Press "Create Child" twice to create three windows + Verify that the parent windows are disabled + 2. Press "Create Modal Dialog" + Verify that the parent windows are disabled + 3. Press "enable" + Verify that no windows accept mouse events + 4. Press "ok" + Verify that the first window is still disabled + If all the verifications are done, then test is + PASSED, else test fails. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(new ChildDialog(1, null)) + .build() + .awaitAndCheck(); + } +} + +class ChildDialog extends Frame implements ActionListener { + Window parent; + int id; + Button b, c, d; + + public ChildDialog(int frameNumber, Window myParent) { + super(); + id = frameNumber; + parent = myParent; + + setTitle("Frame Number " + id); + + b = new Button("Dismiss me"); + c = new Button("Create Child"); + d = new Button("Create Modal Dialog"); + + setLayout(new BorderLayout()); + add("North", c); + add("Center", d); + add("South", b); + pack(); + + b.addActionListener(this); + c.addActionListener(this); + d.addActionListener(this); + } + + public void setVisible(boolean b) { + if (parent != null) { + if (b) { + parent.setEnabled(false); + } else { + parent.setEnabled(true); + parent.requestFocus(); + } + } + + super.setVisible(b); + } + + public void dispose() { + if (parent != null) { + parent.setEnabled(true); + parent.requestFocus(); + } + super.dispose(); + } + + + public void actionPerformed(ActionEvent evt) { + if (evt.getSource() == c) { + (new ChildDialog(id + 1, this)).setVisible(true); + } else if (evt.getSource() == d) { + Dialog D = new Dialog(this, "Modal Dialog "); + D.setLayout(new FlowLayout()); + Button b = new Button("ok"); + Button e = new Button("enable"); + D.add(b); + D.add(e); + D.setModal(true); + D.pack(); + b.addActionListener(this); + e.addActionListener(this); + D.setVisible(true); + } else if (evt.getSource() == b) { + dispose(); + } else if (evt.getSource() instanceof Button) { + if ("ok".equals(evt.getActionCommand())) { + Button target = (Button) evt.getSource(); + Window w = (Window) target.getParent(); + w.dispose(); + } + if ("enable".equals(evt.getActionCommand())) { + parent.setEnabled(true); + } + } + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogEmptyTitleTest.java b/test/jdk/java/awt/Dialog/FileDialogEmptyTitleTest.java new file mode 100644 index 0000000000000..d288a7c18f65f --- /dev/null +++ b/test/jdk/java/awt/Dialog/FileDialogEmptyTitleTest.java @@ -0,0 +1,59 @@ +/* + * 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.FileDialog; +import java.awt.Frame; + +/* + * @test + * @bug 4177831 + * @summary solaris: default FileDialog title is not empty + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogEmptyTitleTest + */ + +public class FileDialogEmptyTitleTest { + static String instructions = """ + Test passes if title of file dialog is empty, + otherwise test failed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FileDialogEmptyTitleTest") + .instructions(instructions) + .testTimeOut(5) + .rows(10) + .columns(35) + .testUI(FileDialogEmptyTitleTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static FileDialog createGUI() { + Frame frame = new Frame("invisible dialog owner"); + FileDialog fileDialog = new FileDialog(frame); + return fileDialog; + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogFilterTest.java b/test/jdk/java/awt/Dialog/FileDialogFilterTest.java new file mode 100644 index 0000000000000..e30d8ea58a2d6 --- /dev/null +++ b/test/jdk/java/awt/Dialog/FileDialogFilterTest.java @@ -0,0 +1,68 @@ +/* + * 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 + * 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.FileDialog; +import java.awt.Frame; +import java.io.File; +import java.io.FilenameFilter; + +/* + * @test + * @bug 4364256 + * @summary Test to File Dialog filter + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogFilterTest + */ + +public class FileDialogFilterTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Run the test, make sure a file dialog + comes up with no crash. If the file dialog + comes up successfully then press PASS, else FAIL. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static FileDialog initialize() { + FileDialog fDlg = new FileDialog(new Frame()); + fDlg.addNotify(); + fDlg.setFilenameFilter(new MyFilter()); + return fDlg; + } +} + +class MyFilter implements FilenameFilter { + public boolean accept(File dir, String name) { + return true; + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogGetFileTest.java b/test/jdk/java/awt/Dialog/FileDialogGetFileTest.java new file mode 100644 index 0000000000000..d4670cceb601e --- /dev/null +++ b/test/jdk/java/awt/Dialog/FileDialogGetFileTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4414105 + * @summary Tests that FileDialog returns null when cancelled + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogGetFileTest + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +public class FileDialogGetFileTest { + static FileDialog fd; + static Frame frame; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Open FileDialog from "Show File Dialog" button. + 2. Click cancel button without selecting any file/folder. + 3. If FileDialog.getFile return null then test PASSES, + else test FAILS automatically. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(4) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + frame = new Frame("FileDialog GetFile test"); + fd = new FileDialog(frame); + fd.setFile("FileDialogGetFileTest.html"); + fd.setBounds(100, 100, 400, 400); + Button showBtn = new Button("Show File Dialog"); + frame.add(showBtn); + frame.pack(); + showBtn.addActionListener(e -> { + fd.setVisible(true); + if (fd.getFile() != null) { + PassFailJFrame.forceFail("Test failed: FileDialog returned non-null value"); + } else { + PassFailJFrame.log("Test Passed!"); + } + }); + return frame; + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogIconTest/FileDialogIconTest.java b/test/jdk/java/awt/Dialog/FileDialogIconTest/FileDialogIconTest.java new file mode 100644 index 0000000000000..e8505681a82a5 --- /dev/null +++ b/test/jdk/java/awt/Dialog/FileDialogIconTest/FileDialogIconTest.java @@ -0,0 +1,258 @@ +/* + * 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. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/* + * @test + * @bug 4035189 + * @summary Test to verify that PIT File Dialog icon not matching with + * the new java icon (frame Icon) - PIT build + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogIconTest + */ + +public class FileDialogIconTest { + public static Frame frame; + public static Image image; + public static List images; + static String fileBase; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Select the Image for a Dialog and Frame using either + Load/Save/Just Dialog. + 2. Set the Icon Image/s to Frame and Dialog. Verify that the + Icon is set for the respective Frame and Dialog. + If selected Icon is set to Frame and Dialog press PASS + else FAIL. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(8) + .build() + .awaitAndCheck(); + } + + public static void setImagesToFD(java.util.List listIcon) { + FileDialogIconTest.images = listIcon; + } + + public static void setImagesToFrame(java.util.List listIcon) { + frame.setIconImages(listIcon); + } + + public static void setImageToFD(Image img) { + FileDialogIconTest.image = img; + } + + public static void setImageToFrame(Image img) { + frame.setIconImage(img); + } + + public static Frame initialize() { + frame = new Frame("FileDialogIconTest"); + Button setImageButton1 = new Button("setIconImageToFrame"); + Button setImageButton2 = new Button("setIconImageToDialog"); + Button setImageButton3 = new Button("setIconImagesToFrame"); + Button setImageButton4 = new Button("setIconImagesToDialog"); + Button setImageButton5 = new Button("setIconBufferedImagesToDialog"); + Button setImageButton6 = new Button("setIconBufferedImagesToFrame"); + + if (System.getProperty("test.src") == null) { + fileBase = ""; + } else { + fileBase = System.getProperty("test.src") + System.getProperty("file.separator"); + } + + final String fileName = fileBase + "loading-msg.gif"; + + setImageButton1.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + Image image = Toolkit.getDefaultToolkit().getImage(fileName); + setImageToFrame(image); + PassFailJFrame.log("Loaded image . setting to frame"); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + setImageButton2.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + Image image = Toolkit.getDefaultToolkit().getImage(fileName); + setImageToFD(image); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + setImageButton3.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + Image image; + java.util.List list = new java.util.ArrayList(); + for (int i = 1; i <= 4; i++) { + String fileName = fileBase + "T" + i + ".gif"; + image = Toolkit.getDefaultToolkit().getImage(fileName); + PassFailJFrame.log("Loaded image " + fileName + ". setting to the list for frame"); + list.add(image); + } + setImagesToFrame(list); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + + setImageButton4.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + Image image; + List list = new ArrayList<>(); + for (int i = 1; i <= 4; i++) { + String fileName = fileBase + "T" + i + ".gif"; + image = Toolkit.getDefaultToolkit().getImage(fileName); + PassFailJFrame.log("Loaded image " + fileName + ". setting to the list for dialog"); + list.add(image); + } + setImagesToFD(list); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + + setImageButton5.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + List list = new ArrayList<>(); + try { + Robot robot = new Robot(); + Rectangle rectangle; + for (int i = 1; i <= 4; i++) { + rectangle = new Rectangle(i * 10, i * 10, i * 10 + 40, i * 10 + 40); + java.awt.image.BufferedImage image = robot.createScreenCapture(rectangle); + robot.delay(100); + list.add(image); + } + } catch (Throwable t) { + t.printStackTrace(); + } + PassFailJFrame.log("Captured images and set to the list for dialog"); + } + }); + + setImageButton6.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + List list = new ArrayList<>(); + try { + Robot robot = new Robot(); + Rectangle rectangle; + for (int i = 1; i <= 4; i++) { + rectangle = new Rectangle(i * 10, i * 10, i * 10 + 40, i * 10 + 40); + java.awt.image.BufferedImage image = robot.createScreenCapture(rectangle); + robot.delay(100); + list.add(image); + } + } catch (Throwable t) { + t.printStackTrace(); + } + PassFailJFrame.log("Captured images and set to the list for frame"); + } + }); + + Button buttonLoad = new Button("Load Dialog"); + Button buttonSave = new Button("Save Dialog"); + Button buttonSimple = new Button("Just Dialog"); + buttonLoad.addActionListener(new MyActionListener(FileDialog.LOAD, "LOAD")); + buttonSave.addActionListener(new MyActionListener(FileDialog.SAVE, "SAVE")); + buttonSimple.addActionListener(new MyActionListener(-1, "")); + + frame.setSize(400, 400); + frame.setLayout(new FlowLayout()); + frame.add(buttonLoad); + frame.add(buttonSave); + frame.add(buttonSimple); + frame.add(setImageButton1); + frame.add(setImageButton2); + frame.add(setImageButton3); + frame.add(setImageButton4); + frame.pack(); + return frame; + } +} + +class MyActionListener implements ActionListener { + int id; + String name; + + public MyActionListener(int id, String name) { + this.id = id; + this.name = name; + } + + public void actionPerformed(ActionEvent ae) { + try { + FileDialog filedialog; + if (id == -1 && Objects.equals(name, "")) { + filedialog = new FileDialog(FileDialogIconTest.frame); + } else { + filedialog = new FileDialog(FileDialogIconTest.frame, name, id); + } + if (FileDialogIconTest.image != null) { + filedialog.setIconImage(FileDialogIconTest.image); + } + + if (FileDialogIconTest.images != null) { + filedialog.setIconImages(FileDialogIconTest.images); + } + filedialog.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogIconTest/T1.gif b/test/jdk/java/awt/Dialog/FileDialogIconTest/T1.gif new file mode 100644 index 0000000000000..24a7dea299fd1 Binary files /dev/null and b/test/jdk/java/awt/Dialog/FileDialogIconTest/T1.gif differ diff --git a/test/jdk/java/awt/Dialog/FileDialogIconTest/T2.gif b/test/jdk/java/awt/Dialog/FileDialogIconTest/T2.gif new file mode 100644 index 0000000000000..1f3fd66328ba6 Binary files /dev/null and b/test/jdk/java/awt/Dialog/FileDialogIconTest/T2.gif differ diff --git a/test/jdk/java/awt/Dialog/FileDialogIconTest/T3.gif b/test/jdk/java/awt/Dialog/FileDialogIconTest/T3.gif new file mode 100644 index 0000000000000..af6d626058a67 Binary files /dev/null and b/test/jdk/java/awt/Dialog/FileDialogIconTest/T3.gif differ diff --git a/test/jdk/java/awt/Dialog/FileDialogIconTest/T4.gif b/test/jdk/java/awt/Dialog/FileDialogIconTest/T4.gif new file mode 100644 index 0000000000000..67876264d8f7f Binary files /dev/null and b/test/jdk/java/awt/Dialog/FileDialogIconTest/T4.gif differ diff --git a/test/jdk/java/awt/Dialog/FileDialogIconTest/loading-msg.gif b/test/jdk/java/awt/Dialog/FileDialogIconTest/loading-msg.gif new file mode 100644 index 0000000000000..6c7570a6d8435 Binary files /dev/null and b/test/jdk/java/awt/Dialog/FileDialogIconTest/loading-msg.gif differ diff --git a/test/jdk/java/awt/Dialog/FileDialogTest.java b/test/jdk/java/awt/Dialog/FileDialogTest.java new file mode 100644 index 0000000000000..4ac937d773d83 --- /dev/null +++ b/test/jdk/java/awt/Dialog/FileDialogTest.java @@ -0,0 +1,189 @@ +/* + * 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.Container; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Panel; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4105025 4153487 4177107 4146229 4119383 4181310 4152317 + * @summary Test: FileDialogTest + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogTest + */ + +public class FileDialogTest extends Panel implements ActionListener { + Button buttonShow, buttonNullShow, buttonShowHide, buttonShowDispose; + TextField fieldFile; + TextField fieldDir; + TextField fieldTitle; + private static final String INSTRUCTIONS = """ + 1. Set file, directory, and title fields to some real values + Title will not show on macos dialog + 2. Click the "Get File..." button. + 3. Verify that dialog is set to proper file and directory, and that + title is also set. + 4. Select a file and OK the dialog + (or whatever the selection button is). + 5. Verify that the file and directory fields reflect the file chosen. + 6. Now, click the "Get null File with null Directory..." button. + 7. Verify that the file list matches the listed directory. + 8. Cancel or OK the dialog. + 9. Verify that no NullPointerException is thrown. + 10. Now, click the "Show FileDialog, then hide() in 5 s..." button. + 11. Wait for 5 seconds. The FileDialog should then + disappear automatically. + 12. 12-14 are Windows specific. Set file to some invalid value, + like "/<>++". + 13. Click the "Get File..." button. + 14. Verify that FileDialog is shown with empty "file" field. + 15. Run the test on different locales. Verify that filter string + "All Files" is localized. + """; + + public static void main(String args[]) throws Exception { + Frame frame = new Frame("FileDialogTest"); + frame.setLayout(new GridLayout()); + frame.add(new FileDialogTest()); + frame.pack(); + + PassFailJFrame.builder() + .title("FileDialogTest") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(frame) + .build() + .awaitAndCheck(); + } + + public FileDialogTest() { + setLayout(new GridLayout(6, 2)); + + buttonShow = new Button("Get File..."); + add(buttonShow); + buttonNullShow = new Button("Get null File with null Directory..."); + add(buttonNullShow); + buttonShowHide = new Button("Show FileDialog, then hide() in 5 s..."); + add(buttonShowHide); + buttonShowDispose = + new Button("Show FileDialog, then dispose() in 5 s..."); + add(buttonShowDispose); + + add(new Label("")); + add(new Label("")); + + add(new Label("File:")); + fieldFile = new TextField(20); + add(fieldFile); + + add(new Label("Directory:")); + fieldDir = new TextField(20); + add(fieldDir); + + add(new Label("Title:")); + fieldTitle = new TextField(20); + fieldTitle.setText("TestTitle"); + add(fieldTitle); + + buttonShow.addActionListener(this); + buttonNullShow.addActionListener(this); + buttonShowHide.addActionListener(this); + buttonShowDispose.addActionListener(this); + } + + public void actionPerformed(ActionEvent evt) { + if (evt.getSource() == buttonShow) { + FileDialog fd = new FileDialog(getFrame(), fieldTitle.getText()); + fd.setFile(fieldFile.getText()); + fd.setDirectory(fieldDir.getText()); + fd.show(); + System.out.println("back from show"); + fieldFile.setText(fd.getFile()); + fieldDir.setText(fd.getDirectory()); + fd.dispose(); + } else if (evt.getSource() == buttonNullShow) { + FileDialog fd = new FileDialog(getFrame(), fieldTitle.getText()); + fd.setFile(null); + fd.setDirectory(null); + fd.show(); + System.out.println("back from show"); + fieldFile.setText(fd.getFile()); + fieldDir.setText(fd.getDirectory()); + fd.setFile(null); + fd.setDirectory(null); + fd.dispose(); + } else if (evt.getSource() == buttonShowHide) { + final FileDialog fd = new FileDialog(getFrame(), + fieldTitle.getText()); + fd.setFile(fieldFile.getText()); + fd.setDirectory(fieldDir.getText()); + new Thread(new Runnable() { + public void run() { + try { + Thread.currentThread().sleep(5000); + } catch (InterruptedException ex) { + } + fd.hide(); + } + }).start(); + fd.show(); + System.out.println("back from show"); + fd.dispose(); + } else if (evt.getSource() == buttonShowDispose) { + final FileDialog fd = new FileDialog(getFrame(), + fieldTitle.getText()); + fd.setFile(fieldFile.getText()); + fd.setDirectory(fieldDir.getText()); + new Thread(() -> { + try { + Thread.currentThread().sleep(5000); + } catch (InterruptedException ex) { + } + fd.dispose(); + }).start(); + fd.show(); + System.out.println("back from show"); + fd.dispose(); + } + } + + private Frame getFrame() { + Container cont = getParent(); + while (cont != null) { + if (cont instanceof Frame) { + return (Frame) cont; + } + cont = cont.getParent(); + } + return null; + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogUIUpdate.java b/test/jdk/java/awt/Dialog/FileDialogUIUpdate.java new file mode 100644 index 0000000000000..f97d947991b43 --- /dev/null +++ b/test/jdk/java/awt/Dialog/FileDialogUIUpdate.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4859390 + * @requires (os.family == "windows") + * @summary Verify that FileDialog matches the look + of the native windows FileDialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogUIUpdate + */ + +public class FileDialogUIUpdate extends Frame { + static String instructions = """ + Click the button to show the FileDialog. Then open the Paint + application (usually found in Program Files->Accessories). + Select File->Open from Paint to display a native Open dialog. + Compare the native dialog to the AWT FileDialog. + Specifically, confirm that the Places Bar icons are along the left side (or + not, if the native dialog doesn't have them), and that the + dialogs are both resizable (or not). + If the file dialogs both look the same press Pass. If not, + press Fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FileDialogUIUpdate") + .instructions(instructions) + .testTimeOut(5) + .rows(12) + .columns(35) + .testUI(FileDialogUIUpdate::new) + .build() + .awaitAndCheck(); + } + + public FileDialogUIUpdate() { + final FileDialog fd = new FileDialog(new Frame("FileDialogUIUpdate frame"), + "Open FileDialog"); + Button showButton = new Button("Show FileDialog"); + setLayout(new BorderLayout()); + + fd.setDirectory("c:/"); + showButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + fd.setVisible(true); + } + }); + + add(showButton); + setSize(200, 200); + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogUserFilterTest.java b/test/jdk/java/awt/Dialog/FileDialogUserFilterTest.java new file mode 100644 index 0000000000000..80ff9ed0bde60 --- /dev/null +++ b/test/jdk/java/awt/Dialog/FileDialogUserFilterTest.java @@ -0,0 +1,150 @@ +/* + * 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.Button; +import java.awt.Checkbox; +import java.awt.Component; +import java.awt.Container; +import java.awt.Event; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Label; +import java.awt.Panel; +import java.awt.TextField; +import java.io.File; +import java.io.FilenameFilter; + +/* + * @test + * @bug 4293697 4416433 4417139 4409600 + * @summary Test to verify that user filter always gets called on changing the + * directory in FileDialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogUserFilterTest + */ + +public class FileDialogUserFilterTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Enter a mask into the field, a directory into + the field (or leave the default values). + 2. Then click the button, file dialog will appear. + Output of the user filter will be shown in the output + area. Enter several different directories to the file dialog + via double-clicking on the directory list. The output + area should show some filtering output on each directory + change. If any output was only given on dialog startup, + the test is FAILED. + 3. Look at the list of files accepted by the filter. + If some files do not match the filter, + the test is FAILED. + 4. Open dialog with an empty filter. + Enter some directories with a lot of files (like /usr/bin). + If dialog crashes the test is FAILED. + Enter the directory that contain files and other directories. + If the directories are shown in the files box along with files + then the test is FAILED. + 5. Click in checkbox 'do not use filter', make it checked. + Open dialog, enter the directory with some files. + If no files is shown in the File list box (while you are sure + there are some files there) the test is FAILED + Otherwise it is PASSED." + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(new DialogFilterTest()) + .build() + .awaitAndCheck(); + } +} + +class DialogFilterTest extends Frame implements FilenameFilter { + FileDialog fd; + static TextField tfDirectory = new TextField(); + static TextField tfFile = new TextField(); + static TextField tfFilter = new TextField(); + static Checkbox useFilterCheck = new Checkbox("do not use filter"); + + public DialogFilterTest() { + setTitle("File Dialog User Filter test"); + add("North", new Button("Load")); + Panel p = new Panel(); + p.setLayout(new GridBagLayout()); + addRow(p, new Label("directory:", Label.RIGHT), tfDirectory); + addRow(p, new Label("file:", Label.RIGHT), tfFile); + addRow(p, new Label("filter:", Label.RIGHT), tfFilter); + addRow(p, new Label(""), useFilterCheck); + tfFilter.setText(".java"); + tfDirectory.setText("."); + add("Center", p); + setSize(300, 200); + } + + static void addRow(Container cont, Component c1, Component c2) { + GridBagLayout gbl = (GridBagLayout) cont.getLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + cont.add(c1); + gbl.setConstraints(c1, c); + + c.gridwidth = GridBagConstraints.REMAINDER; + c.weightx = 1.0; + cont.add(c2); + gbl.setConstraints(c2, c); + } + + public boolean accept(File dir, String name) { + System.out.println("File " + dir + " String " + name); + if (fd.getMode() == FileDialog.LOAD) { + return name.lastIndexOf(tfFilter.getText()) > 0; + } + return true; + } + + public boolean action(Event evt, Object what) { + boolean load = "Load".equals(what); + + if (load || "Save".equals(what)) { + fd = new FileDialog(new Frame(), null, + load ? FileDialog.LOAD : FileDialog.SAVE); + fd.setDirectory(tfDirectory.getText()); + fd.setFile(tfFile.getText()); + if (!useFilterCheck.getState()) { + fd.setFilenameFilter(this); + } + fd.setVisible(true); + tfDirectory.setText(fd.getDirectory()); + tfFile.setText(fd.getFile()); + + return true; + } + return false; + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogWrongNameCrash.java b/test/jdk/java/awt/Dialog/FileDialogWrongNameCrash.java new file mode 100644 index 0000000000000..f3d83a6849465 --- /dev/null +++ b/test/jdk/java/awt/Dialog/FileDialogWrongNameCrash.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +import java.awt.Button; +import java.awt.Frame; + +/* + * @test + * @bug 4779118 + * @summary Tests that FileDialog with wrong initial file name + * doesn't crash when Open button is pressed. + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogWrongNameCrash + */ + +public class FileDialogWrongNameCrash { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + (This is Windows only test) + 1. You should see a frame 'Frame' with button 'Load'. Press button.", + 2. You should see 'Load file' dialog, select any file and press 'Open'", + (not 'Cancel'!!!). If Java doesn't crash - press PASS, else FAIL + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + private static Frame initialize() { + Frame frame = new Frame("File Dialog Wrong Name Crash Test"); + Button fileButton = new Button("Load"); + fileButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent e) { + final java.awt.FileDialog selector = + new java.awt.FileDialog(frame); + selector.setFile("Z:\\O2 XDA\\LogiTest\\\\Testcase.xml"); + selector.setVisible(true); + } + }); + frame.add(fileButton); + frame.setSize(100, 60); + return frame; + } +} diff --git a/test/jdk/java/awt/Dialog/GetLocationTest_1.java b/test/jdk/java/awt/Dialog/GetLocationTest_1.java new file mode 100644 index 0000000000000..a373f931cf72a --- /dev/null +++ b/test/jdk/java/awt/Dialog/GetLocationTest_1.java @@ -0,0 +1,129 @@ +/* + * 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. + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4168481 + * @summary Test to verify Dialog getLocation() regression on Solaris + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual GetLocationTest_1 + */ + +public class GetLocationTest_1 { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Click in in the blue square and the yellow window should come + up with the top left by the cursor + 2. If you see this correct behavior press PASS. If you see that + the yellow window location is offset by some inset, press FAIL + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(8) + .build() + .awaitAndCheck(); + } + + public static Dialog initialize() { + Frame f = new Frame("Owner Frame"); + ColorComponent blue = new ColorComponent(); + blue.setBackground(Color.blue); + blue.setSize(50, 50); + + final Dialog dialog = new Dialog(f, "GetLocation test"); + dialog.setLocation(300, 300); + System.out.println("Dialog location = " + dialog.getLocation()); + blue.setLocation(50, 50); + dialog.setLayout(null); + dialog.add(blue); + dialog.setSize(200, 200); + + final ColorWindow w = new ColorWindow(f); + w.setSize(50, 50); + w.setBackground(Color.yellow); + + blue.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + PassFailJFrame.log("Dialog location = " + dialog.getLocation()); + Point p = e.getPoint(); + Component c = e.getComponent(); + PassFailJFrame.log("Position = " + p); + convertPointToScreen(p, c); + PassFailJFrame.log("Converted to = " + p); + w.setLocation(p.x, p.y); + w.setVisible(true); + } + }); + return dialog; + } + + static class ColorComponent extends Component { + public void paint(Graphics g) { + g.setColor(getBackground()); + Rectangle bounds = getBounds(); + g.fillRect(0, 0, bounds.width, bounds.height); + } + } + + static class ColorWindow extends Window { + ColorWindow(Frame f) { + super(f); + } + + public void paint(Graphics g) { + g.setColor(getBackground()); + Rectangle bounds = getBounds(); + g.fillRect(0, 0, bounds.width, bounds.height); + } + } + + public static void convertPointToScreen(Point p, Component c) { + do { + Point b = c.getLocation(); + PassFailJFrame.log("Adding " + b + " for " + c); + p.x += b.x; + p.y += b.y; + + if (c instanceof java.awt.Window) { + break; + } + c = c.getParent(); + } while (c != null); + } +} diff --git a/test/jdk/java/awt/Dialog/HideDialogTest.java b/test/jdk/java/awt/Dialog/HideDialogTest.java new file mode 100644 index 0000000000000..78d0344a6cf8e --- /dev/null +++ b/test/jdk/java/awt/Dialog/HideDialogTest.java @@ -0,0 +1,138 @@ +/* + * 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 + * 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.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4048664 4065506 4122094 4171979 + * @summary Test if Dialog can be successfully hidden, see that no other app + * comes to front, see if hide + dispose causes assertion failure + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HideDialogTest + */ + +public class HideDialogTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. A Frame should appear with a "test" button in it + 2. Click on the "test" button. A Dialog will appear with a "dismiss" button + and a "dismiss-with-dispose" button + 3. First, click on the "dismiss-with-dispose" button. Verify that + no assertion failure appears. + 4. Now, click on the "dismiss" button. The Dialog should go away. + 5. Repeat from (2) 10-20 times. + 6. When the dialog goes away check that the frame window does not briefly + get obscured by another app or repaint it's entire area. There should be + no flicker at all in areas obscured by the dialog. (4065506 4122094) + If there is the test fails. + 7. If the Dialog is successfully hidden each time, the test passed. If the + Dialog did not hide, the test failed (4048664). + + NOTE: When the dialog does not go away (meaning the bug has manifested itself), + the "dismiss-with-dispose" button can be used to get rid of it. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(new MyFrame()) + .build() + .awaitAndCheck(); + } +} + +class MyDialog extends Dialog { + public MyDialog(Frame f) { + super(f, "foobar", true); + setSize(200, 200); + setLayout(new BorderLayout()); + Panel p = new Panel(); + p.setLayout(new FlowLayout(FlowLayout.CENTER)); + Button okButton; + okButton = new Button("dismiss"); + p.add(okButton); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println("Calling setVisible(false)"); + setVisible(false); + } + }); + Button newButton; + p.add(newButton = new Button("dismiss-with-dispose")); + newButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println("Calling setVisible(false) + dispose()"); + setVisible(false); + dispose(); + } + }); + add("South", p); + pack(); + } +} + +class MyFrame extends Frame implements ActionListener { + public MyFrame() { + super(); + setSize(600, 400); + setTitle("HideDialogTest"); + setLayout(new BorderLayout()); + Panel toolbar = new Panel(); + toolbar.setLayout(new FlowLayout(FlowLayout.LEFT)); + Button testButton = new Button("test"); + testButton.addActionListener(this); + toolbar.add(testButton); + add("North", toolbar); + } + + public void actionPerformed(ActionEvent e) { + String s = e.getActionCommand(); + if (s.equals("test")) { + System.out.println("Begin test"); + MyDialog d = new MyDialog(this); + d.setVisible(true); + System.out.println("End test"); + } + } + + public void paint(Graphics g) { + for (int i = 0; i < 10; i++) { + g.setColor(Color.red); + g.fillRect(0, 0, 2000, 2000); + g.setColor(Color.blue); + g.fillRect(0, 0, 2000, 2000); + } + } +} diff --git a/test/jdk/java/awt/Dialog/MenuAndModalDialogTest.java b/test/jdk/java/awt/Dialog/MenuAndModalDialogTest.java new file mode 100644 index 0000000000000..c22116ff8df1c --- /dev/null +++ b/test/jdk/java/awt/Dialog/MenuAndModalDialogTest.java @@ -0,0 +1,104 @@ +/* + * 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 + * 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.Dialog; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4070085 + * @summary Java program locks up X server + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuAndModalDialogTest + */ + +public class MenuAndModalDialogTest { + static Frame frame; + static String instructions = """ + 1. Bring up the File Menu and leave it up. + 2. In a few seconds, the modal dialog will appear. + 3. Verify that your system does not lock up when you push the "OK" button. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame pf = PassFailJFrame.builder() + .title("MenuAndModalDialogTest") + .instructions(instructions) + .testTimeOut(5) + .rows(10) + .columns(35) + .testUI(MenuAndModalDialogTest::createFrame) + .build(); + + // Allow time to pop up the menu + try { + Thread.currentThread().sleep(5000); + } catch (InterruptedException exception) { + } + + createDialog(); + pf.awaitAndCheck(); + } + + public static Frame createFrame() { + frame = new Frame("MenuAndModalDialogTest frame"); + + MenuBar menuBar = new MenuBar(); + frame.setMenuBar(menuBar); + + Menu file = new Menu("File"); + menuBar.add(file); + + MenuItem menuItem = new MenuItem("A Menu Entry"); + file.add(menuItem); + + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + return frame; + } + + public static void createDialog() { + Dialog dialog = new Dialog(frame); + + Button button = new Button("OK"); + dialog.add(button); + button.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + dialog.dispose(); + } + } + ); + + dialog.setSize(200, 200); + dialog.setModal(true); + dialog.setVisible(true); + } +} diff --git a/test/jdk/java/awt/Dialog/ModalDialogTest.java b/test/jdk/java/awt/Dialog/ModalDialogTest.java new file mode 100644 index 0000000000000..aceacc9209a80 --- /dev/null +++ b/test/jdk/java/awt/Dialog/ModalDialogTest.java @@ -0,0 +1,147 @@ +/* + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +/* + * @test + * @bug 4078176 + * @summary Test to verify Modal dialogs don't act modal if addNotify() + * is called before setModal(true). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ModalDialogTest + */ + +public class ModalDialogTest implements ActionListener { + public boolean modal = true; + Button closeBtn = new Button("Close me"); + Button createBtn = new Button("Create Dialog"); + Button createNewBtn = new Button("Create Modal Dialog"); + Button lastBtn = new Button("Show Last Dialog"); + Dialog dialog; + Dialog newDialog; + Frame testFrame; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Use 'Modal' checkbox to select which dialog you're + going to create - modal or non-modal. + (this checkbox affects only new created dialog but + not existing one) + 2. Use 'Create Dialog' button to create a dialog. + If you have selected 'Modal' checkbox then dialog has to + be created modal - you can make sure of that clicking + on any other control (i.e. 'Modal' checkbox) - they + should not work. + 3. Use 'Show Last Dialog' button to bring up last + created dialog - to make sure that if you show/hide + modal dialog several times it stays modal. + 4. On the appearing dialog there are two buttons: + 'Close Me' which closes the dialog, + and 'Create Modal Dialog' which creates one more + MODAL dialog just to make sure that + in situation with two modal dialogs all is fine. + 5. If created modal dialogs are really modal + (which means that they blocks the calling app) + then test is PASSED, otherwise it's FAILED." + """; + ModalDialogTest test = new ModalDialogTest(); + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(test.initialize()) + .build() + .awaitAndCheck(); + } + + public Frame initialize() { + testFrame = new Frame("Parent Frame"); + Frame frame = new Frame("Modal Dialog test"); + Panel panel = new Panel(); + panel.setLayout(new BorderLayout()); + + createBtn.addActionListener(this); + createNewBtn.addActionListener(this); + closeBtn.addActionListener(this); + lastBtn.addActionListener(this); + panel.add("Center", createBtn); + panel.add("South", lastBtn); + Checkbox cb = new Checkbox("Modal", modal); + cb.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + modal = ((Checkbox) e.getSource()).getState(); + } + }); + panel.add("North", cb); + panel.setSize(200, 100); + + frame.add(panel); + frame.pack(); + return frame; + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == createBtn) { + if (dialog != null) { + dialog.dispose(); + } + dialog = new Dialog(testFrame, "Modal Dialog"); + dialog.add("North", closeBtn); + dialog.add("South", createNewBtn); + createBtn.setEnabled(false); + dialog.pack(); + dialog.setModal(modal); + dialog.setVisible(true); + } else if (e.getSource() == closeBtn && dialog != null) { + createBtn.setEnabled(true); + dialog.setVisible(false); + } else if (e.getSource() == lastBtn && dialog != null) { + dialog.setVisible(true); + } else if (e.getSource() == createNewBtn && newDialog == null) { + newDialog = new Dialog(testFrame, "New Modal Dialog"); + Button clsBtn = new Button("Close Me"); + clsBtn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + newDialog.dispose(); + newDialog = null; + } + }); + newDialog.add("North", clsBtn); + newDialog.pack(); + newDialog.setModal(true); + newDialog.setVisible(true); + } + } +} diff --git a/test/jdk/java/awt/Dialog/ModalExcludedTest.java b/test/jdk/java/awt/Dialog/ModalExcludedTest.java new file mode 100644 index 0000000000000..2531c26d3bc3f --- /dev/null +++ b/test/jdk/java/awt/Dialog/ModalExcludedTest.java @@ -0,0 +1,315 @@ +/* + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.JobAttributes; +import java.awt.PageAttributes; +import java.awt.Panel; +import java.awt.PrintJob; +import java.awt.TextArea; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; + +import sun.awt.SunToolkit; + +/* + * @test + * @bug 4813288 4866704 + * @summary Test for "modal exclusion" functionality + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame + * @modules java.desktop/sun.awt + * @run main/manual ModalExcludedTest + */ + +public class ModalExcludedTest { + private static final String INSTRUCTIONS = """ + 1. Press 'Modal dialog w/o modal excluded' button below + A window, a modeless dialog and a modal dialog will appear + Make sure the frame and the modeless dialog are inaccessible, + i.e. receive no mouse and keyboard events. MousePressed and + KeyPressed events are logged in the text area - use it + to watch events + Close all 3 windows + + 2. Press 'Modal dialog w/ modal excluded' button below + Again, 3 windows will appear (frame, dialog, modal dialog), + but the frame and the dialog would be modal excluded, i.e. + behave the same way as there is no modal dialog shown. Verify + this by pressing mouse buttons and typing any keys. The + RootFrame would be modal blocked - verify this too + Close all 3 windows + + 3. Repeat step 2 for file and print dialogs using appropriate + buttons below + + Notes: if there is no printer installed in the system you may not + get any print dialogs + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ModalExcludedTest") + .instructions(INSTRUCTIONS) + .rows(10) + .columns(35) + .testUI(ModalExcludedTest::createGUIs) + .build() + .awaitAndCheck(); + } + + public static Frame createGUIs() { + final Frame f = new Frame("RootFrame"); + f.setBounds(0, 0, 480, 500); + f.setLayout(new BorderLayout()); + + final TextArea messages = new TextArea(); + + final WindowListener wl = new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + if (ev.getSource() instanceof Window) { + ((Window) ev.getSource()).dispose(); + } + } + }; + final MouseListener ml = new MouseAdapter() { + public void mousePressed(MouseEvent ev) { + messages.append(ev + "\n"); + } + }; + final KeyListener kl = new KeyAdapter() { + public void keyPressed(KeyEvent ev) { + messages.append(ev + "\n"); + } + }; + + if (!SunToolkit.isModalExcludedSupported()) { + throw new jtreg.SkippedException("Modal exclude is not supported on this platform."); + } + + messages.addMouseListener(ml); + messages.addKeyListener(kl); + f.add(messages, BorderLayout.CENTER); + + Panel buttons = new Panel(); + buttons.setLayout(new GridLayout(6, 1)); + + Button b = new Button("Modal dialog w/o modal excluded"); + b.addActionListener(ev -> { + Frame ff = new Frame("Non-modal-excluded frame"); + ff.setBounds(400, 0, 200, 100); + ff.addWindowListener(wl); + ff.addMouseListener(ml); + ff.addKeyListener(kl); + ff.setVisible(true); + + Dialog dd = new Dialog(ff, "Non-modal-excluded dialog", false); + dd.setBounds(500, 100, 200, 100); + dd.addWindowListener(wl); + dd.addMouseListener(ml); + dd.addKeyListener(kl); + dd.setVisible(true); + + Dialog d = new Dialog(f, "Modal dialog", true); + d.setBounds(600, 200, 200, 100); + d.addWindowListener(wl); + d.addMouseListener(ml); + d.addKeyListener(kl); + d.setVisible(true); + }); + buttons.add(b); + + Button c = new Button("Modal dialog w/ modal excluded"); + c.addActionListener(ev -> { + JFrame ff = new JFrame("Modal-excluded frame"); + ff.setBounds(400, 0, 200, 100); + ff.addWindowListener(wl); + ff.addMouseListener(ml); + ff.addKeyListener(kl); + JMenuBar mb = new JMenuBar(); + JMenu m = new JMenu("Test menu"); + m.add("Test menu item"); + m.add("Test menu item"); + m.add("Test menu item"); + m.add("Test menu item"); + m.add("Test menu item"); + m.add("Test menu item"); + m.add("Test menu item"); + m.add("Test menu item"); + m.add("Test menu item"); + mb.add(m); + ff.setJMenuBar(mb); + // 1: set visible + ff.setVisible(true); + + Dialog dd = new Dialog(ff, "Modal-excluded dialog", false); + dd.setBounds(500, 100, 200, 100); + dd.addWindowListener(wl); + dd.addMouseListener(ml); + dd.addKeyListener(kl); + dd.setVisible(true); + + // 2: set modal excluded + SunToolkit.setModalExcluded(ff); + + Dialog d = new Dialog(f, "Modal dialog", true); + d.setBounds(600, 200, 200, 100); + d.addWindowListener(wl); + d.addMouseListener(ml); + d.addKeyListener(kl); + d.setVisible(true); + }); + buttons.add(c); + + Button c1 = new Button("Modal dialog before modal excluded"); + c1.addActionListener(ev -> { + // 1: create dialog + Dialog d = new Dialog(f, "Modal dialog", true); + d.setBounds(600, 200, 200, 100); + d.addWindowListener(wl); + d.addMouseListener(ml); + d.addKeyListener(kl); + + // 2: create frame + Frame ff = new Frame("Modal-excluded frame"); + // 3: set modal excluded + SunToolkit.setModalExcluded(ff); + ff.setBounds(400, 0, 200, 100); + ff.addWindowListener(wl); + ff.addMouseListener(ml); + ff.addKeyListener(kl); + // 4: show frame + ff.setVisible(true); + + Dialog dd = new Dialog(ff, "Modal-excluded dialog", false); + dd.setBounds(500, 100, 200, 100); + dd.addWindowListener(wl); + dd.addMouseListener(ml); + dd.addKeyListener(kl); + dd.setVisible(true); + + // 5: show dialog + d.setVisible(true); + }); + buttons.add(c1); + + Button d = new Button("File dialog w/ modal excluded"); + d.addActionListener(ev -> { + Frame ff = new Frame("Modal-excluded frame"); + ff.setBounds(400, 0, 200, 100); + ff.addWindowListener(wl); + ff.addMouseListener(ml); + ff.addKeyListener(kl); + // 1: set modal excluded (peer is not created yet) + SunToolkit.setModalExcluded(ff); + // 2: set visible + ff.setVisible(true); + + Dialog dd = new Dialog(ff, "Modal-excluded dialog", false); + dd.setBounds(500, 100, 200, 100); + dd.addWindowListener(wl); + dd.addMouseListener(ml); + dd.addKeyListener(kl); + dd.setVisible(true); + SunToolkit.setModalExcluded(dd); + + Dialog d1 = new FileDialog(f, "File dialog"); + d1.setVisible(true); + }); + buttons.add(d); + + Button e = new Button("Native print dialog w/ modal excluded"); + e.addActionListener(ev -> { + Frame ff = new Frame("Modal-excluded frame"); + ff.setBounds(400, 0, 200, 100); + ff.addWindowListener(wl); + ff.addMouseListener(ml); + ff.addKeyListener(kl); + ff.setVisible(true); + SunToolkit.setModalExcluded(ff); + + Dialog dd = new Dialog(ff, "Modal-excluded dialog", false); + dd.setBounds(500, 100, 200, 100); + dd.addWindowListener(wl); + dd.addMouseListener(ml); + dd.addKeyListener(kl); + dd.setVisible(true); + + JobAttributes jobAttributes = new JobAttributes(); + jobAttributes.setDialog(JobAttributes.DialogType.NATIVE); + PageAttributes pageAttributes = new PageAttributes(); + PrintJob job = Toolkit.getDefaultToolkit().getPrintJob(f, "Test", jobAttributes, pageAttributes); + }); + buttons.add(e); + + Button g = new Button("Common print dialog w/ modal excluded"); + g.addActionListener(ev -> { + Frame ff = new Frame("Modal-excluded frame"); + ff.setBounds(400, 0, 200, 100); + ff.addWindowListener(wl); + ff.addMouseListener(ml); + ff.addKeyListener(kl); + ff.setVisible(true); + SunToolkit.setModalExcluded(ff); + ff.dispose(); + // modal excluded must still be alive + ff.setVisible(true); + + Dialog dd = new Dialog(ff, "Modal-excluded dialog", false); + dd.setBounds(500, 100, 200, 100); + dd.addWindowListener(wl); + dd.addMouseListener(ml); + dd.addKeyListener(kl); + dd.setVisible(true); + + JobAttributes jobAttributes = new JobAttributes(); + jobAttributes.setDialog(JobAttributes.DialogType.COMMON); + PageAttributes pageAttributes = new PageAttributes(); + PrintJob job = Toolkit.getDefaultToolkit().getPrintJob(f, "Test", jobAttributes, pageAttributes); + }); + buttons.add(g); + + f.add(buttons, BorderLayout.SOUTH); + return f; + } +} diff --git a/test/jdk/java/awt/Dialog/NestedDialogTest.java b/test/jdk/java/awt/Dialog/NestedDialogTest.java new file mode 100644 index 0000000000000..28fb1bc919e6a --- /dev/null +++ b/test/jdk/java/awt/Dialog/NestedDialogTest.java @@ -0,0 +1,312 @@ +/* + * 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.Choice; +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.Vector; +import java.util.Enumeration; + +/* + * @test + * @bug 4110094 4178930 4178390 + * @summary Test: Rewrite of Win modal dialogs + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NestedDialogTest + */ + +public class NestedDialogTest { + private static Vector windows = new Vector(); + static String instructions = """ + To solve various race conditions, windows modal dialogs were rewritten. This + test exercises various modal dialog boundary conditions and checks that + previous fixes to modality are incorporated in the rewrite. + + Check the following: + - No IllegalMonitorStateException is thrown when a dialog closes + + - Open multiple nested dialogs and verify that all other windows + are disabled when modal dialog is active. + + - Check that the proper window is activated when a modal dialog closes. + + - Close nested dialogs out of order (e.g. close dialog1 before dialog2) + and verify that this works and no deadlock occurs. + + - Check that all other windows are disabled when a FileDialog is open. + + - Check that the proper window is activated when a FileDialog closes. + + - Verify that the active window nevers switches to another application + when closing dialogs, even temporarily. + + - Check that choosing Hide always sucessfully hides a dialog. You should + try this multiple times to catch any race conditions. + + - Check that the scrollbar on the Choice component in the dialog works, as opposed + to just using drag-scrolling or the cursor keys + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("NestedDialogTest") + .instructions(instructions) + .testTimeOut(5) + .rows((int) instructions.lines().count() + 2) + .columns(35) + .testUI(NestedDialogTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Frame frame1 = new NestedDialogTestFrame("frame0"); + Frame frame2 = new NestedDialogTestFrame("frame1"); + frame2.setLocation(100, 100); + return frame1; + } + + public static void addWindow(Window window) { + // System.out.println("Pushing window " + window); + windows.removeElement(window); + windows.addElement(window); + } + + public static void removeWindow(Window window) { + // System.out.println("Popping window " + window); + windows.removeElement(window); + } + + public static Window getWindow(int index) { + return (Window) windows.elementAt(index); + } + + public static Enumeration enumWindows() { + return windows.elements(); + } + + public static int getWindowIndex(Window win) { + return windows.indexOf(win); + } +} + +class NestedDialogTestFrame extends Frame { + NestedDialogTestFrame(String name) { + super(name); + setSize(200, 200); + show(); + + setLayout(new FlowLayout()); + Button btnDlg = new Button("Dialog..."); + add(btnDlg); + Button btnFileDlg = new Button("FileDialog..."); + add(btnFileDlg); + + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + System.exit(0); + } + }); + + btnDlg.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + Dialog d1 = new SimpleDialog(NestedDialogTestFrame.this, null, true); + System.out.println("Returned from showing dialog: " + d1); + } + } + ); + + btnFileDlg.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + FileDialog dlg = new FileDialog(NestedDialogTestFrame.this); + dlg.show(); + } + } + ); + + validate(); + } + + public void show() { + if (!isVisible()) { + NestedDialogTest.addWindow(this); + } + super.show(); + } + + public void dispose() { + NestedDialogTest.removeWindow(this); + super.dispose(); + } +} + +class SimpleDialog extends Dialog { + Button btnNested; + Button btnFileDlg; + Button btnShow; + Button btnHide; + Button btnDispose; + Button btnExit; + List listWins; + Dialog dlgPrev; + + public SimpleDialog(Frame frame, Dialog prev, boolean isModal) { + super(frame, "", isModal); + + dlgPrev = prev; + + addWindowListener(new WindowAdapter() { + public void windowActivated(WindowEvent ev) { + populateListWin(); + } + }); + + setTitle(getName()); + + Panel panelNorth = new Panel(); + panelNorth.setLayout(new GridLayout(1, 1)); + listWins = new List(); + panelNorth.add(listWins); + + Panel panelSouth = new Panel(); + panelSouth.setLayout(new FlowLayout()); + btnNested = new Button("Dialog..."); + panelSouth.add(btnNested); + btnFileDlg = new Button("FileDialog..."); + panelSouth.add(btnFileDlg); + btnShow = new Button("Show"); + panelSouth.add(btnShow); + btnHide = new Button("Hide"); + panelSouth.add(btnHide); + btnDispose = new Button("Dispose"); + panelSouth.add(btnDispose); + + Choice cbox = new Choice(); + cbox.add("Test1"); + cbox.add("Test2"); + cbox.add("Test3"); + cbox.add("Test4"); + cbox.add("Test5"); + cbox.add("Test6"); + cbox.add("Test7"); + cbox.add("Test8"); + cbox.add("Test9"); + cbox.add("Test10"); + cbox.add("Test11"); + panelSouth.add(cbox); + + validate(); + + add("Center", panelNorth); + add("South", panelSouth); + + btnNested.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Dialog dlg = new SimpleDialog((Frame) getParent(), SimpleDialog.this, true); + System.out.println("Returned from showing dialog: " + dlg); + } + }); + + btnFileDlg.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + FileDialog dlg = new FileDialog((Frame) getParent()); + dlg.show(); + } + }); + + btnHide.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Window wnd = getSelectedWindow(); + System.out.println(wnd); + wnd.hide(); + } + }); + + btnShow.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + getSelectedWindow().show(); + } + }); + + btnDispose.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + getSelectedWindow().dispose(); + populateListWin(); + } + }); + + pack(); + setSize(getSize().width, getSize().height * 2); + if (dlgPrev != null) { + Point pt = dlgPrev.getLocation(); + setLocation(pt.x + 30, pt.y + 50); + } + show(); + } + + private Window getSelectedWindow() { + Window window; + int index = listWins.getSelectedIndex(); + + window = NestedDialogTest.getWindow(index); + return window; + } + + private void populateListWin() { + Enumeration enumWindows = NestedDialogTest.enumWindows(); + + listWins.removeAll(); + while (enumWindows.hasMoreElements()) { + Window win = (Window) enumWindows.nextElement(); + listWins.add(win.getName()); + } + listWins.select(NestedDialogTest.getWindowIndex(this)); + } + + public void show() { + if (!isVisible()) { + NestedDialogTest.addWindow(this); + } + super.show(); + } + + public void dispose() { + NestedDialogTest.removeWindow(this); + super.dispose(); + } +} diff --git a/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileFrame.java b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileFrame.java new file mode 100644 index 0000000000000..a117622d57003 --- /dev/null +++ b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileFrame.java @@ -0,0 +1,40 @@ +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.PrintJob; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +class PrintToFileFrame extends Frame implements ActionListener { + Button nativeDlg = new Button("Show print dialog"); + + public PrintToFileFrame() { + this.setLayout(new FlowLayout()); + add(nativeDlg); + nativeDlg.addActionListener(this); + + setSize(300, 300); + } + + @SuppressWarnings("removal") + public void actionPerformed(ActionEvent ae) { + if (System.getSecurityManager() == null) { + throw new RuntimeException("Security manager isn't installed."); + } + + try { + System.getSecurityManager().checkPrintJobAccess(); + System.out.println("checkPrintJobAccess - OK"); + } catch (SecurityException e) { + System.out.println("checkPrintJobAccess - ERROR " + e); + } + + PrintJob printJob = getToolkit().getPrintJob(this, null, null); + + if (printJob != null) { + System.out.println("Print Job: " + printJob); + } else { + System.out.println("Print Job is null."); + } + } +} diff --git a/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileGranted.java b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileGranted.java new file mode 100644 index 0000000000000..05d73123d983a --- /dev/null +++ b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileGranted.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.print.PrinterJob; + +/* + * @test + * @bug 6275359 + * @summary Test to verify system menu of a dialog on win32 + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @compile PrintToFileFrame.java + * @compile PrintToFileGranted.java + * @run main/manual/policy=granted/othervm PrintToFileGranted + */ + +public class PrintToFileGranted { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS; + if (isPrintSupport()) { + INSTRUCTIONS = """ + 1. Click on 'Show file dialog' button A print dialog will come up + 2. If checkbox 'Print to file' is enabled then the test passed + else the test failed + 3. Close the print dialog before pressing PASS or FAIL buttons + """; + } else { + INSTRUCTIONS = """ + 1. The test requires printer installed in your system, + but there is no printers found + Please install one and re-run the test + """; + } + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(new PrintToFileFrame()) + .build() + .awaitAndCheck(); + } + + public static boolean isPrintSupport() { + PrinterJob pj = PrinterJob.getPrinterJob(); + return pj.getPrintService() != null; + } +} diff --git a/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileRevoked.java b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileRevoked.java new file mode 100644 index 0000000000000..7c724e97bed53 --- /dev/null +++ b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileRevoked.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.print.PrinterJob; + +/* + * @test + * @bug 6275359 + * @summary Test to verify Printing ignores Security permissions + * using native dialog + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @compile PrintToFileRevoked.java + * @run main/manual/policy=revoked/othervm PrintToFileRevoked + */ + +public class PrintToFileRevoked { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS; + if (isPrintSupport()) { + INSTRUCTIONS = """ + 1. Click on 'Show file dialog' button A print dialog will come up + 2. If checkbox 'Print to file' is disabled then the test passed + else the test failed + 3. Close the print dialog before pressing PASS or FAIL buttons + """; + } else { + INSTRUCTIONS = """ + 1. The test requires printer installed in your system, + but there is no printers found + Please install one and re-run the test + """; + } + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(new PrintToFileFrame()) + .build() + .awaitAndCheck(); + } + + public static boolean isPrintSupport() { + PrinterJob pj = PrinterJob.getPrinterJob(); + return pj.getPrintService() != null; + } +} diff --git a/test/jdk/java/awt/Dialog/PrintToFileTest/granted b/test/jdk/java/awt/Dialog/PrintToFileTest/granted new file mode 100644 index 0000000000000..e73b0fdf3cdef --- /dev/null +++ b/test/jdk/java/awt/Dialog/PrintToFileTest/granted @@ -0,0 +1,10 @@ +/* AUTOMATICALLY GENERATED ON Thu Jan 03 15:48:39 PST 2002*/ +/* DO NOT EDIT */ + +grant { + permission java.lang.RuntimePermission "queuePrintJob"; + permission java.util.PropertyPermission "*", "read"; + permission java.io.FilePermission "<>", "read"; + permission java.io.FilePermission "<>", "write"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.util.locale.provider"; +}; diff --git a/test/jdk/java/awt/Dialog/PrintToFileTest/revoked b/test/jdk/java/awt/Dialog/PrintToFileTest/revoked new file mode 100644 index 0000000000000..d2545e15e1155 --- /dev/null +++ b/test/jdk/java/awt/Dialog/PrintToFileTest/revoked @@ -0,0 +1,9 @@ +/* AUTOMATICALLY GENERATED ON Thu Jan 03 15:48:39 PST 2002*/ +/* DO NOT EDIT */ + +grant { + permission java.lang.RuntimePermission "queuePrintJob"; + permission java.util.PropertyPermission "*", "read"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.util.locale.provider"; +}; + diff --git a/test/jdk/java/awt/Dialog/ShownModalDialogSerializationTest.java b/test/jdk/java/awt/Dialog/ShownModalDialogSerializationTest.java new file mode 100644 index 0000000000000..b57dd2cf8f238 --- /dev/null +++ b/test/jdk/java/awt/Dialog/ShownModalDialogSerializationTest.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; + +import java.awt.TextArea; +import java.io.File; +import java.io.FileOutputStream; +import java.io.ObjectOutputStream; + +/* + * @test + * @bug 4739757 + * @summary REGRESSION: Modal Dialog is not serializable after showing + * @key headful + * @run main ShownModalDialogSerializationTest + */ + +public class ShownModalDialogSerializationTest { + static volatile Frame frame; + static volatile Frame outputFrame; + static volatile Dialog dialog; + + public static void main(String[] args) throws Exception { + + EventQueue.invokeLater(ShownModalDialogSerializationTest::createTestUI); + + while (dialog == null || !dialog.isShowing()) { + Thread.sleep(500); + } + File file = new File("dialog.ser"); + FileOutputStream fos = new FileOutputStream(file); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(dialog); + oos.flush(); + file.delete(); + + EventQueue.invokeAndWait(ShownModalDialogSerializationTest::deleteTestUI); + } + + static void deleteTestUI() { + if (dialog != null) { + dialog.setVisible(false); + dialog.dispose(); + } + if (frame != null) { + frame.setVisible(false); + frame.dispose(); + } + if (outputFrame != null) { + outputFrame.setVisible(false); + outputFrame.dispose(); + } + } + + private static void createTestUI() { + outputFrame = new Frame("ShownModalDialogSerializationTest"); + TextArea output = new TextArea(40, 50); + outputFrame.add(output); + + frame = new Frame("invisible dialog owner"); + dialog = new Dialog(frame, "Dialog for Close", true); + dialog.add(new Label("Close This Dialog")); + outputFrame.setSize(200, 200); + outputFrame.setVisible(true); + dialog.pack(); + dialog.setVisible(true); + } +} diff --git a/test/jdk/java/awt/Dialog/TaskbarIconTest.java b/test/jdk/java/awt/Dialog/TaskbarIconTest.java new file mode 100644 index 0000000000000..2ced3853a0c06 --- /dev/null +++ b/test/jdk/java/awt/Dialog/TaskbarIconTest.java @@ -0,0 +1,145 @@ +/* + * 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 + * 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.Dialog; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.awt.print.PageFormat; +import java.awt.print.PrinterJob; + +/* + * @test + * @bug 6488834 + * @requires (os.family == "windows") + * @summary Tests that native dialogs (file, page, print) appear or + don't appear on the windows taskbar depending of their parent + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TaskbarIconTest +*/ + +public class TaskbarIconTest { + private static WindowListener wl = new WindowAdapter() { + public void windowClosing(WindowEvent we) { + Window w = we.getWindow(); + w.dispose(); + Window owner = w.getOwner(); + if (owner != null) { + owner.dispose(); + } + } + }; + + private static ActionListener al = new ActionListener() { + public void actionPerformed(ActionEvent ae) { + Button b = (Button) ae.getSource(); + + String bLabel = b.getLabel(); + boolean hasParent = (bLabel.indexOf("parentless") < 0); + Frame parent = hasParent ? new Frame("Parent") : null; + + if (bLabel.startsWith("Java")) { + Dialog d = new Dialog(parent, "Java dialog", true); + d.setBounds(0, 0, 160, 120); + d.addWindowListener(wl); + d.setVisible(true); + } else if (bLabel.startsWith("File")) { + FileDialog d = new FileDialog(parent, "File dialog"); + d.setVisible(true); + } else if (bLabel.startsWith("Print")) { + PrinterJob pj = PrinterJob.getPrinterJob(); + pj.printDialog(); + } else if (bLabel.startsWith("Page")) { + PrinterJob pj = PrinterJob.getPrinterJob(); + pj.pageDialog(new PageFormat()); + } + } + }; + + private static final String INSTRUCTIONS = """ + When the test starts a frame 'Main' is shown. It contains + several buttons, pressing each of them shows a dialog. + Some of the dialogs have a parent window, others are + parentless, according to the corresponding button's test. + + Press each button one after another. Make sure that all + parentless dialogs have an icon in the windows taskbar + and all the dialogs with parents don't. Press PASS or + FAIL button depending on the result. + + Note: as all the dialogs shown are modal, you have to close + them before showing the next dialog or PASS or FAIL buttons." + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("WindowInputBlock") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(TaskbarIconTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Button b; + + Frame mainFrame = new Frame("Main"); + mainFrame.setBounds(120, 240, 160, 240); + mainFrame.setLayout(new GridLayout(6, 1)); + + b = new Button("Java dialog, with parent"); + b.addActionListener(al); + mainFrame.add(b); + + b = new Button("Java dialog, parentless"); + b.addActionListener(al); + mainFrame.add(b); + + b = new Button("File dialog, with parent"); + b.addActionListener(al); + mainFrame.add(b); + + b = new Button("File dialog, parentless"); + b.addActionListener(al); + mainFrame.add(b); + + b = new Button("Print dialog, parentless"); + b.addActionListener(al); + mainFrame.add(b); + + b = new Button("Page dialog, parentless"); + b.addActionListener(al); + mainFrame.add(b); + + return mainFrame; + } +} diff --git a/test/jdk/java/awt/Dialog/TopmostModalDialogTest.java b/test/jdk/java/awt/Dialog/TopmostModalDialogTest.java new file mode 100644 index 0000000000000..7b91d47e248c4 --- /dev/null +++ b/test/jdk/java/awt/Dialog/TopmostModalDialogTest.java @@ -0,0 +1,152 @@ +/* + * 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. + */ + +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/* + * @test + * @bug 4940645 + * @summary Test to verify setAlwaysOnTop(true) does + * work in modal dialog in Windows + * @requires (os.family == "windows" | os.family == "linux" ) + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TopmostModalDialogTest + */ + +public class TopmostModalDialogTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + (This test verifies that modal dialog can be made always on top + This test should only be run on the platforms which support always-on-top windows + Such platforms are: Windows, Linux with GNOME2/Metacity window manager, + Solaris with GNOME2/Metacity window manager + If you are not running on any of these platforms, please select 'Pass' to skip testing + If you are unsure on which platform you are running please select 'Pass') + + 1. After test started you see a frame with \\"Main Frame\\" title + It contains three buttons. Every button starts one of test stage + You should test all three stages + 2. After you press button to start the stage. It shows modal dialog + This modal dialog should be always-on-top window + 3. Since it's a modal the only way to test this is try to cover it + using some native window + 4. If you will able to cover it be native window - test FAILS, otherwise - PASS + + Note: in stages #2 and #3 dialog is initially shown as regular modal dialogs + You will see \\"Let's wait\\" message in the message area below + Please wait until message \\"Let's make it topmost\\" will be printed in the area + After that you can continue testing. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(8) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + final Tester tester = new Tester(); + Frame frame = new Frame("Main Frame"); + frame.setLayout(new GridLayout(3, 1)); + for (int i = 0; i < 3; i++) { + Button btn = new Button("Stage #" + i); + frame.add(btn); + btn.addActionListener(tester); + } + frame.pack(); + return frame; + } +} + +class Tester implements ActionListener { + public void actionPerformed(ActionEvent e) { + String command = e.getActionCommand(); + PassFailJFrame.log(command); + int cmd = Integer.parseInt(command.substring(command.length() - 1)); + PassFailJFrame.log("" + cmd); + Dialog dlg = new Dialog(new Frame(""), "Modal Dialog", true); + dlg.setBounds(100, 100, 100, 100); + dlg.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent we) { + Window self = we.getWindow(); + Window owner = self.getOwner(); + if (owner != null) { + owner.dispose(); + } else { + self.dispose(); + } + } + }); + + switch (cmd) { + case 0: + dlg.setAlwaysOnTop(true); + dlg.setVisible(true); + break; + case 1: + (new Thread(new TopmostMaker(dlg))).start(); + dlg.setVisible(true); + break; + case 2: + dlg.setFocusableWindowState(false); + (new Thread(new TopmostMaker(dlg))).start(); + dlg.setVisible(true); + break; + default: + PassFailJFrame.log("Unsupported operation :("); + } + } +} + +class TopmostMaker implements Runnable { + final Window wnd; + + public TopmostMaker(Window wnd) { + this.wnd = wnd; + } + + public void run() { + PassFailJFrame.log("Let's wait"); + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + PassFailJFrame.log("Test was interrupted. " + ie); + ie.printStackTrace(); + } + PassFailJFrame.log("Let's make it topmost"); + wnd.setAlwaysOnTop(true); + } +} diff --git a/test/jdk/java/awt/Dialog/WindowInputBlock.java b/test/jdk/java/awt/Dialog/WindowInputBlock.java new file mode 100644 index 0000000000000..c38e8653ecc85 --- /dev/null +++ b/test/jdk/java/awt/Dialog/WindowInputBlock.java @@ -0,0 +1,134 @@ +/* + * 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.BorderLayout; +import java.awt.Color; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +/* + * @test + * @bug 4124096 + * @summary Modal JDialog is not modal on Solaris + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual WindowInputBlock + */ + +public class WindowInputBlock { + private static final String INSTRUCTIONS = """ + When the Window is up, you see a "Show Modal Dialog" button, a + "Test" button and a TextField. + Verify that the "Test" button is clickable, and the TextField can + receive focus. + + Now, click on "Show Modal Dialog" button to bring up a modal dialog + and verify that both "Test" button and TextField are not accessible. + Close the new dialog window. If the test behaved as described, pass + this test. Otherwise, fail this test. + + """; + + public static void main(String[] argv) throws Exception { + JFrame frame = new ModalDialogTest(); + PassFailJFrame.builder() + .title("WindowInputBlock") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(frame) + .build() + .awaitAndCheck(); + } +} + +class ModalDialogTest extends JFrame implements ActionListener { + JDialog dialog = new JDialog(new JFrame(), "Modal Dialog", true); + + public ModalDialogTest() { + setTitle("Modal Dialog Test"); + JPanel controlPanel = new JPanel(); + JPanel infoPanel = new JPanel(); + JButton showButton = new JButton("Show Modal Dialog"); + JButton testButton = new JButton("Test"); + JTextField textField = new JTextField("Test"); + + getContentPane().setLayout(new BorderLayout()); + infoPanel.setLayout(new GridLayout(0, 1)); + + showButton.setOpaque(true); + showButton.setBackground(Color.yellow); + + testButton.setOpaque(true); + testButton.setBackground(Color.pink); + + controlPanel.add(showButton); + controlPanel.add(testButton); + controlPanel.add(textField); + + infoPanel.add(new JLabel("Click the \"Show Modal Dialog\" button " + + "to display a modal JDialog.")); + infoPanel.add(new JLabel("Click the \"Test\" button to verify " + + "dialog modality.")); + + getContentPane().add(BorderLayout.NORTH, controlPanel); + getContentPane().add(BorderLayout.SOUTH, infoPanel); + dialog.setSize(200, 200); + + showButton.addActionListener(this); + testButton.addActionListener(this); + + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + System.exit(0); + } + + public void windowClosed(WindowEvent e) { + System.exit(0); + } + }); + + pack(); + setSize(450, 120); + } + + public void actionPerformed(ActionEvent evt) { + String command = evt.getActionCommand(); + + if (command == "Show Modal Dialog") { + System.out.println("*** Invoking JDialog.show() ***"); + dialog.setLocation(200, 200); + dialog.setVisible(true); + } else if (command == "Test") { + System.out.println("*** Test ***"); + } + } +} diff --git a/test/jdk/java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java b/test/jdk/java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java new file mode 100644 index 0000000000000..82ca54871848e --- /dev/null +++ b/test/jdk/java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java @@ -0,0 +1,97 @@ +/* + * 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 4212687 + * @summary Verifies that calling EventQueue.push() and EventQueue.pop() + * does not deadlock. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PushPopDeadlock + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Robot; +import java.awt.Toolkit; + +public class PushPopDeadlock { + static int counter = 0; + static Robot robot; + static Frame f; + static Label l; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + String INSTRUCTIONS = """ + Click rapidly in the Frame labeled 'Click Here!'. + The number in the Frame should continue to increase. If the number + stops increasing (remains at a constant value), the test fails. + """; + + PassFailJFrame pfJFrame = PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(PushPopDeadlock::createUI) + .build(); + PushPopDeadlock.test(); + pfJFrame.awaitAndCheck(); + } + + public static Frame createUI() { + f = new Frame("Click Here!"); + l = new Label("Counter: " + counter); + f.add(l); + f.setSize(200, 200); + return f; + } + + public static void test() { + EventQueue q = new EventQueue() { + public void push(EventQueue queue) { + super.push(queue); + pop(); + } + }; + EventQueue q2 = new EventQueue(); + + Toolkit.getDefaultToolkit().getSystemEventQueue().push(q); + + new Thread(() -> { + while (true) { + robot.delay(500); + l.setText("Counter: " + ++counter); + q.push(q2); + try { + Thread.currentThread().sleep(500); + } catch (InterruptedException e) { + return; + } + } + }).start(); + } +} diff --git a/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java b/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java new file mode 100644 index 0000000000000..5d3feaa42ed4b --- /dev/null +++ b/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6227750 + * @summary Tests that FileDialog can be closed by clicking the 'close' (X) button + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DoubleActionCloseX + */ + +public class DoubleActionCloseX { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + NOTE: On Linux and Mac, there is no 'close'(X) button + when file dialog is visible, press Pass. + + Click the 'Open File Dialog' button to open FileDialog. + A file dialog will appear on the screen. + Click on the 'close'(X) button. + The dialog should be closed. + If not, the test failed, press Fail otherwise press Pass. + """; + + PassFailJFrame.builder() + .title("DoubleActionCloseX Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(DoubleActionCloseX::createUI) + .build() + .awaitAndCheck(); + } + public static Frame createUI() { + Frame f = new Frame("DoubleActionCloseX Test"); + Button b = new Button("Open File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setVisible(true); + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/FileDialog/DoubleActionESC.java b/test/jdk/java/awt/FileDialog/DoubleActionESC.java new file mode 100644 index 0000000000000..748c3aeb5e446 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/DoubleActionESC.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; + +/* + * @test + * @bug 5097243 + * @summary Tests that FileDialog can be closed by ESC any time + * @key headful + * @run main DoubleActionESC + */ + +public class DoubleActionESC { + private static Frame f; + private static Button showBtn; + private static FileDialog fd; + private static Robot robot; + private static volatile Point p; + private static volatile Dimension d; + private static volatile CountDownLatch latch; + private static final int REPEAT_COUNT = 2; + + public static void main(String[] args) throws Exception { + latch = new CountDownLatch(1); + + robot = new Robot(); + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> { + createAndShowUI(); + }); + + robot.delay(1000); + EventQueue.invokeAndWait(() -> { + p = showBtn.getLocationOnScreen(); + d = showBtn.getSize(); + }); + + for (int i = 0; i < REPEAT_COUNT; ++i) { + Thread thread = new Thread(() -> { + robot.mouseMove(p.x + d.width / 2, p.y + d.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + }); + thread.start(); + robot.delay(3000); + + Thread thread1 = new Thread(() -> { + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.waitForIdle(); + }); + thread1.start(); + robot.delay(3000); + } + + latch.await(); + if (fd.isVisible()) { + throw new RuntimeException("File Dialog is not closed"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + public static void createAndShowUI() { + f = new Frame("DoubleActionESC Test"); + showBtn = new Button("Show File Dialog"); + fd = new FileDialog(f); + showBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == showBtn) { + fd.setSize(200, 200); + fd.setLocation(200, 200); + fd.setVisible(true); + latch.countDown(); + } + } + }); + f.add(showBtn); + f.setSize(300, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + } +} diff --git a/test/jdk/java/awt/FileDialog/KeyboardInteractionTest.java b/test/jdk/java/awt/FileDialog/KeyboardInteractionTest.java new file mode 100644 index 0000000000000..f919a8a338af8 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/KeyboardInteractionTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6259434 + * @summary PIT: Choice in FileDialog is not responding to keyboard interactions, XToolkit + * @requires (os.family == "linux") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual KeyboardInteractionTest + */ + +public class KeyboardInteractionTest { + public static void main(String[] args) throws Exception { + System.setProperty("sun.awt.disableGtkFileDialogs", "true"); + String INSTRUCTIONS = """ + 1) Click on 'Show File Dialog' button to bring up the FileDialog window. + A file dialog will come up. + 2) You will see a text field 'Enter full path or filename'. + Right next to it, you will see a button. + Transfer the focus on this button using 'TAB'. + Make sure that the popup choice is not shown. + 3) Press 'ESC'. If file dialog isn't disposed, then the test failed. + 4) Again, click on 'Show File Dialog' to bring up the file dialog. + A file dialog will come up. + 5) You will see a text field 'Enter full path or filename'. + Right next to it, you will see a button. + Click on this button. The popup choice will appear. + 6) Look at the popup choice. Change the current item in the popup + choice by the arrow keys. + If the text in the 'Enter full path or filename' text field isn't + changed, then the test failed. + 7) The test passed. + """; + + PassFailJFrame.builder() + .title("KeyboardInteractionTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(KeyboardInteractionTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("KeyboardInteractionTest Test"); + Button b = new Button("Show File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setVisible(true); + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/FileDialog/PathChoiceDisposeTest.java b/test/jdk/java/awt/FileDialog/PathChoiceDisposeTest.java new file mode 100644 index 0000000000000..267b2a807cff8 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/PathChoiceDisposeTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6240084 + * @summary Test that disposing unfurled list by the pressing ESC + * in FileDialog is working properly on XToolkit + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PathChoiceDisposeTest + */ + +public class PathChoiceDisposeTest { + public static void main(String[] args) throws Exception { + System.setProperty("sun.awt.disableGtkFileDialogs", "true"); + String INSTRUCTIONS = """ + 1) Click on 'Show File Dialog' button to bring up the FileDialog window. + 2) Open the directory selection choice by clicking button next to + 'Enter Path or Folder Name'. A drop-down will appear. + 3) Press 'ESC'. + 4) If you see that the dialog gets disposed and the popup + still remains on the screen, the test failed, otherwise passed. + """; + + PassFailJFrame.builder() + .title("PathChoiceDisposeTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(PathChoiceDisposeTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("PathChoiceDisposeTest Test"); + Button b = new Button("Show File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setVisible(true); + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/FileDialog/PathChoiceWorkArrowsTest.java b/test/jdk/java/awt/FileDialog/PathChoiceWorkArrowsTest.java new file mode 100644 index 0000000000000..17aee8abb800a --- /dev/null +++ b/test/jdk/java/awt/FileDialog/PathChoiceWorkArrowsTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6240074 + * @summary Test that file drop-down field in FileDialog is working properly on XToolkit + * @requires (os.family == "linux") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PathChoiceWorkArrowsTest + */ + +public class PathChoiceWorkArrowsTest { + public static void main(String[] args) throws Exception { + System.setProperty("sun.awt.disableGtkFileDialogs", "true"); + String INSTRUCTIONS = """ + This is only XAWT test. + + 1) Click on 'Show File Dialog' to bring up the FileDialog window. + A file dialog would come up. + 2) Click on the button next to 'Enter folder name' field. + A drop-down will appear. After this, there are 2 scenarios. + 3) Press the down arrow one by one. You will see a '/' being + appended as soon as the current entry is removed. + Keep pressing till the last entry is reached. Now the drop-down + will stop responding to arrow keys. If yes, the test failed. + 4) Press the up arrow. The cursor will directly go to the last + entry ('/') and navigation will stop there. You will see 2 + entries being selected at the same time. + If yes, the test failed. + """; + + PassFailJFrame.builder() + .title("PathChoiceWorkArrowsTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(PathChoiceWorkArrowsTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("PathChoiceWorkArrowsTest Test"); + Button b = new Button("Show File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setSize(200, 200); + fd.setLocation(200, 200); + fd.setVisible(true); + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/FileDialog/SavedDirInitTest.java b/test/jdk/java/awt/FileDialog/SavedDirInitTest.java new file mode 100644 index 0000000000000..7a3b33f55fe16 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/SavedDirInitTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6260650 + * @summary FileDialog.getDirectory() does not return null when file dialog is cancelled + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SavedDirInitTest + */ + +public class SavedDirInitTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click on 'Show File Dialog' button to bring up the FileDialog window. + 1) A file dialog will come up. + 2) Press 'Cancel' button to cancel the file dialog. + 3) The result (passed or failed) will be shown in the message window below. + """; + + PassFailJFrame.builder() + .title("SavedDirInitTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(SavedDirInitTest::createUI) + .logArea(2) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("SavedDirInitTest Test"); + Button b = new Button("Show File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setVisible(true); + if (fd.getDirectory() == null && fd.getFile() == null) { + PassFailJFrame.log("TEST PASSED"); + } else { + PassFailJFrame.log("TEST FAILED. dir = " + fd.getDirectory() + + " , file = " + fd.getFile()); + } + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java b/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java new file mode 100644 index 0000000000000..56b6c49214488 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4906972 + * @summary Tests using of JNI reference to peer object. + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestFileDialogDupJNIRef + */ + +public class TestFileDialogDupJNIRef { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This is a crash test. + After test started you will see 'Test Frame' with one button. + 1. Click the button to open FileDialog. + 2. Go to the dialog and choose any directory with some files in it.. + 3. Click on any file to highlight it. + 4. Click on the file again to rename. + 5. Leave the file in edit mode and click Open button + + If there was no crash the test passed, Press Pass. + """; + + PassFailJFrame.builder() + .title("TestFileDialogDupJNIRef Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TestFileDialogDupJNIRef::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame frame = new Frame("TestFileDialogDupJNIRef Test Frame"); + Button open = new Button("Open File Dialog"); + + open.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + FileDialog fd = new FileDialog(frame); + fd.setVisible(true); + } + }); + + frame.setLayout(new FlowLayout()); + frame.add(open); + frame.setSize(250, 70); + return frame; + } +} diff --git a/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java b/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java new file mode 100644 index 0000000000000..f5f1018c26282 --- /dev/null +++ b/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java @@ -0,0 +1,120 @@ +/* + * 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.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Robot; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/* + * @test + * @key headful + * @bug 4159883 + * @summary Adding/Removing a menu causes frame to unexpected small size + * @requires (os.family == "linux" | os.family == "windows") + */ + +public class AddRemoveMenuBarTest_5 { + + static Frame frame; + static MenuBar menu; + static Button btnAdd, btnRemove; + static Dimension oldSize; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(AddRemoveMenuBarTest_5::initAndShowGui); + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(() -> { + oldSize = frame.getSize(); + changeMenubar(true); + }); + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(() -> { + checkSize(); + changeMenubar(false); + }); + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(AddRemoveMenuBarTest_5::checkSize); + } finally { + EventQueue.invokeAndWait(frame::dispose); + } + } + + public static void initAndShowGui() { + frame = new Frame(); + frame.setLocationRelativeTo(null); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + System.out.println("Frame size:" + frame.getSize().toString()); + System.out.println("Button size:" + btnAdd.getSize().toString()); + } + }); + frame.add("West", btnAdd = new Button("TRY:ADD")); + frame.add("East", btnRemove = new Button("TRY:REMOVE")); + + + btnAdd.addActionListener((e) -> changeMenubar(true)); + btnRemove.addActionListener((e) -> changeMenubar(false)); + frame.setSize(500, 100); + frame.setVisible(true); + } + + private static void changeMenubar(boolean enable) { + if (enable) { + menu = new MenuBar(); + menu.add(new Menu("BAAAAAAAAAAAAAAA")); + menu.add(new Menu("BZZZZZZZZZZZZZZZ")); + menu.add(new Menu("BXXXXXXXXXXXXXXX")); + } else { + menu = null; + } + frame.setMenuBar(menu); + frame.invalidate(); + frame.validate(); + + System.out.println("Frame size:" + frame.getSize().toString()); + System.out.println("Button size:" + btnAdd.getSize().toString()); + } + + private static void checkSize() { + Dimension newSize = frame.getSize(); + if (!oldSize.equals(newSize)) { + throw new RuntimeException("Frame size changed: old %s new %s" + .formatted(oldSize, newSize)); + } + } +} diff --git a/test/jdk/java/awt/Frame/DefaultFrameIconTest.java b/test/jdk/java/awt/Frame/DefaultFrameIconTest.java index 3ca3b70dbd1a1..f8b48c6df2ca5 100644 --- a/test/jdk/java/awt/Frame/DefaultFrameIconTest.java +++ b/test/jdk/java/awt/Frame/DefaultFrameIconTest.java @@ -50,21 +50,11 @@ public static void main(String[] args) throws Exception { .instructions(INSTRUCTIONS) .columns(45) .testUI(DefaultFrameIconTest::createAndShowUI) - .positionTestUI(DefaultFrameIconTest::positionTestWindows) + .positionTestUIRightRow() .build() .awaitAndCheck(); } - private static void positionTestWindows(List testWindows, - PassFailJFrame.InstructionUI instructionUI) { - int gap = 5; - int x = instructionUI.getLocation().x + instructionUI.getSize().width + gap; - for (Window w : testWindows) { - w.setLocation(x, instructionUI.getLocation().y); - x += w.getWidth() + gap; - } - } - private static List createAndShowUI() { Frame testFrame = new Frame("Frame DefaultFrameIconTest"); Dialog testDialog = new Dialog(testFrame, "Dialog DefaultFrameIconTest"); diff --git a/test/jdk/java/awt/Frame/FocusTest.java b/test/jdk/java/awt/Frame/FocusTest.java new file mode 100644 index 0000000000000..14d194789fe94 --- /dev/null +++ b/test/jdk/java/awt/Frame/FocusTest.java @@ -0,0 +1,151 @@ +/* + * 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. + */ + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Window; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/* + * @test + * @bug 4140293 + * @summary Tests that focus is returned to the correct Component when a Frame + * is reactivated. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FocusTest + */ + +public class FocusTest { + private static final String INSTRUCTIONS = """ + Click on the bottom rectangle. Move the mouse slightly. + A focus rectangle should appear around the bottom rectangle. + + Now, deactivate the window and then reactivate it. + (You would click on the caption bar of another window, + and then on the caption bar of the FocusTest Frame.) + + If the focus rectangle appears again, the test passes. + If it does not appear, or appears around the top rectangle, + the test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FocusTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .logArea(6) + .testUI(FocusTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Window createAndShowUI() { + Frame frame = new Frame("FocusTest"); + + frame.add(new FocusTestPanel()); + frame.setSize(400, 400); + + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + frame.dispose(); + } + }); + + frame.validate(); + return frame; + } + + private static class FocusTestPanel extends Panel { + PassiveClient pc1 = new PassiveClient("pc1"); + PassiveClient pc2 = new PassiveClient("pc2"); + + public FocusTestPanel() { + super(); + setLayout(new GridLayout(2, 1, 10, 10)); + add(pc1); + add(pc2); + } + } + + private static class PassiveClient extends Canvas implements FocusListener { + boolean haveFocus = false; + final String name; + + PassiveClient(String name) { + super(); + this.name = name; + setSize(400, 100); + setBackground(Color.cyan); + setVisible(true); + setEnabled(true); + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + requestFocus(); + } + }); + addFocusListener(this); + } + + public void paint(Graphics g) { + g.setColor(getBackground()); + Dimension size = getSize(); + g.fillRect(0, 0, size.width, size.height); + if (haveFocus) { + g.setColor(Color.black); + g.drawRect(0, 0, size.width - 1, size.height - 1); + g.drawRect(1, 1, size.width - 3, size.height - 3); + } + g.setColor(getForeground()); + } + + public void focusGained(FocusEvent event) { + haveFocus = true; + paint(getGraphics()); + PassFailJFrame.log("<<<< %s Got focus!! %s>>>>".formatted(this, event)); + } + + public void focusLost(FocusEvent event) { + haveFocus = false; + paint(getGraphics()); + PassFailJFrame.log("<<<< %s Lost focus!! %s>>>>".formatted(this, event)); + } + + @Override + public String toString() { + return "PassiveClient " + name; + } + } +} diff --git a/test/jdk/java/awt/Frame/FrameMenuPackTest.java b/test/jdk/java/awt/Frame/FrameMenuPackTest.java new file mode 100644 index 0000000000000..c034acd8eb710 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameMenuPackTest.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.ScrollPane; +import java.awt.Window; +import java.util.List; + +/* + * @test + * @bug 4084766 + * @summary Test for bug(s): 4084766 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameMenuPackTest + */ + +public class FrameMenuPackTest { + private static final String INSTRUCTIONS = """ + Check that both frames that appear are properly packed with + the scrollpane visible. + """; + + public static void main(String[] argv) throws Exception { + PassFailJFrame.builder() + .title("FrameMenuPackTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(FrameMenuPackTest::createAndShowUI) + .positionTestUIRightRow() + .build() + .awaitAndCheck(); + } + + private static List createAndShowUI() { + // Frame without menu, packs correctly + PackedFrame f1 = new PackedFrame(false); + f1.pack(); + + // Frame with menu, doesn't pack right + PackedFrame f2 = new PackedFrame(true); + f2.pack(); + + return List.of(f1, f2); + } + + private static class PackedFrame extends Frame { + public PackedFrame(boolean withMenu) { + super("PackedFrame"); + + MenuBar menubar; + Menu fileMenu; + MenuItem foo; + ScrollPane sp; + + sp = new ScrollPane(); + sp.add(new Label("Label in ScrollPane")); + System.out.println(sp.getMinimumSize()); + + this.setLayout(new BorderLayout()); + this.add(sp, "Center"); + this.add(new Label("Label in Frame"), "South"); + + if (withMenu) { + menubar = new MenuBar(); + fileMenu = new Menu("File"); + foo = new MenuItem("foo"); + fileMenu.add(foo); + menubar.add(fileMenu); + this.setMenuBar(menubar); + } + } + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizableTest.java b/test/jdk/java/awt/Frame/FrameResizableTest.java new file mode 100644 index 0000000000000..4734ce71670aa --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizableTest.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.Label; +import java.awt.Panel; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 1231233 + * @summary Tests whether the resizable property of a Frame is + * respected after it is set. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizableTest + */ + +public class FrameResizableTest { + private static final String INSTRUCTIONS = """ + There is a frame with two buttons and a label. The label + reads 'true' or 'false' to indicate whether the frame can be + resized or not. + + When the first button, 'Set Resizable', is + clicked, you should be able to resize the frame. + When the second button, 'UnSet Resizable', is clicked, you should + not be able to resize the frame. + + A frame is resized in a way which depends upon the window manager (WM) running. + You may resize the frame by dragging the corner resize handles or the borders, + or you may use the title bar's resize menu items and buttons. + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FrameResizableTest Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(FrameResizable::new) + .build() + .awaitAndCheck(); + } + + private static class FrameResizable extends Frame { + Label label; + Button buttonResizable; + Button buttonNotResizable; + + public FrameResizable() { + super("FrameResizable"); + setResizable(false); + Panel panel = new Panel(); + + add("North", panel); + ActionListener actionListener = (e) -> { + if (e.getSource() == buttonResizable) { + setResizable(true); + } else if (e.getSource() == buttonNotResizable) { + setResizable(false); + } + label.setText("Resizable: " + isResizable()); + }; + + panel.add(buttonResizable = new Button("Set Resizable")); + panel.add(buttonNotResizable = new Button("UnSet Resizable")); + panel.add(label = new Label("Resizable: " + isResizable())); + buttonResizable.addActionListener(actionListener); + buttonNotResizable.addActionListener(actionListener); + + setSize(400, 200); + } + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_3.java b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_3.java new file mode 100644 index 0000000000000..6fdef005775a5 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_3.java @@ -0,0 +1,86 @@ +/* + * 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 + * 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.GridLayout; +import java.awt.Window; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4097207 + * @summary setSize() on a Frame does not resize its content + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizeTest_3 +*/ + +public class FrameResizeTest_3 { + + private static final String INSTRUCTIONS = """ + 1. You would see a frame titled 'TestFrame' with 2 buttons + named 'setSize(500,500)' and 'setSize(400,400)' + 2. Click any button and you would see the frame resized + 3. If the buttons get resized along with the frame + (ie., to fit the frame), press Pass else press Fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FrameResizeTest_3 Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .logArea(6) + .testUI(FrameResizeTest_3::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Window createTestUI() { + Frame frame = new Frame("TestFrame"); + frame.setLayout(new GridLayout(2, 1)); + + Button butSize500 = new Button("setSize(500,500)"); + Button butSize400 = new Button("setSize(400,400)"); + + ActionListener actionListener = e -> { + if (e.getSource() instanceof Button) { + if (e.getSource() == butSize500) { + frame.setSize(500, 500); + PassFailJFrame.log("New bounds: " + frame.getBounds()); + } else if (e.getSource() == butSize400) { + frame.setSize(400, 400); + PassFailJFrame.log("New bounds: " + frame.getBounds()); + } + } + }; + butSize500.addActionListener(actionListener); + butSize400.addActionListener(actionListener); + frame.add(butSize500); + frame.add(butSize400); + + frame.setSize(270, 200); + return frame; + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_4.java b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_4.java new file mode 100644 index 0000000000000..4428feee3355b --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_4.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +/* Note that although this test makes use of Swing classes, like JFrame and */ +/* JButton, it is really an AWT test, because it tests mechanism of sending */ +/* paint events. */ + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import java.awt.BorderLayout; + +/* + * @test + * @bug 4174831 + * @summary Tests that frame do not flicker on diagonal resize + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizeTest_4 + */ + +public class FrameResizeTest_4 { + private static final String INSTRUCTIONS = """ + Try enlarging the frame diagonally. + If buttons inside frame excessively repaint themselves and flicker + while you enlarge frame, the test fails. + Otherwise, it passes. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FrameResizeTest_4 Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(FrameResizeTest_4::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame f = new JFrame("FrameResizeTest_4 Flickering Frame"); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(new JButton("West"), BorderLayout.WEST); + panel.add(new JButton("East"), BorderLayout.EAST); + panel.add(new JButton("North"), BorderLayout.NORTH); + panel.add(new JButton("South"), BorderLayout.SOUTH); + panel.add(new JButton("Center"), BorderLayout.CENTER); + f.setContentPane(panel); + + f.pack(); + f.setBounds(100, 50, 300, 200); + + return f; + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_5.java b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_5.java new file mode 100644 index 0000000000000..5a43b755a5212 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_5.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; + +/* + * @test + * @summary Test to make sure non-resizable Frames can be resized with the + * setSize() method. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizeTest_5 +*/ + +public class FrameResizeTest_5 { + private static final String INSTRUCTIONS = """ + This tests the programmatic resizability of non-resizable Frames. + Even when a Frame is set to be non-resizable, it should still be + programmatically resizable using the setSize() method. + + Initially the Frame will be resizable. Try using the "Smaller" + and "Larger" buttons to verify that the Frame resizes correctly. + Then, click the "Toggle" button to make the Frame non-resizable. + Again, verify that clicking the "Larger" and "Smaller" buttons + causes the Frame to get larger and smaller. If the Frame does + not change size, or does not re-layout correctly, the test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FrameResizeTest_5 Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .logArea(6) + .testUI(TestFrame::new) + .build() + .awaitAndCheck(); + } + + private static class TestFrame extends Frame { + Button bLarger, bSmaller, bCheck, bToggle; + + public TestFrame() { + super("Frame Resize Test"); + setSize(200, 200); + bLarger = new Button("Larger"); + bLarger.addActionListener(e -> { + setSize(400, 400); + validate(); + }); + bSmaller = new Button("Smaller"); + bSmaller.addActionListener(e -> { + setSize(200, 100); + validate(); + }); + bCheck = new Button("Resizable?"); + bCheck.addActionListener(e -> { + if (isResizable()) { + PassFailJFrame.log("Frame is resizable"); + setResizable(true); + } else { + PassFailJFrame.log("Frame is not resizable"); + setResizable(false); + } + }); + bToggle = new Button("Toggle"); + bToggle.addActionListener(e -> { + if (isResizable()) { + PassFailJFrame.log("Frame is now not resizable"); + setResizable(false); + } else { + PassFailJFrame.log("Frame is now resizable"); + setResizable(true); + } + }); + setLayout(new GridLayout(4, 1)); + add(bSmaller); + add(bLarger); + add(bCheck); + add(bToggle); + } + } +} diff --git a/test/jdk/java/awt/Frame/I18NTitle.java b/test/jdk/java/awt/Frame/I18NTitle.java new file mode 100644 index 0000000000000..7127fc3dfbf6b --- /dev/null +++ b/test/jdk/java/awt/Frame/I18NTitle.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Window; + +/* + * @test + * @bug 6269884 4929291 + * @summary Tests that title which contains mix of non-English characters is displayed correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual I18NTitle + */ + +public class I18NTitle { + private static final String INSTRUCTIONS = """ + You will see a frame with some title (S. Chinese, Cyrillic and German). + Please check if non-English characters are visible and compare + the visible title with the same string shown in the label + (it should not look worse than the label). + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("I18NTitle Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(I18NTitle::createAndShowGUI) + .build() + .awaitAndCheck(); + } + + private static Window createAndShowGUI() { + String s = "\u4e2d\u6587\u6d4b\u8bd5 \u0420\u0443\u0441\u0441\u043a\u0438\u0439 Zur\u00FCck"; + Frame frame = new Frame(s); + frame.setLayout(new BorderLayout()); + Label l = new Label(s); + frame.add(l); + frame.setSize(400, 100); + return frame; + } +} diff --git a/test/jdk/java/awt/Frame/InitialIconifiedTest.java b/test/jdk/java/awt/Frame/InitialIconifiedTest.java index f3f43929e7b16..4a8d959566575 100644 --- a/test/jdk/java/awt/Frame/InitialIconifiedTest.java +++ b/test/jdk/java/awt/Frame/InitialIconifiedTest.java @@ -50,36 +50,75 @@ public class InitialIconifiedTest { private static Robot robot; + private static final StringBuilder FAILURES = new StringBuilder(); + public static void main(String[] args) throws Exception { robot = new Robot(); - try { - EventQueue.invokeAndWait(InitialIconifiedTest::initAndShowGui); + EventQueue.invokeAndWait(InitialIconifiedTest::initAndShowBackground); robot.waitForIdle(); robot.delay(500); - test(); + + test(false); + test(true); } finally { EventQueue.invokeAndWait(() -> { backgroundFrame.dispose(); testedFrame.dispose(); }); } + + if (!FAILURES.isEmpty()) { + throw new RuntimeException(FAILURES.toString()); + } + } + + private static void test(boolean isUndecorated) throws Exception { + String prefix = isUndecorated ? "undecorated" : "decorated"; + + EventQueue.invokeAndWait(() -> initAndShowTestedFrame(isUndecorated)); + // On macos, we can observe the animation of the window from the initial + // NORMAL state to the ICONIFIED state, + // even if the window was created in the ICONIFIED state. + // The following delay is commented out to capture this animation + // robot.waitForIdle(); + // robot.delay(500); + if (!testIfIconified(prefix + "_no_extra_delay")) { + FAILURES.append("Case %s frame with no extra delay failed\n" + .formatted(isUndecorated ? "undecorated" : "decorated")); + } + + EventQueue.invokeAndWait(() -> initAndShowTestedFrame(isUndecorated)); + robot.waitForIdle(); + robot.delay(500); + if (!testIfIconified(prefix + "_with_extra_delay")) { + FAILURES.append("Case %s frame with extra delay failed\n" + .formatted(isUndecorated ? "undecorated" : "decorated")); + } } - private static void initAndShowGui() { + private static void initAndShowBackground() { backgroundFrame = new Frame("DisposeTest background"); backgroundFrame.setUndecorated(true); backgroundFrame.setBackground(Color.RED); backgroundFrame.setBounds(backgroundFrameBounds); backgroundFrame.setVisible(true); + } + private static void initAndShowTestedFrame(boolean isUndecorated) { + if (testedFrame != null) { + testedFrame.dispose(); + } testedFrame = new Frame("Should have started ICONIC"); + if (isUndecorated) { + testedFrame.setUndecorated(true); + } testedFrame.setExtendedState(Frame.ICONIFIED); testedFrame.setBounds(testedFrameBounds); testedFrame.setVisible(true); } - private static void test() { + private static boolean testIfIconified(String prefix) { BufferedImage bi = robot.createScreenCapture(backgroundFrameBounds); int redPix = Color.RED.getRGB(); @@ -88,11 +127,12 @@ private static void test() { if (bi.getRGB(x, y) != redPix) { try { ImageIO.write(bi, "png", - new File("failure.png")); + new File(prefix + "_failure.png")); } catch (IOException ignored) {} - throw new RuntimeException("Test failed"); + return false; } } } + return true; } } diff --git a/test/jdk/java/awt/Frame/MenuBarOffsetTest.java b/test/jdk/java/awt/Frame/MenuBarOffsetTest.java new file mode 100644 index 0000000000000..65a4a8ef4bd59 --- /dev/null +++ b/test/jdk/java/awt/Frame/MenuBarOffsetTest.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Menu; +import java.awt.MenuBar; + +/* + * @test + * @bug 4180577 + * @summary offset problems with menus in frames: (2 * 1) should be (2 * menuBarBorderSize) + * @requires (os.family == "linux" | os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarOffsetTest +*/ + +public class MenuBarOffsetTest { + private static final String INSTRUCTIONS = """ + If a menubar containing a menubar item labeled Test appears. + in a frame, and fits within the frame, press Pass, else press Fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("MenuBarOffsetTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(FrameTest::new) + .build() + .awaitAndCheck(); + } + + private static class FrameTest extends Frame { + public FrameTest() { + super("MenuBarOffsetTest FrameTest"); + MenuBar m = new MenuBar(); + setMenuBar(m); + Menu test = m.add(new Menu("Test")); + test.add("1"); + test.add("2"); + setSize(100, 100); + } + + public void paint(Graphics g) { + setForeground(Color.red); + Insets i = getInsets(); + Dimension d = getSize(); + System.err.println(getBounds()); + System.err.println("" + i); + + g.drawRect(i.left, i.top, + d.width - i.left - i.right - 1, + d.height - i.top - i.bottom - 1); + } + } +} diff --git a/test/jdk/java/awt/Frame/MenuCrash.java b/test/jdk/java/awt/Frame/MenuCrash.java index f41408ecdadfb..f68dd4ad00002 100644 --- a/test/jdk/java/awt/Frame/MenuCrash.java +++ b/test/jdk/java/awt/Frame/MenuCrash.java @@ -62,7 +62,7 @@ public static void main(String[] args) throws Exception { .instructions(INSTRUCTIONS) .columns(45) .testUI(MenuCrash::createAndShowUI) - .positionTestUI(MenuCrash::positionTestWindows) + .positionTestUIRightRow() .build() .awaitAndCheck(); } @@ -81,16 +81,6 @@ private static List createAndShowUI() { return List.of(frame1, frame2); } - private static void positionTestWindows(List testWindows, - PassFailJFrame.InstructionUI instructionUI) { - int gap = 5; - int x = instructionUI.getLocation().x + instructionUI.getSize().width + gap; - for (Window w : testWindows) { - w.setLocation(x, instructionUI.getLocation().y); - x += w.getWidth() + gap; - } - } - static class MenuFrame extends Frame { private final TextField field; diff --git a/test/jdk/java/awt/Frame/MinimumSizeTest.java b/test/jdk/java/awt/Frame/MinimumSizeTest.java new file mode 100644 index 0000000000000..cfff77be5f93c --- /dev/null +++ b/test/jdk/java/awt/Frame/MinimumSizeTest.java @@ -0,0 +1,114 @@ +/* + * 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 javax.imageio.ImageIO; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +/* + * @test + * @key headful + * @bug 1256759 + * @summary Checks that Frames with a very small size don't cause Motif + * to generate VendorShells which consume the entire desktop. + */ + +public class MinimumSizeTest { + + private static final Color BG_COLOR = Color.RED; + private static Frame backgroundFrame; + private static Frame testedFrame; + + private static Robot robot; + private static final Point location = new Point(200, 200); + private static final Point[] testPointLocations = { + new Point(100, 200), + new Point(200, 100), + new Point(450, 210), + new Point(210, 350), + }; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + + try { + EventQueue.invokeAndWait(MinimumSizeTest::initAndShowGui); + robot.waitForIdle(); + robot.delay(500); + test(); + System.out.println("Test passed."); + } finally { + EventQueue.invokeAndWait(() -> { + backgroundFrame.dispose(); + testedFrame.dispose(); + }); + } + } + + private static void test() { + for (Point testLocation : testPointLocations) { + Color pixelColor = robot.getPixelColor(testLocation.x, testLocation.y); + + if (!pixelColor.equals(BG_COLOR)) { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + BufferedImage screenCapture = robot.createScreenCapture(new Rectangle(screenSize)); + try { + ImageIO.write(screenCapture, "png", new File("failure.png")); + } catch (IOException ignored) {} + throw new RuntimeException("Pixel color does not match expected color %s at %s" + .formatted(pixelColor, testLocation)); + } + } + } + + private static void initAndShowGui() { + backgroundFrame = new Frame("MinimumSizeTest background"); + backgroundFrame.setUndecorated(true); + backgroundFrame.setBackground(BG_COLOR); + backgroundFrame.setBounds(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())); + backgroundFrame.setVisible(true); + + testedFrame = new MinimumSizeTestFrame(); + testedFrame.setVisible(true); + } + + private static class MinimumSizeTestFrame extends Frame { + public MinimumSizeTestFrame() { + super("MinimumSizeTest"); + setVisible(true); + setBackground(Color.BLUE); + setSize(0, 0); + setLocation(location); + } + } +} + diff --git a/test/jdk/java/awt/GradientPaint/JerkyGradient.java b/test/jdk/java/awt/GradientPaint/JerkyGradient.java new file mode 100644 index 0000000000000..dc33b9c185af8 --- /dev/null +++ b/test/jdk/java/awt/GradientPaint/JerkyGradient.java @@ -0,0 +1,125 @@ +/* + * 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 4221201 + * @summary Test where the gradient drawn should remain in sync with the + * rotating rectangle. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual JerkyGradient + */ + +import java.awt.Color; +import java.awt.Frame; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Panel; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; + +public class JerkyGradient extends Panel implements Runnable { + protected static Shape mShape; + protected static Paint mPaint; + protected static double mTheta; + static Thread animatorThread; + static BufferedImage mImg; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Watch at least one full rotation of the rectangle. Check that + the gradient drawn remains in sync with the rotating + rectangle. If so, pass this test. Otherwise, fail this test. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(JerkyGradient::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Rotating Gradient Test"); + JerkyGradient jg = new JerkyGradient(); + f.add(jg); + f.setSize(200, 200); + return f; + } + + public JerkyGradient() { + mShape = new Rectangle2D.Double(60, 50, 80, 100); + mPaint = new GradientPaint(0, 0, Color.red, + 25, 25, Color.yellow, + true); + mImg = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); + + animatorThread = new Thread(this); + animatorThread.setPriority(Thread.MIN_PRIORITY); + animatorThread.start(); + } + + public synchronized void run() { + Thread me = Thread.currentThread(); + double increment = Math.PI / 36; + double twoPI = Math.PI * 2; + + while (animatorThread == me) { + mTheta = (mTheta + increment) % twoPI; + repaint(); + try { + wait(50); + } catch (InterruptedException ie) { + break; + } + } + } + + public void update(Graphics g) { + Graphics2D g2 = mImg.createGraphics(); + g2.setColor(getBackground()); + g2.fillRect(0, 0, 200, 200); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2.rotate(mTheta, 100, 100); + g2.setPaint(Color.black); + g2.drawLine(100, 30, 100, 55); + g2.setPaint(mPaint); + g2.fill(mShape); + g2.setPaint(Color.black); + g2.draw(mShape); + paint(g); + g2.dispose(); + } + + public void paint(Graphics g) { + g.drawImage(mImg, 0, 0, null); + } +} diff --git a/test/jdk/java/awt/GradientPaint/ShearTest.java b/test/jdk/java/awt/GradientPaint/ShearTest.java new file mode 100644 index 0000000000000..95a4e4a6dcd3e --- /dev/null +++ b/test/jdk/java/awt/GradientPaint/ShearTest.java @@ -0,0 +1,137 @@ +/* + * 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 4171820 + * @summary Checks that GradientPaint responds to shearing transforms correctly + * The gradients drawn should be parallel to the sides of the + * indicated anchor rectangle. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ShearTest + */ + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; + +public class ShearTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test displays 2 rows each containing 4 gradient fills. Each + gradient fill is labeled depending on whether the line or lines + of the gradient should be truly vertical, truly horizontal, or + some slanted diagonal direction. The test passes if the direction + of each gradient matches its label. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ShearTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Shear Gradient Test"); + f.setLayout(new GridLayout(0, 1)); + f.add(getPanelSet(false), "North"); + f.add(getPanelSet(true), "Center"); + f.setSize(500, 300); + return f; + } + + public static Panel getPanelSet(boolean horizontal) { + String direven = horizontal ? "Slanted" : "Vertical"; + String dirodd = horizontal ? "Horizontal" : "Slanted"; + + Panel p = new Panel(); + p.setLayout(new GridLayout(0, 4)); + p.add(new ShearCanvas(direven, false, horizontal, false, true)); + p.add(new ShearCanvas(dirodd, false, horizontal, true, false)); + p.add(new ShearCanvas(direven, true, horizontal, false, true)); + p.add(new ShearCanvas(dirodd, true, horizontal, true, false)); + + return p; + } + + public static class ShearCanvas extends Canvas { + public static final int GRADW = 30; + + public static final Rectangle anchor = + new Rectangle(-GRADW / 2, -GRADW / 2, GRADW, GRADW); + + public static final Color faintblue = new Color(0f, 0f, 1.0f, 0.35f); + + private AffineTransform txform; + private GradientPaint grad; + private String label; + + public ShearCanvas(String label, + boolean cyclic, boolean horizontal, + boolean shearx, boolean sheary) { + txform = new AffineTransform(); + if (shearx) { + txform.shear(-.5, 0); + } + if (sheary) { + txform.shear(0, -.5); + } + int relx = horizontal ? 0 : GRADW / 2; + int rely = horizontal ? GRADW / 2 : 0; + grad = new GradientPaint(-relx, -rely, Color.green, + relx, rely, Color.yellow, cyclic); + this.label = label; + } + + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + + AffineTransform at = g2d.getTransform(); + g2d.translate(75, 75); + g2d.transform(txform); + g2d.setPaint(grad); + g2d.fill(g.getClip()); + g2d.setColor(faintblue); + g2d.fill(anchor); + g2d.setTransform(at); + + Dimension d = getSize(); + g2d.setColor(Color.black); + g2d.drawRect(0, 0, d.width - 1, d.height - 1); + g2d.drawString(label, 5, d.height - 5); + g2d.dispose(); + } + } +} diff --git a/test/jdk/java/awt/Graphics2D/BasicStrokeValidate.java b/test/jdk/java/awt/Graphics2D/BasicStrokeValidate.java new file mode 100644 index 0000000000000..251f14e5081bd --- /dev/null +++ b/test/jdk/java/awt/Graphics2D/BasicStrokeValidate.java @@ -0,0 +1,87 @@ +/* + * 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 + * 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 4363534 + * @summary This test verifies that setting a non-thin-line BasicStroke + * on a Graphics2D obtained from a BufferedImage will correctly validate + * the pipelines for the line-widening pipeline even if that is the only + * non-default attribute on the graphics. + * + */ + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; + +public class BasicStrokeValidate { + + public static final int TESTW = 100; + public static final int TESTH = 100; + + public static void main(String[] args) { + BufferedImage bi1 = createImage(false); + BufferedImage bi2 = createImage(true); + compare(bi1, bi2); // images should differ + } + + static BufferedImage createImage(boolean dashed) { + BufferedImage bi = new BufferedImage(TESTW, TESTH, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = bi.createGraphics(); + g2d.setColor(Color.white); + g2d.fillRect(0, 0, TESTW, TESTH); + g2d.setColor(Color.black); + if (dashed) { + g2d.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, + BasicStroke.JOIN_MITER, 10.0f, + new float[] {2.5f, 3.5f}, + 0.0f)); + } + g2d.drawRect(10, 10, TESTW-20, TESTH-20); + g2d.setStroke(new BasicStroke(10f)); + g2d.drawRect(20, 20, TESTW-40, TESTH-40); + return bi; + } + + static void compare(BufferedImage i1, BufferedImage i2) { + boolean same = true; + int w = i1.getWidth(), h = i1.getHeight(); + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int p1 = i1.getRGB(x, y); + int p2 = i2.getRGB(x, y); + if (p1 != p2) { + same = false; + } + } + if (!same) { + break; + } + } + if (same) { + throw new RuntimeException("No difference"); + } + } +} diff --git a/test/jdk/java/awt/Graphics2D/DrawImageIAETest/DrawImageIAETest.java b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/DrawImageIAETest.java new file mode 100644 index 0000000000000..af7ebae72a6c8 --- /dev/null +++ b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/DrawImageIAETest.java @@ -0,0 +1,169 @@ +/* + * 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 4191004 + * @summary Tests that no IllegalArgumentException is thrown when calling + * drawImage with certain conditions + * @key headful + */ + +import java.awt.AlphaComposite; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.awt.geom.GeneralPath; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.JFrame; +import javax.swing.JPanel; + +public class DrawImageIAETest extends Frame { + + static String filename = "/duke.gif"; + private volatile Image dimg; + private volatile BufferedImage bimg; + static volatile DrawImageIAETest app; + static volatile JFrame jframe; + static volatile boolean passed = true; + static volatile Exception exception = null; + static volatile CountDownLatch imageLatch = new CountDownLatch(1); + + DrawImageIAETest(String title) { + super(title); + } + + public static void main(final String[] args) throws Exception { + EventQueue.invokeAndWait(DrawImageIAETest:: createUI); + imageLatch.await(3, TimeUnit.MILLISECONDS); + try { + if (!passed) { + throw new RuntimeException("Test FAILED: exception caught:" + exception); + } + } finally { + if (jframe != null) { + EventQueue.invokeAndWait(jframe::dispose); + } + if (app != null) { + EventQueue.invokeAndWait(app::dispose); + } + } + } + + static void createUI() { + app = new DrawImageIAETest("DrawImageIAETest"); + app.setLayout (new BorderLayout()); + app.setSize(200,200); + app.setLocationRelativeTo(null); + app.setVisible(true); + + String file; + try { + String dir = System.getProperty("test.src", + System.getProperty("user.dir")); + file = dir + filename; + } catch (Exception e) { + file = "." + filename; + } + + Image textureAlphaSource = null; + MediaTracker tracker = new MediaTracker(app); + app.dimg = Toolkit.getDefaultToolkit().getImage(file); + tracker.addImage(app.dimg, 1); + try { + tracker.waitForAll(); + imageLatch.countDown(); + } catch (Exception e) { + System.err.println("Can't load images"); + } + + if (app.dimg == null) { + passed = false; + return; + } + + jframe = new JFrame("Test DrawImageIAETest"); + jframe.setSize(300, 300); + JPanel jpanel; + jframe.getContentPane().add("Center", jpanel = new JPanel() { + public void paint(Graphics _g) { + Graphics2D g = (Graphics2D)_g; + Dimension d = getSize(); + Graphics2D g2 = app.createGraphics2D(d.width, d.height); + app.drawDemo(d.width, d.height, g2); + g2.dispose(); + g.drawImage(app.bimg, 0, 0, app); + } + }); + jpanel.setSize(140, 140); + jframe.setVisible(true); + } + + public void drawDemo(int w, int h, Graphics2D g2) { + GeneralPath p1 = new GeneralPath(); + GeneralPath p2 = new GeneralPath(); + + int dukeX = 73; + int dukeY = 26; + + double x = 118; + double y = 17; + double ew = 50; + double eh = 48; + + p1.append(new Ellipse2D.Double(x, y, ew, eh), false); + p2.append(new Rectangle2D.Double(x+5, y+5, ew-10, eh-10),false); + + g2.setClip(p1); + g2.clip(p2); + try { + g2.drawImage(dimg, dukeX, dukeY, null); + } catch (IllegalArgumentException e) { + passed = false; + exception = e; + } + } + + public Graphics2D createGraphics2D(int w, int h) { + Graphics2D g2 = null; + if (bimg == null || bimg.getWidth() != w || bimg.getHeight() != h) { + bimg = (BufferedImage) createImage(w, h); + } + g2 = bimg.createGraphics(); + g2.setBackground(getBackground()); + g2.clearRect(0, 0, w, h); + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); + return g2; + } +} diff --git a/test/jdk/java/awt/Graphics2D/DrawImageIAETest/duke.gif b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/duke.gif new file mode 100644 index 0000000000000..ed32e0ff79b05 Binary files /dev/null and b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/duke.gif differ diff --git a/test/jdk/java/awt/Graphics2D/ImageRendering/ImageRendering.java b/test/jdk/java/awt/Graphics2D/ImageRendering/ImageRendering.java new file mode 100644 index 0000000000000..209a93e92d50f --- /dev/null +++ b/test/jdk/java/awt/Graphics2D/ImageRendering/ImageRendering.java @@ -0,0 +1,66 @@ +/* + * 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 4203598 + * @summary This test verifies that an image with transparent background can be displayed + * correctly with the red background color given. + * The correct display should be the sleeping Duke on a red background. + * + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class ImageRendering { + + public static void main(String[] args) throws Exception { + + String imgName = "snooze.gif"; + File file = new File(System.getProperty("test.src", "."), imgName); + BufferedImage image = ImageIO.read(file); + int w = image.getWidth(); + int h = image.getHeight(); + BufferedImage dest = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = dest.createGraphics(); + g2d.drawImage(image, 0, 0, Color.red, null); + int redPixel = Color.red.getRGB(); + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int srcPixel = image.getRGB(x, y); + if ((srcPixel & 0x0ff000000) == 0) { + int destPix = dest.getRGB(x, y); + if (destPix != redPixel) { + throw new RuntimeException("Not red at x=" + x + + " y=" + y + + "pix = " + Integer.toHexString(destPix)); + } + } + } + } + } +} diff --git a/test/jdk/java/awt/Graphics2D/ImageRendering/snooze.gif b/test/jdk/java/awt/Graphics2D/ImageRendering/snooze.gif new file mode 100644 index 0000000000000..e357e316cdbef Binary files /dev/null and b/test/jdk/java/awt/Graphics2D/ImageRendering/snooze.gif differ diff --git a/test/jdk/java/awt/Graphics2D/LargeWindowPaintTest.java b/test/jdk/java/awt/Graphics2D/LargeWindowPaintTest.java index 991c22938b8a3..2c61a29aacba8 100644 --- a/test/jdk/java/awt/Graphics2D/LargeWindowPaintTest.java +++ b/test/jdk/java/awt/Graphics2D/LargeWindowPaintTest.java @@ -33,25 +33,14 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @bug 8240654 * @summary Test painting a large window works * @key headful * @requires (os.family == "windows") - * @requires vm.gc.ZSinglegen - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Dsun.java2d.uiScale=1 LargeWindowPaintTest - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Dsun.java2d.uiScale=1 -Dsun.java2d.d3d=false LargeWindowPaintTest - */ - -/* - * @test id=ZGenerational - * @bug 8240654 - * @summary Test painting a large window works - * @key headful - * @requires (os.family == "windows") - * @requires vm.gc.ZGenerational - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Dsun.java2d.uiScale=1 LargeWindowPaintTest - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Dsun.java2d.uiScale=1 -Dsun.java2d.d3d=false LargeWindowPaintTest + * @requires vm.gc.Z + * @run main/othervm -XX:+UseZGC -Dsun.java2d.uiScale=1 LargeWindowPaintTest + * @run main/othervm -XX:+UseZGC -Dsun.java2d.uiScale=1 -Dsun.java2d.d3d=false LargeWindowPaintTest */ import java.awt.Color; diff --git a/test/jdk/java/awt/Graphics2D/ScaledThinLineTest.java b/test/jdk/java/awt/Graphics2D/ScaledThinLineTest.java new file mode 100644 index 0000000000000..fd4a5dd5e7ca9 --- /dev/null +++ b/test/jdk/java/awt/Graphics2D/ScaledThinLineTest.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 4210466 4417756 + * @summary thin lines are not draw correctly under large scales + */ +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.image.BufferedImage; +import java.awt.geom.Ellipse2D; + +public class ScaledThinLineTest { + + public static void main(String[] args) { + ScaledThinLineTest c1 = new ScaledThinLineTest(200, 200); + ScaledThinLineTest c2 = new ScaledThinLineTest(1, 10000); + ScaledThinLineTest c3 = new ScaledThinLineTest(10000, 1); + ScaledThinLineTest c4 = new ScaledThinLineTest(0.01, 10000); + ScaledThinLineTest c5 = new ScaledThinLineTest(10000, 0.01); + compare(c1.bi, c2.bi); + compare(c2.bi, c3.bi); + compare(c3.bi, c4.bi); + compare(c4.bi, c5.bi); + } + + private final Shape shape; + private final double scaleX,scaleY; + private BufferedImage bi = null; + + public ScaledThinLineTest(double width, double height) { + shape = new Ellipse2D.Double(0.25*width, 0.25*height, width, height); + scaleX = 200/width; + scaleY = 200/height; + int iw = 300, ih = 300; + bi = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB); + Graphics2D g2 = bi.createGraphics(); + g2.setColor(Color.white); + g2.fillRect(0, 0, iw, ih); + g2.setColor(Color.black); + g2.scale(scaleX,scaleY); + g2.setStroke(new BasicStroke(0)); + g2.draw(shape); + } + + + static void compare(BufferedImage i1, BufferedImage i2) { + int w = i1.getWidth(), h = i1.getHeight(); + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int p1 = i1.getRGB(x, y); + int p2 = i2.getRGB(x, y); + if (p1 != p2) { + System.out.println("images differ at " + x + " " + y); + } + } + } + } +} diff --git a/test/jdk/java/awt/Graphics2D/TextPerf.java b/test/jdk/java/awt/Graphics2D/TextPerf.java new file mode 100644 index 0000000000000..d3e5cc2d4d0dd --- /dev/null +++ b/test/jdk/java/awt/Graphics2D/TextPerf.java @@ -0,0 +1,159 @@ +/* + * 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 4190429 + * @key headful + * @summary In this bug, text drawing performance should be reasonable. + * And should (per string) be consistent with the size of the + * rectangle in which the string is drawn, not the rectangle + * bounding the whole window. + */ + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +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.RenderingHints; +import java.awt.Toolkit; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class TextPerf extends Canvas { + + static volatile CountDownLatch paintLatch = new CountDownLatch(1); + static volatile long paintTime = 5000; // causes test fail if it is not updated. + static volatile Frame frame; + + public static void main(String[] args) throws Exception { + EventQueue.invokeAndWait(TextPerf::createUI); + paintLatch.await(5, TimeUnit.SECONDS); + if (paintTime > 2000) { + throw new RuntimeException("Paint time is " + paintTime + "ms"); + } + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + static void createUI() { + frame = new Frame("TextPerf"); + frame.setLayout(new BorderLayout()); + TextPerf tp = new TextPerf(); + frame.add(tp, BorderLayout.CENTER); + frame.pack(); + frame.setVisible(true); + } + + public Dimension getPreferredSize() { + Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); + return new Dimension(d.width - 50, d.height - 50); + } + + static Font[] fonts = { + new Font(Font.SERIF, Font.PLAIN, 10), + new Font(Font.SANS_SERIF, Font.PLAIN, 10), + new Font(Font.MONOSPACED, Font.ITALIC, 10), + new Font(Font.SERIF, Font.PLAIN, 14), + new Font(Font.SERIF, Font.BOLD, 12), + }; + + public void paint(Graphics g1) { + + Graphics2D g = (Graphics2D)g1; + String text = "Hello,_Wgjpqy!"; + Toolkit.getDefaultToolkit().sync(); + long startTime = System.currentTimeMillis(); + FontMetrics[] cachedMetrics = new FontMetrics[fonts.length]; + Dimension size = getSize(); + int prim = 0; + int spaceWidth = 5; + Color cols[] = { Color.red, Color.blue, Color.yellow, + Color.green, Color.pink, Color.orange} ; + + for (int y = 20; y < size.height; y += 20) { + int i = 0; + for (int x = 0; x < size.width; i++) { + Font font = fonts[i % fonts.length]; + FontMetrics metrics = cachedMetrics[i % fonts.length]; + if (metrics == null) { + metrics = g.getFontMetrics(font); + cachedMetrics[i % fonts.length] = metrics; + } + + g.setFont(font); + g.setColor(cols[i % cols.length]); + switch (prim++) { + case 0: g.drawString(text, x, y); + break; + case 1: g.drawBytes(text.getBytes(), 0, text.length(), x, y); + break; + case 2: char[] chs= new char[text.length()]; + text.getChars(0,text.length(), chs, 0); + g.drawChars(chs, 0, text.length(), x, y); + break; + case 3: GlyphVector gv = font.createGlyphVector( + g.getFontRenderContext(), text); + g.drawGlyphVector(gv, (float)x, (float)y); + default: prim = 0; + } + + x += metrics.stringWidth(text) + spaceWidth; + } + } + + // Draw some transformed text to verify correct bounds calculated + AffineTransform at = AffineTransform.getTranslateInstance(50, 50); + at.scale(7.0,7.0); + at.rotate(1.0); + g.transform(at); + g.setColor(Color.black); + Font font = new Font(Font.SERIF, Font.PLAIN, 20); + RenderingHints hints = new RenderingHints(null); + hints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHints(hints); + g.setFont(font); + FontMetrics metrics = g.getFontMetrics(font); + g.drawString("Java", 5,5); + + Toolkit.getDefaultToolkit().sync(); + long endTime = System.currentTimeMillis(); + paintTime = endTime - startTime; + String msg = "repainted in " + paintTime + " milliseconds"; + System.out.println(msg); + System.out.flush(); + + paintLatch.countDown(); + } +} diff --git a/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java b/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java new file mode 100644 index 0000000000000..b59460322daf6 --- /dev/null +++ b/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java @@ -0,0 +1,116 @@ +/* + * 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.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Label; +import java.awt.Rectangle; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.List; + +/* + * @test + * @bug 4473671 + * @summary Test to verify GraphicsEnvironment.getDefaultScreenDevice always + * returning first screen + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DefaultScreenDeviceTest + */ + +public class DefaultScreenDeviceTest { + private static Frame testFrame; + + public static void main(String[] args) throws Exception { + GraphicsEnvironment ge = GraphicsEnvironment. + getLocalGraphicsEnvironment(); + GraphicsDevice[] gds = ge.getScreenDevices(); + if (gds.length < 2) { + System.out.println("Test requires at least 2 displays"); + return; + } + + String INSTRUCTIONS = """ + 1. The test is for systems which allows primary display + selection in multiscreen systems. + Set the system primary screen to be the rightmost + (i.e. the right screen in two screen configuration) + This can be done by going to OS Display Settings + selecting the screen and checking the 'Use this device + as primary monitor' checkbox. + 2. When done, click on 'Frame on Primary Screen' button and + see where the frame will pop up + 3. If Primary Frame pops up on the primary display, + the test passed, otherwise it failed + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + private static List initialize() { + Frame frame = new Frame("Default screen device test"); + GraphicsConfiguration gc = + GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + + testFrame = new Frame("Primary screen frame", gc); + frame.setLayout(new BorderLayout()); + frame.setSize(200, 200); + + Button b = new Button("Frame on Primary Screen"); + b.addActionListener(e -> { + if (testFrame != null) { + testFrame.setVisible(false); + testFrame.dispose(); + } + + testFrame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e1) { + testFrame.setVisible(false); + testFrame.dispose(); + } + }); + testFrame.add(new Label("This frame should be on the primary screen")); + testFrame.setBackground(Color.red); + testFrame.pack(); + Rectangle rect = gc.getBounds(); + testFrame.setLocation(rect.x + 100, rect.y + 100); + testFrame.setVisible(true); + }); + frame.add(b); + return List.of(testFrame, frame); + } +} diff --git a/test/jdk/java/awt/LightweightComponent/LWParentMovedTest/LWParentMovedTest.java b/test/jdk/java/awt/LightweightComponent/LWParentMovedTest/LWParentMovedTest.java new file mode 100644 index 0000000000000..d46af3a0d5e51 --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/LWParentMovedTest/LWParentMovedTest.java @@ -0,0 +1,99 @@ +/* + * 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 4147246 + * @summary Simple check for peer != null in Component.componentMoved + * @key headful + * @run main LWParentMovedTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Container; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; + +public class LWParentMovedTest { + static CMTFrame f; + + // test will throw an exception and fail if lwc is null + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(() -> f = new CMTFrame()); + } finally { + if (f != null) { + EventQueue.invokeAndWait(() -> f.dispose()); + } + } + } +} + +class CMTFrame extends Frame { + Container lwc; + Button button; + + public CMTFrame() { + super("Moving LWC Test"); + setLayout(new FlowLayout()); + lwc = new LWSquare(Color.blue, 100, 100); + button = new Button(); + lwc.add(button); + add(lwc); + + setSize(400, 300); + setVisible(true); + + // queue up a bunch of COMPONENT_MOVED events + for (int i = 0; i < 1000; i++) { + lwc.setLocation(i, i); + } + + // remove heavyweight from lightweight container + lwc.remove(button); + } +} + +// +// Lightweight container +// +class LWSquare extends Container { + int width; + int height; + + public LWSquare(Color color, int w, int h) { + setBackground(color); + setLayout(new FlowLayout()); + width = w; + height = h; + setName("LWSquare-" + color.toString()); + } + + public void paint(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, 1000, 1000); + } +} diff --git a/test/jdk/java/awt/LightweightComponent/LightWeightTabFocus/LightWeightTabFocus.java b/test/jdk/java/awt/LightweightComponent/LightWeightTabFocus/LightWeightTabFocus.java new file mode 100644 index 0000000000000..05889580fd423 --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/LightWeightTabFocus/LightWeightTabFocus.java @@ -0,0 +1,154 @@ +/* + * 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 4095214 + * @summary Test change of focus on lightweights using the tab key + * @key headful + * @run main LightWeightTabFocus + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +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.KeyEvent; + +public class LightWeightTabFocus { + private static Frame f; + private static LightweightButton btn1; + private static Button btn2; + private static Robot robot; + private static volatile Point point; + private static Point loc; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> createUI()); + robot.delay(1000); + EventQueue.invokeAndWait(() -> { + loc = f.getLocation(); + point = btn2.getLocation(); + }); + robot.mouseMove(loc.x + point.x, loc.y + point.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + // First TAB + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + if (!btn1.hasFocus()) { + new RuntimeException("First tab failed"); + } + // Second TAB + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + if (!btn2.hasFocus()) { + new RuntimeException("Second tab failed"); + } + // First SHIFT+TAB + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_TAB); + robot.delay(100); + robot.keyRelease(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_SHIFT); + if (!btn1.hasFocus()) { + new RuntimeException("First shift+tab failed"); + } + // Second SHIFT+TAB + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_TAB); + robot.delay(100); + robot.keyRelease(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_SHIFT); + if (!btn2.hasFocus()) { + new RuntimeException("Second shift+tab failed"); + } + + } catch (Exception e) { + e.printStackTrace(); + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static Frame createUI() { + f = new Frame("TAB Focus Change on LW Test"); + f.setLayout(new FlowLayout()); + btn1 = new LightweightButton(); + f.add(btn1); + btn2 = new Button("Click Me To start"); + f.add(btn2); + f.pack(); + f.setVisible(true); + return f; + } +} + +class LightweightButton extends Component implements FocusListener { + boolean focus; + LightweightButton() { + focus = false; + addFocusListener(this); + } + + public Dimension getPreferredSize() + { + return new Dimension(100, 100); + } + + public void focusGained(FocusEvent e) { + focus = true; + repaint(); + } + + public void focusLost(FocusEvent e) { + focus = false; + repaint(); + } + + public void paint(Graphics g) { + if (focus) { + g.drawString("Has Focus", 10, 20); + } else { + g.drawString("Not Focused", 10, 20); + } + } + + public boolean isFocusable() { + return true; + } +} diff --git a/test/jdk/java/awt/LightweightComponent/LightweightFontTest/LightweightFontTest.java b/test/jdk/java/awt/LightweightComponent/LightweightFontTest/LightweightFontTest.java new file mode 100644 index 0000000000000..4fd90656d6124 --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/LightweightFontTest/LightweightFontTest.java @@ -0,0 +1,182 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4077709 4153989 + * @summary Lightweight component font settable test + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual LightweightFontTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; + + +public class LightweightFontTest { + static Font desiredFont = null; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + [ There are 7 steps to this test ] + 1. The 2 bordered labels (Emacs vs. vi) should be in a LARGE font + (approximately 1/2 inch tall) + 2. The labels should not overlap. + 3. Each button should be large enough to contain the entire label. + 4. The labels should have red backgrounds + 5. The text in the left label should be blue and the right yellow + 6. Resize the window to make it much smaller and larger + 7. The buttons should never overlap, and they should be large + enough to contain the entire label. + (although the button may disappear if there is not enough + room in the window)" + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(LightweightFontTest::createUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("Lightweight Font Test"); + f.setLayout(new FlowLayout()); + + desiredFont = new Font(Font.DIALOG, Font.PLAIN, 36); + Component component; + component = new BorderedLabel("Emacs or vi?"); + component.setFont(desiredFont); + component.setBackground(Color.red); + component.setForeground(Color.blue); + f.add(component); + component = new BorderedLabel("Vi or Emacs???"); + component.setFont(desiredFont); + component.setBackground(Color.red); + component.setForeground(Color.yellow); + f.add(component); + f.pack(); + return f; + } +} + +/** + * Lightweight component + */ +class BorderedLabel extends Component { + boolean superIsButton; + String labelString; + + BorderedLabel(String labelString) { + this.labelString = labelString; + + Component thisComponent = this; + superIsButton = (thisComponent instanceof Button); + if(superIsButton) { + ((Button)thisComponent).setLabel(labelString); + } + } + + public Dimension getMinimumSize() { + Dimension minSize = new Dimension(); + + if (superIsButton) { + minSize = super.getMinimumSize(); + } else { + + Graphics g = getGraphics(); + verifyFont(g); + FontMetrics metrics = g.getFontMetrics(); + + minSize.width = metrics.stringWidth(labelString) + 14; + minSize.height = metrics.getMaxAscent() + metrics.getMaxDescent() + 9; + + g.dispose(); + } + return minSize; + } + + public Dimension getPreferredSize() { + Dimension prefSize = new Dimension(); + if (superIsButton) { + prefSize = super.getPreferredSize(); + } else { + prefSize = getMinimumSize(); + } + return prefSize; + } + + public void paint(Graphics g) { + verifyFont(g); + super.paint(g); + if (superIsButton) { + return; + } + Dimension size = getSize(); + Color oldColor = g.getColor(); + + // draw border + g.setColor(getBackground()); + g.fill3DRect(0, 0, size.width, size.height, false); + g.fill3DRect(3, 3, size.width - 6, size.height - 6, true); + + // draw text + FontMetrics metrics = g.getFontMetrics(); + int centerX = size.width / 2; + int centerY = size.height / 2; + int textX = centerX - (metrics.stringWidth(labelString) / 2); + int textY = centerY + ((metrics.getMaxAscent() + + metrics.getMaxDescent()) / 2); + g.setColor(getForeground()); + g.drawString(labelString, textX, textY); + + g.setColor(oldColor); + } + + /** + * Verifies that the font is correct and prints a warning + * message and/or throws a RuntimeException if it is not. + */ + private void verifyFont(Graphics g) { + Font desiredFont = LightweightFontTest.desiredFont; + Font actualFont = g.getFont(); + if (!actualFont.equals(desiredFont)) { + PassFailJFrame.log("AWT BUG: FONT INFORMATION LOST!"); + PassFailJFrame.log(" Desired font: " + desiredFont); + PassFailJFrame.log(" Actual font: " + actualFont); + PassFailJFrame.forceFail(); + } + } +} diff --git a/test/jdk/java/awt/LightweightComponent/MultipleAddNotifyTest/MultipleAddNotifyTest.java b/test/jdk/java/awt/LightweightComponent/MultipleAddNotifyTest/MultipleAddNotifyTest.java new file mode 100644 index 0000000000000..fbbc2ae61854a --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/MultipleAddNotifyTest/MultipleAddNotifyTest.java @@ -0,0 +1,118 @@ +/* + * 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 4058400 + * @summary Tests that calling addNotify on a lightweight component more than + * once does not break event dispatching for that component. + * @key headful + * @run main MultipleAddNotifyTest + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class MultipleAddNotifyTest { + static volatile boolean passFlag; + static volatile int posX; + static volatile int posY; + static Frame f; + static LightComponent l; + + public static void main(String[] args) throws Exception { + Robot r; + try { + r = new Robot(); + r.setAutoWaitForIdle(true); + passFlag = false; + + EventQueue.invokeAndWait(() -> { + f = new Frame("Multiple addNotify Test"); + l = new LightComponent(); + f.setLayout(new FlowLayout()); + l.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + System.out.println("Mouse Clicked"); + passFlag = true; + } + }); + f.add(l); + f.addNotify(); + f.addNotify(); + + if (!l.isVisible()) { + throw new RuntimeException("Test failed. LW Component " + + "not visible."); + } + f.setSize(200, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + }); + r.waitForIdle(); + r.delay(1000); + + EventQueue.invokeAndWait(() -> { + posX = f.getX() + l.getWidth() + (l.getWidth() / 2); + posY = f.getY() + l.getHeight(); + }); + + r.mouseMove(posX, posY); + r.delay(500); + + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + r.delay(500); + + if (!passFlag) { + throw new RuntimeException("Test failed. MouseClicked event " + + "not working properly."); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} + +class LightComponent extends Component { + public void paint(Graphics g) { + setSize(100, 100); + Dimension d = getSize(); + g.setColor(Color.red); + g.fillRect(0, 0, d.width, d.height); + } +} diff --git a/test/jdk/java/awt/LightweightComponent/PopupTest/PopupTest.java b/test/jdk/java/awt/LightweightComponent/PopupTest/PopupTest.java new file mode 100644 index 0000000000000..beae4b4d9042e --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/PopupTest/PopupTest.java @@ -0,0 +1,93 @@ +/* + * 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 4476083 + * @summary Disabled components do not receive MouseEvent in Popups + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PopupTest + */ + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Frame; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +public class PopupTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + PopupMenus should disappear when a disabled component is + clicked. + + Step 1. Pop down the popup menu by clicking on it. + Step 2. Click on the disabled component to make the menu + disappear. + + If the menu disappears when the disabled component is clicked, + the test passes, otherwise, the test fails. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(PopupTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("Disabled Component in Popup Test"); + f.setLayout(new BorderLayout()); + + JButton b = new JButton("step 1: press me to display menu"); + b.addActionListener(e -> { + JPopupMenu m = new JPopupMenu(); + m.add(new JMenuItem("item 1")); + m.add(new JMenuItem("item 2")); + m.add(new JMenuItem("item 3")); + m.add(new JMenuItem("item 4")); + m.add(new JMenuItem("item 5")); + m.add(new JMenuItem("item 6")); + m.show((Component) e.getSource(), 0, 10); + }); + + JLabel disabled = new JLabel("step 2: click me. the menu should be " + + "dismissed"); + disabled.setEnabled(false); + + JLabel enabled = new JLabel("step 3: there is no step 3"); + + f.add(BorderLayout.NORTH, b); + f.add(BorderLayout.CENTER, disabled); + f.add(BorderLayout.SOUTH, enabled); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/List/ActionEventWhenHitEnterTest.java b/test/jdk/java/awt/List/ActionEventWhenHitEnterTest.java new file mode 100644 index 0000000000000..232189ef53bbb --- /dev/null +++ b/test/jdk/java/awt/List/ActionEventWhenHitEnterTest.java @@ -0,0 +1,126 @@ +/* + * 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 4234245 + * @summary the actionEvent is not invoked when hit enter on list. + * @key headful + * @run main ActionEventWhenHitEnterTest + */ + +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.IllegalComponentStateException; +import java.awt.List; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; + +public class ActionEventWhenHitEnterTest + implements ActionListener, ItemListener { + + volatile boolean passed1; + volatile boolean passed2; + volatile Point pt; + List list; + Frame frame; + + public static void main(final String[] args) throws Exception { + ActionEventWhenHitEnterTest app = new ActionEventWhenHitEnterTest(); + app.doTest(); + } + + public ActionEventWhenHitEnterTest() { + list = new List(7); + for (int i = 0; i < 10; i++) { + list.add("Item " + i); + } + list.addItemListener(this); + list.addActionListener(this); + } + + public void actionPerformed(ActionEvent ae) { + passed1 = true; + System.out.println("--> Action event invoked: " + ae.getSource()); + } + + public void itemStateChanged(ItemEvent ie) { + passed2 = true; + System.out.println("--> Item state changed:" + ie.getSource()); + } + + public void doTest() throws Exception { + EventQueue.invokeAndWait(() -> { + frame = new Frame("ActionEventWhenHitEnterTest"); + frame.add(list); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + pt = list.getLocationOnScreen(); + }); + + if (pt.x != 0 || pt.y != 0) { + robot.mouseMove(pt.x + list.getWidth() / 2, + pt.y + list.getHeight() / 2); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + } + + robot.waitForIdle(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + if (!passed1 || !passed2) { + throw new RuntimeException("ActionEventWhenHitEnterTest FAILED"); + } + System.out.println("Test PASSED"); + + } + +} diff --git a/test/jdk/java/awt/List/ListAddPerfTest.java b/test/jdk/java/awt/List/ListAddPerfTest.java new file mode 100644 index 0000000000000..7ff3eaf882c62 --- /dev/null +++ b/test/jdk/java/awt/List/ListAddPerfTest.java @@ -0,0 +1,99 @@ +/* + * 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 4117288 + * @summary JDKversion1.2beta3-J List's add() method is much slower. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ListAddPerfTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Frame; +import java.awt.List; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ListAddPerfTest { + + static Button button; + static List list; + + private static final String INSTRUCTIONS = """ + It is used to check the performance of List add operation. + + Instructions: + Click on the Remove All button. + The list should be cleared. + The button is now named "Add Items". + Click on the "Add Items" button. + 800 items should be added to the list. + Notice not only how fast or slow this is, but also how + 'smooth' it goes as well i.e. without any flashing. + + Press pass if the list performance is acceptable."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ListAddPerfTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ListAddPerfTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("ListAddPerfTest"); + frame.setLayout(new BorderLayout()); + + button = new Button("Remove All"); + button.addActionListener((ActionEvent e) -> { + if (list.getItemCount() > 0) { + list.removeAll(); + list.invalidate(); + button.setLabel("Add Items"); + } else { + for (int i = 0; i < 800; i ++) { + list.add("My number is " + i); + } + button.setLabel("Remove All"); + } + }); + + list = new List(15); + for (int i = 0; i < 800; i ++) { + list.add("My number is " + i); + } + + frame.add("North", button); + frame.add("South", list); + + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/List/MouseDraggedOriginatedByScrollBarTest.java b/test/jdk/java/awt/List/MouseDraggedOriginatedByScrollBarTest.java new file mode 100644 index 0000000000000..600d38fe39380 --- /dev/null +++ b/test/jdk/java/awt/List/MouseDraggedOriginatedByScrollBarTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6240151 + * @summary XToolkit: Dragging the List scrollbar initiates DnD + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseDraggedOriginatedByScrollBarTest +*/ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class MouseDraggedOriginatedByScrollBarTest { + + private static final String INSTRUCTIONS = """ + 1) Click and drag the scrollbar of the list. + 2) Keep dragging till the mouse pointer goes out the scrollbar. + 3) The test failed if you see messages about events. The test passed if you don't."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("MouseDraggedOriginatedByScrollBarTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MouseDraggedOriginatedByScrollBarTest::createTestUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame(); + List list = new List(4, false); + + list.add("000"); + list.add("111"); + list.add("222"); + list.add("333"); + list.add("444"); + list.add("555"); + list.add("666"); + list.add("777"); + list.add("888"); + list.add("999"); + + frame.add(list); + + list.addMouseMotionListener( + new MouseMotionAdapter(){ + @Override + public void mouseDragged(MouseEvent me){ + PassFailJFrame.log(me.toString()); + } + }); + + list.addMouseListener( + new MouseAdapter() { + public void mousePressed(MouseEvent me) { + PassFailJFrame.log(me.toString()); + } + + public void mouseReleased(MouseEvent me) { + PassFailJFrame.log(me.toString()); + } + + public void mouseClicked(MouseEvent me){ + PassFailJFrame.log(me.toString()); + } + }); + + frame.setLayout(new FlowLayout()); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/MenuBar/CellsResize.java b/test/jdk/java/awt/MenuBar/CellsResize.java new file mode 100644 index 0000000000000..64777095fa8d5 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/CellsResize.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6502052 + * @summary Menu cells must resize if font changes (XToolkit) + * @requires os.family == "linux" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CellsResize + */ + +import java.awt.Button; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuComponent; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.Toolkit; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class CellsResize { + private static Frame frame; + private static MenuBar menuBar; + private static PopupMenu popupMenu; + private static Menu barSubMenu; + private static Menu popupSubMenu; + private static boolean fontMultiplied = false; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Open all nested menus in menu bar. + 2. Click on "popup-menu" button to show popup-menus. + 3. Open all nested menus in popup-menu. + 4. Click on "big-font" button (to make all menus have a + bigger font). + 5. Open all nested menus again (as described in 1, 2, 3). + 6. If all menu items use a bigger font now and their labels fit + into menu-item size, press "pass", otherwise press "fail". + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(CellsResize::createUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + public static Frame createUI () { + if (!checkToolkit()) { + new RuntimeException("Toolkit check failed."); + } + frame = new Frame("MenuBar Cell Resize Test"); + + popupMenu = new PopupMenu(); + popupMenu.add(createMenu(false)); + + frame.add(popupMenu); + + menuBar = new MenuBar(); + menuBar.add(createMenu(true)); + + frame.setMenuBar(menuBar); + + Button bp = new Button("popup-menu"); + bp.addMouseListener(new MouseAdapter() { + public void mouseReleased(MouseEvent e) { + popupMenu.show(e.getComponent(), e.getX(), e.getY()); + } + }); + + Button bf = new Button("big-font"); + bf.addMouseListener(new MouseAdapter() { + public void mouseReleased(MouseEvent e) { + bigFont(); + } + }); + + Panel panel = new Panel(); + panel.setLayout(new GridLayout(2, 1)); + panel.add(bp); + panel.add(bf); + + frame.add(panel); + frame.setSize(300, 300); + return frame; + } + + static boolean checkToolkit() { + String toolkitName = Toolkit.getDefaultToolkit().getClass().getName(); + return toolkitName.equals("sun.awt.X11.XToolkit"); + } + + static Menu createMenu(boolean bar) { + Menu menu1 = new Menu("Menu-1"); + Menu menu11 = new Menu("Menu-11"); + menu1.add(menu11); + if (bar) { + barSubMenu = menu11; + } else { + popupSubMenu = menu11; + } + menu11.add(new MenuItem("MenuItem")); + return menu1; + } + + static void bigFont() { + if (fontMultiplied) { + return; + } else { + fontMultiplied = true; + } + + multiplyFont(barSubMenu, 7); + multiplyFont(popupSubMenu, 7); + + // NOTE: if previous two are moved below following + // two, they get their font multiplied twice. + + multiplyFont(menuBar, 5); + multiplyFont(popupMenu, 5); + } + + static void multiplyFont(MenuComponent comp, int times) { + Font font = comp.getFont(); + float size = font.getSize() * times; + comp.setFont(font.deriveFont(size)); + } +} diff --git a/test/jdk/java/awt/MenuBar/MenuBarAddRemoveTest/MenuBarAddRemoveTest.java b/test/jdk/java/awt/MenuBar/MenuBarAddRemoveTest/MenuBarAddRemoveTest.java new file mode 100644 index 0000000000000..fdb9f06e98c76 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/MenuBarAddRemoveTest/MenuBarAddRemoveTest.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4028130 4112308 + * @summary Test for location of Frame/MenuBar when MenuBar is re-added + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarAddRemoveTest + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; + +public class MenuBarAddRemoveTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Click the left mouse button on the "Re-Add MenuBar" + button several times. + 3. The Frame/MenuBar may repaint or flash, but the location + of its upper left corner should never change. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MenuBarAddRemoveTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("Re-Add MenuBar Test Frame"); + Button b = new Button("Re-Add MenuBar"); + b.addActionListener(e -> f.setMenuBar(createMenuBar())); + f.setMenuBar(createMenuBar()); + f.add(b); + f.pack(); + return f; + } + + private static MenuBar createMenuBar() { + MenuBar bar = new MenuBar(); + bar.add(new Menu("foo")); + return bar; + } +} diff --git a/test/jdk/java/awt/MenuBar/MenuBarOnDisabledFrame/MenuBarOnDisabledFrame.java b/test/jdk/java/awt/MenuBar/MenuBarOnDisabledFrame/MenuBarOnDisabledFrame.java new file mode 100644 index 0000000000000..06f5d96c19e32 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/MenuBarOnDisabledFrame/MenuBarOnDisabledFrame.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6185057 + * @summary Disabling a frame does not disable the menus on the frame, on + * solaris/linux + * @requires os.family != "mac" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarOnDisabledFrame + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +public class MenuBarOnDisabledFrame { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Check if MenuBar is disabled on 'Disabled frame' + Press pass if menu bar is disabled, fail otherwise + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MenuBarOnDisabledFrame::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Disabled frame"); + MenuBar mb = new MenuBar(); + Menu m1 = new Menu("Disabled Menu 1"); + Menu m2 = new Menu("Disabled Menu 2"); + MenuItem m11 = new MenuItem("MenuItem 1.1"); + MenuItem m21 = new MenuItem("MenuItem 2.1"); + Button b = new Button("Disabled button"); + + m1.add(m11); + m2.add(m21); + mb.add(m1); + mb.add(m2); + f.setMenuBar(mb); + f.add(b); + f.setEnabled(false); + f.setSize(300, 300); + return f; + } +} diff --git a/test/jdk/java/awt/MenuBar/MenuBarRemoveMenu/MenuBarRemoveMenuTest.java b/test/jdk/java/awt/MenuBar/MenuBarRemoveMenu/MenuBarRemoveMenuTest.java new file mode 100644 index 0000000000000..098065d1361f6 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/MenuBarRemoveMenu/MenuBarRemoveMenuTest.java @@ -0,0 +1,93 @@ +/* + * 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 4275848 + * @summary Tests that MenuBar is painted correctly after its submenu is removed + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarRemoveMenuTest + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class MenuBarRemoveMenuTest implements ActionListener { + private static MenuBar menubar; + private static Button removeButton; + private static Button addButton; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Press "Remove menu" button. If you see that both menus + disappeared, the test failed. Otherwise try to add and remove + menu several times to verify that the test passed. Every time + you press "Remove menu" button only one menu should go away. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MenuBarRemoveMenuTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame(); + menubar = new MenuBar(); + removeButton = new Button("Remove menu"); + addButton = new Button("Add menu"); + removeButton.addActionListener(new MenuBarRemoveMenuTest()); + addButton.addActionListener(new MenuBarRemoveMenuTest()); + addButton.setEnabled(false); + menubar.add(new Menu("menu")); + menubar.add(new Menu("menu")); + frame.setMenuBar(menubar); + frame.setLayout(new GridLayout(1, 2)); + frame.add(removeButton); + frame.add(addButton); + frame.pack(); + return frame; + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == removeButton) { + menubar.remove(0); + removeButton.setEnabled(false); + addButton.setEnabled(true); + } else { + menubar.add(new Menu("menu")); + removeButton.setEnabled(true); + addButton.setEnabled(false); + } + } +} diff --git a/test/jdk/java/awt/MenuBar/MenuBarVisuals/MenuBarVisuals.java b/test/jdk/java/awt/MenuBar/MenuBarVisuals/MenuBarVisuals.java new file mode 100644 index 0000000000000..7663dd0d99be1 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/MenuBarVisuals/MenuBarVisuals.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6180416 + * @summary Tests MenuBar and drop down menu visuals + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarVisuals + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.event.KeyEvent; + +public class MenuBarVisuals { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Look at the MenuBar and traverse the menus using mouse and + keyboard. Then check if following is showing correctly: + 1. Mnemonic label Ctrl+A is NOT drawn for Menu 1/Submenu 1.1 + 2. Mnemonic label Ctrl+B is drawn for + Menu 1/Submenu 1.1/Item 1.1.1 + 3. Mnemonic label Ctrl+C is drawn for Menu1/Item 1.2 + Press PASS if Menu is drawing correctly, FAIL otherwise. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MenuBarVisuals::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("MenuBar Visuals Test"); + MenuBar mb = new MenuBar(); + Menu menu1 = new Menu("Menu 1"); + Menu submenu11 = new Menu("Submenu 1.1"); + MenuItem item111 = new MenuItem("Item 1.1.1"); + MenuItem item112 = new MenuItem("Item 1.1.2"); + MenuItem item12 = new MenuItem("Item 1.2"); + Menu menu2 = new Menu("Menu 2"); + MenuItem item21 = new MenuItem("Item 2.1"); + MenuItem item22 = new MenuItem("Item 2.2"); + item111.setShortcut(new MenuShortcut(KeyEvent.VK_B, false)); + submenu11.add(item111); + submenu11.add(item112); + submenu11.setShortcut(new MenuShortcut(KeyEvent.VK_A, false)); + menu1.add(submenu11); + item12.setShortcut(new MenuShortcut(KeyEvent.VK_C, false)); + menu1.add(item12); + mb.add(menu1); + menu2.add(item21); + menu2.add(item22); + mb.add(menu2); + f.setMenuBar(mb); + f.setSize(300, 300); + return f; + } +} diff --git a/test/jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java b/test/jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java new file mode 100644 index 0000000000000..a7a3a3480118e --- /dev/null +++ b/test/jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java @@ -0,0 +1,63 @@ +/* + * 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 + * 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 5005194 + * @summary Frame.remove(getMenuBar()) throws NPE if the frame doesn't + * have a menu bar + * @key headful + * @run main MenuNPE + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +public class MenuNPE { + private static Frame frame; + public static void main(String[] args) throws Exception { + try { + frame = new Frame("Menu NPE"); + MenuBar menuBar = new MenuBar(); + Menu menu1 = new Menu("Menu 01"); + MenuItem menuLabel = new MenuItem("Item 01"); + menu1.add(menuLabel); + menuBar.add(menu1); + frame.setMenuBar(menuBar); + frame.setSize(200, 200); + frame.setVisible(true); + frame.validate(); + frame.remove(frame.getMenuBar()); + frame.remove(frame.getMenuBar()); + System.out.println("Test passed."); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (frame != null) { + frame.dispose(); + } + } + } +} diff --git a/test/jdk/java/awt/MenuBar/SetHelpMenuTest/SetHelpMenuTest.java b/test/jdk/java/awt/MenuBar/SetHelpMenuTest/SetHelpMenuTest.java new file mode 100644 index 0000000000000..fcfc3e80ed34c --- /dev/null +++ b/test/jdk/java/awt/MenuBar/SetHelpMenuTest/SetHelpMenuTest.java @@ -0,0 +1,88 @@ +/* + * 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 4275843 + * @summary MenuBar doesn't display all of its Menus correctly on Windows + * @requires os.family == "windows" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetHelpMenuTest + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +public class SetHelpMenuTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + An empty frame should be visible. When focused, the MenuBar + should have 5 menus ("one", "two", "three", "Help 2", + "four"). If so, then the test passed. Otherwise, the test + failed. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(SetHelpMenuTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("Help MenuBar Test"); + f.setSize(100, 100); + + MenuBar mb = new MenuBar(); + Menu h1, h2; + + f.setMenuBar(mb); + mb.add(createMenu("one", false)); + mb.add(createMenu("two", false)); + mb.add(createMenu("three", true)); + + mb.add(h1 = createMenu("Help 1", false)); // h1 is HelpMenu + mb.setHelpMenu(h1); + + mb.add(h2 = createMenu("Help 2", false)); // h2 replaced h1 + mb.setHelpMenu(h2); + + mb.add(createMenu("four", false)); + + return f; + } + + private static Menu createMenu(String name, boolean tearOff) { + Menu m = new Menu(name, tearOff); + m.add(new MenuItem(name + " item 1")); + m.add(new MenuItem(name + " item 2")); + m.add(new MenuItem(name + " item 3")); + return m; + } +} diff --git a/test/jdk/java/awt/MenuBar/SetMBarWhenHidden/SetMBarWhenHidden.java b/test/jdk/java/awt/MenuBar/SetMBarWhenHidden/SetMBarWhenHidden.java new file mode 100644 index 0000000000000..67eefe4894248 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/SetMBarWhenHidden/SetMBarWhenHidden.java @@ -0,0 +1,92 @@ +/* + * 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 4105881 + * @summary Sets the menu bar while frame window is hidden, then shows + frame again + * @key headful + * @run main SetMBarWhenHidden + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Rectangle; + +// test case for 4105881: FRAME.SETSIZE() DOESN'T WORK FOR SOME SOLARIS WITH +// JDK115+CASES ON +public class SetMBarWhenHidden { + private static Frame f; + private static Rectangle startBounds; + private static Rectangle endBounds; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(() -> { + f = new Frame("Set MenuBar When Hidden Test"); + Menu file; + Menu edit; + MenuBar menubar = new MenuBar(); + file = new Menu("File"); + menubar.add(file); + edit = new Menu("Edit"); + menubar.add(edit); + edit.setEnabled(false); + f.setMenuBar(menubar); + f.setSize(200, 200); + startBounds = f.getBounds(); + System.out.println("About to call setVisible(false)"); + f.setVisible(false); + System.out.println("About to call setSize(500, 500)"); + f.setSize(500, 500); + // create a new menubar and add + MenuBar menubar1 = new MenuBar(); + menubar1.add(file); + menubar1.add(edit); + System.out.println("About to call setMenuBar"); + f.setMenuBar(menubar1); + System.out.println("About to call setVisible(true)"); + f.setVisible(true); + endBounds = f.getBounds(); + }); + if (startBounds.getHeight() > endBounds.getHeight() && + startBounds.getWidth() > endBounds.getWidth()) { + throw new RuntimeException("Test failed. Frame size didn't " + + "change.\nStart: " + startBounds + "\n" + + "End: " + endBounds); + } else { + System.out.println("Test passed.\nStart: " + startBounds + + "\nEnd: " + endBounds); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/java/awt/MenuShortcut/ActionCommandTest.java b/test/jdk/java/awt/MenuShortcut/ActionCommandTest.java new file mode 100644 index 0000000000000..bd1648cdc2cd3 --- /dev/null +++ b/test/jdk/java/awt/MenuShortcut/ActionCommandTest.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4079449 + * @key headful + * @summary MenuItem objects return null if they are activated by shortcut + */ + +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Point; +import java.awt.Robot; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import static java.awt.event.KeyEvent.VK_CONTROL; +import static java.awt.event.KeyEvent.VK_META; + +public class ActionCommandTest implements ActionListener { + + static volatile Frame frame; + static volatile boolean event = false; + static volatile boolean failed = false; + static final String ITEMTEXT = "Testitem"; + + static void createUI() { + frame = new Frame("ActionCommand Menu Shortcut Test"); + MenuBar mb = new MenuBar(); + Menu m = new Menu("Test"); + MenuItem mi = new MenuItem(ITEMTEXT, new MenuShortcut(KeyEvent.VK_T)); + mi.addActionListener(new ActionCommandTest()); + m.add(mi); + mb.add(m); + frame.setMenuBar(mb); + frame.setBounds(50, 400, 200, 200); + frame.setVisible(true); + } + + public static void main(String[] args ) throws Exception { + + EventQueue.invokeAndWait(ActionCommandTest::createUI); + try { + Robot robot = new Robot(); + + robot.waitForIdle(); + robot.delay(2000); + + // Ensure window has focus + Point p = frame.getLocationOnScreen(); + robot.mouseMove(p.x + frame.getWidth() / 2, p.y + frame.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(2000); + + // invoke short cut. + robot.keyPress(KeyEvent.VK_T); + robot.delay(50); + robot.keyRelease(KeyEvent.VK_T); + robot.waitForIdle(); + robot.delay(2000); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + if (failed) { + throw new RuntimeException("No actioncommand"); + } + } + + // Since no ActionCommand is set, this should be the menuitem's label. + public void actionPerformed(ActionEvent e) { + event = true; + String s = e.getActionCommand(); + if (s == null || !s.equals(ITEMTEXT)) { + failed = true; + } + } + +} diff --git a/test/jdk/java/awt/MenuShortcut/CheckMenuShortcut.java b/test/jdk/java/awt/MenuShortcut/CheckMenuShortcut.java new file mode 100644 index 0000000000000..cebb42f1b55e3 --- /dev/null +++ b/test/jdk/java/awt/MenuShortcut/CheckMenuShortcut.java @@ -0,0 +1,139 @@ +/* + * 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 4167811 + * @summary tests that shortcuts work for Checkbox menu items + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckMenuShortcut +*/ + +import java.awt.CheckboxMenuItem; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; + +public class CheckMenuShortcut implements ActionListener, ItemListener { + + static final String INSTRUCTIONS = """ + A window that contains a text area will be displayed. + The window will have a menu labeled 'Window Menu'. Click on the menu to see its items. + + The two menu items should have shortcuts which in order are : Ctrl-A, Ctrl-I. + On macOS these will be Command-A, Command-I. + + If the second item only has the label 'checkbox item' and no shortcut + ie none of Ctrl-I or Ctrl-i, or Command-I or Command-i on macOS painted on it, the test FAILS. + + The same second item - labeled 'checkbox item' is in fact a Checkbox menu item. + The menu item should NOT be checked (eg no tick mark). + + Dismiss the menu by clicking inside the window, do not select any of menu items. + After that press Ctrl-i, (Command-i on macOS). + + After that click on the menu again. If the second menu item 'checkbox item' is now + checked, the test PASSES, if it is not checked, the test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("CheckboxMenuItem Shortcut Test Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .logArea() + .testUI(CheckMenuShortcut::createUI) + .build() + .awaitAndCheck(); + } + + + static Frame createUI() { + + MenuBar mainMenu; + Menu menu; + MenuItem action; + CheckboxMenuItem item; + TextArea pane; + + boolean isMac = System.getProperty("os.name").startsWith("Mac"); + String ctrlA = (isMac) ? "Command-A" : "Ctrl-A"; + String ctrlI = (isMac) ? "Command-I" : "Ctrl-I"; + + CheckMenuShortcut cms = new CheckMenuShortcut(); + Frame frame = new Frame("CheckMenuShortcut"); + + mainMenu = new MenuBar(); + menu = new Menu("Window Menu"); + + action = new MenuItem("action"); + action.setShortcut(new MenuShortcut(KeyEvent.VK_A, false)); + action.addActionListener(cms); + action.setActionCommand("action"); + menu.add(action); + + item = new CheckboxMenuItem("checkbox item", false); + item.setShortcut(new MenuShortcut(KeyEvent.VK_I,false)); + item.addItemListener(cms); + item.addActionListener(cms); + menu.add(item); + + mainMenu.add(menu); + + frame.setMenuBar(mainMenu); + + pane = new TextArea(ctrlA + " -- action menu test\n", 10, 40, TextArea.SCROLLBARS_VERTICAL_ONLY); + Dimension mySize = frame.getSize(); + Insets myIns = frame.getInsets(); + pane.setBounds(new Rectangle(mySize.width - myIns.left - myIns.right, + mySize.height - myIns.top - myIns.bottom)); + pane.setLocation(myIns.left,myIns.top); + frame.add(pane); + + pane.append(ctrlI + " -- item menu test\n"); + + frame.pack(); + return frame; + } + + public void itemStateChanged(ItemEvent evt) { + PassFailJFrame.log("Got item: " + evt.getItem() + "\n"); + } + + public void actionPerformed(ActionEvent evt) { + PassFailJFrame.log("Got action: " + evt.getActionCommand() + "\n"); + } +} diff --git a/test/jdk/java/awt/MenuShortcut/FunctionKeyShortcut.java b/test/jdk/java/awt/MenuShortcut/FunctionKeyShortcut.java new file mode 100644 index 0000000000000..960de08bd2d5a --- /dev/null +++ b/test/jdk/java/awt/MenuShortcut/FunctionKeyShortcut.java @@ -0,0 +1,140 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4034665 + * @key headful + * @summary Function keys should work correctly as shortcuts + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import static java.awt.event.KeyEvent.VK_CONTROL; +import static java.awt.event.KeyEvent.VK_META; + +public class FunctionKeyShortcut implements ActionListener { + + static volatile Frame frame; + static volatile boolean event = false; + static volatile boolean failed = false; + + static final boolean isMac = System.getProperty("os.name").contains("OS X"); + + static void createUI() { + frame = new Frame("Function Key Menu Shortcut Test"); + MenuBar mb = new MenuBar(); + Menu m = new Menu("Test"); + MenuItem mi1 = new MenuItem("Function key 1", new MenuShortcut(KeyEvent.VK_F1)); + MenuItem mi2 = new MenuItem("Function key 2", new MenuShortcut(KeyEvent.VK_F2)); + MenuItem mi3 = new MenuItem("Function key 3", new MenuShortcut(KeyEvent.VK_F3)); + MenuItem mi4 = new MenuItem("Function key 4", new MenuShortcut(KeyEvent.VK_F4)); + MenuItem mi5 = new MenuItem("Function key 5", new MenuShortcut(KeyEvent.VK_F5)); + MenuItem mi6 = new MenuItem("Function key 6", new MenuShortcut(KeyEvent.VK_F6)); + MenuItem mi7 = new MenuItem("Function key 7", new MenuShortcut(KeyEvent.VK_F7)); + MenuItem mi8 = new MenuItem("Function key 8", new MenuShortcut(KeyEvent.VK_F8)); + MenuItem mi9 = new MenuItem("Function key 8", new MenuShortcut(KeyEvent.VK_F9)); + + FunctionKeyShortcut fks = new FunctionKeyShortcut(); + mi1.addActionListener(fks); + mi2.addActionListener(fks); + mi3.addActionListener(fks); + mi4.addActionListener(fks); + mi5.addActionListener(fks); + mi6.addActionListener(fks); + mi7.addActionListener(fks); + mi8.addActionListener(fks); + mi9.addActionListener(fks); + + m.add(mi1); + m.add(mi2); + m.add(mi3); + m.add(mi4); + m.add(mi5); + m.add(mi6); + m.add(mi7); + m.add(mi8); + m.add(mi9); + + mb.add(m); + frame.setMenuBar(mb); + frame.setBounds(50,400,200,200); + frame.setVisible(true); + } + + public static void main(String[] args ) throws Exception { + + EventQueue.invokeAndWait(FunctionKeyShortcut::createUI); + try { + Robot robot = new Robot(); + + robot.waitForIdle(); + robot.delay(2000); + + // Ensure window has focus + Point p = frame.getLocationOnScreen(); + robot.mouseMove(p.x + frame.getWidth() / 2, p.y + frame.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(2000); + + int mod = (isMac) ? KeyEvent.VK_META : KeyEvent.VK_CONTROL; + robot.keyPress(mod); + robot.keyPress(KeyEvent.VK_F1); + robot.delay(50); + robot.keyRelease(KeyEvent.VK_F1); + robot.keyRelease(mod); + robot.waitForIdle(); + robot.delay(2000); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + if (!event || failed) { + throw new RuntimeException("No actioncommand"); + } + } + + public void actionPerformed(ActionEvent e) { + System.out.println("Got " + e); + String s = e.getActionCommand(); + event = true; + if (s == null || !s.equals("Function key 1")) { + failed = true; + } + } + +} diff --git a/test/jdk/java/awt/MenuShortcut/MenuItemShortcutReplaceTest.java b/test/jdk/java/awt/MenuShortcut/MenuItemShortcutReplaceTest.java new file mode 100644 index 0000000000000..fe59d1a02ef34 --- /dev/null +++ b/test/jdk/java/awt/MenuShortcut/MenuItemShortcutReplaceTest.java @@ -0,0 +1,111 @@ +/* + * 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 4080225 + * @summary A replaced menu shortcut does not draw in the menu. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuItemShortcutReplaceTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +/* + * Manual test because visual verification of the shortcut being painted is required. + */ + +public class MenuItemShortcutReplaceTest implements ActionListener { + + static boolean isMac = System.getProperty("os.name").startsWith("Mac"); + static String shortcut = (isMac) ? "Cmd" : "Ctrl"; + static String instructions = + "1. On the frame 'MenuItem Shortcut Replace Test' click on the Menu 'Click here'.\n" + + " You will see a MenuItem 'MenuItem1' with the shortcut key displayed as" + + " '" + shortcut + "+M'.\n" + + "2. Click the 'Change Shortcutkey' button.\n" + + "3. Now click on the Menu again to see the MenuItem.\n" + + "4. If the shortcut key displayed near the MenuItem is changed to " + + "'" + shortcut + "+C', press 'Pass' else press 'Fail'"; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("MenuItem Shortcut Replace Test Instructions") + .instructions(instructions) + .columns(60) + .logArea() + .testUI(MenuItemShortcutReplaceTest::createUI) + .build() + .awaitAndCheck(); + + } + + static volatile Button change; + static volatile MenuItem mi; + static volatile MenuShortcut ms; + + static Frame createUI() { + Frame frame = new Frame("MenuItem Shortcut Replace Test"); + MenuBar mb = new MenuBar(); + change = new Button("Change ShortcutKey"); + Panel p = new Panel(); + p.add(change); + MenuItemShortcutReplaceTest misrt = new MenuItemShortcutReplaceTest(); + change.addActionListener(misrt); + Menu m = new Menu("Click here"); + mb.add(m); + mi = new MenuItem("MenuItem1"); + m.add(mi); + mi.addActionListener(misrt); + frame.setMenuBar(mb); + //Set the shortcut key for the menuitem + ms = new MenuShortcut(KeyEvent.VK_M); + mi.setShortcut(ms); + frame.add(p, BorderLayout.SOUTH); + frame.setSize(300, 300); + return frame; + } + + public void actionPerformed(ActionEvent e) { + //change the shortcut key + if (e.getSource() == change) { + ms = new MenuShortcut(KeyEvent.VK_C); + mi.setShortcut(ms); + PassFailJFrame.log("Shortcut key set to "+shortcut+"C"); + } + if (e.getSource() == mi) { + PassFailJFrame.log("MenuItem Selected"); + } + } +} diff --git a/test/jdk/java/awt/Mouse/DoubleClickTest.java b/test/jdk/java/awt/Mouse/DoubleClickTest.java new file mode 100644 index 0000000000000..037332a40981e --- /dev/null +++ b/test/jdk/java/awt/Mouse/DoubleClickTest.java @@ -0,0 +1,88 @@ +/* + * 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.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Event; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; + +/* + * @test + * @bug 4092370 + * @summary Test to verify double click + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DoubleClickTest + */ + +public class DoubleClickTest { + static TextArea ta = new TextArea("", 10, 40); + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Double click on the red area. + 2. Verify that the event reports click_count > 1 on + Double-Click. If click_count shows only 1 for every + Double-Clicks then test FAILS, else test PASS. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("Double-click Test"); + frame.setLayout(new BorderLayout()); + frame.add("East", new MyPanel(ta)); + frame.add("West", ta); + frame.setSize(200, 200); + return frame; + } +} + +class MyPanel extends Panel { + TextArea ta; + + MyPanel(TextArea ta) { + this.ta = ta; + setBackground(Color.red); + } + + public Dimension getPreferredSize() { + return new Dimension(50, 50); + } + + + public boolean mouseDown(Event event, int x, int y) { + ta.append("event click count= " + event.clickCount + "\n"); + return false; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseClickCount.java b/test/jdk/java/awt/Mouse/MouseClickCount.java new file mode 100644 index 0000000000000..a63d24fcb9ffb --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseClickCount.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +import java.awt.Frame; +import java.awt.TextArea; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4199397 + * @summary Test to mouse click count + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseClickCount + */ + +public class MouseClickCount { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Clicking on Frame panel quickly will produce clickCount larger than 1 + in the TextArea the count is printed for each mouse click + 2. Verify that a left-button click followed by a right button click quickly + will not generate 1, 2, i.e. it's not considered a double clicking. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + private static Frame initialize() { + Frame f = new Frame("Mouse Click Count Test"); + final TextArea ta = new TextArea(); + f.add("South", ta); + f.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + if (e.getClickCount() == 1) ta.append("\n1"); + else ta.append(", " + e.getClickCount()); + } + }); + f.setSize(300, 500); + return f; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java b/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java new file mode 100644 index 0000000000000..b2d8e446ffc36 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; + +/* + * @test + * @bug 4141361 + * @summary Test to Ensures that mouse enter / exit is delivered to a new + * frame or component during a drag + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseDragEnterExitTest + */ + +public class MouseDragEnterExitTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click on the blue frame, drag to the white frame, and back + You should get enter/exit messages for the frames when dragging + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MouseEvents.initialize()) + .logArea(8) + .build() + .awaitAndCheck(); + } +} + +class MouseEvents extends Frame { + static int WITH_WIDGET = 0; + + public MouseEvents(int mode) { + super("Mouse Drag Enter/Exit Test"); + setSize(300, 300); + + addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + PassFailJFrame.log("Frame MOUSE_ENTERED" + ": " + " " + + e.getX() + " " + e.getY()); + } + + @Override + public void mouseExited(MouseEvent e) { + PassFailJFrame.log("Frame MOUSE_EXITED" + ": " + " " + + e.getX() + " " + e.getY()); + } + }); + + if (mode == WITH_WIDGET) { + setLayout(new BorderLayout()); + add("Center", new SimplePanel()); + } + } + + public static List initialize() { + MouseEvents m = new MouseEvents(MouseEvents.WITH_WIDGET); + m.setLocation(500, 300); + MouseEvents t = new MouseEvents(MouseEvents.WITH_WIDGET + 1); + t.setLocation(200, 200); + return List.of(m, t); + } +} + +class SimplePanel extends Panel { + public SimplePanel() { + super(); + setName("Test Panel"); + addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + PassFailJFrame.log("Panel MOUSE_ENTERED" + ": " + " " + + e.getX() + " " + e.getY()); + } + + @Override + public void mouseExited(MouseEvent e) { + PassFailJFrame.log("Panel MOUSE_EXITED" + ": " + " " + + e.getX() + " " + e.getY()); + } + }); + setSize(100, 100); + setBackground(Color.blue); + } +} + diff --git a/test/jdk/java/awt/Mouse/MouseDragTest.java b/test/jdk/java/awt/Mouse/MouseDragTest.java new file mode 100644 index 0000000000000..cb8be7b0de25b --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseDragTest.java @@ -0,0 +1,215 @@ +/* + * 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. + */ + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseMotionListener; + +/* + * @test + * @bug 4035189 + * @summary Test to verify that Drag events go to wrong component + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseDragTest + */ + +class HeavySquare extends Canvas { + private final Color colorNormal; + private boolean gotADragEvent; + + public HeavySquare(Color color) { + colorNormal = color; + setBackground(colorNormal); + new MouseChecker(this); + addMouseMotionListener(new DragAdapter()); + addMouseListener(new PressReleaseAdapter()); + } + + class DragAdapter extends MouseMotionAdapter { + public void mouseDragged(MouseEvent ev) { + if (gotADragEvent) + return; + + Point mousePt = ev.getPoint(); + Dimension csize = getSize(); + boolean inBounds = + (mousePt.x >= 0 && mousePt.x <= csize.width && + mousePt.y >= 0 && mousePt.y <= csize.height); + if (!inBounds) { + setBackground(Color.green); + } + gotADragEvent = true; + } + } + + class PressReleaseAdapter extends MouseAdapter { + public void mousePressed(MouseEvent ev) { + gotADragEvent = false; + } + + public void mouseReleased(MouseEvent ev) { + setBackground(colorNormal); + } + } + + public Dimension preferredSize() { + return new Dimension(50, 50); + } +} + +class MouseFrame extends Frame { + public MouseFrame() { + super("MouseDragTest"); + new MouseChecker(this); + setLayout(new FlowLayout()); + add(new HeavySquare(Color.red)); + add(new HeavySquare(Color.blue)); + setBounds(new Rectangle(20, 20, 400, 300)); + } +} + +public class MouseDragTest { + static Frame TestFrame; + + public MouseDragTest() { + TestFrame = new MouseFrame(); + } + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. A frame with two boxes will appear. Click and drag _very_ quickly + off one of the components. You will know you were quick enough + when the component you dragged off of turns green + 2. Repeat this several times on both boxes, ensuring you get them + to turn green. The components should revert to their original + color when you release the mouse + 3. The test FAILS if the component doesn't revert to original + color, else PASS. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(new MouseFrame()) + .build() + .awaitAndCheck(); + } +} + +class MouseChecker implements MouseListener, MouseMotionListener { + private boolean isPressed = false; + private MouseEvent evPrev = null; + private MouseEvent evPrevPrev = null; + + public MouseChecker(Component comp) { + comp.addMouseListener(this); + comp.addMouseMotionListener(this); + } + + private void recordEv(MouseEvent ev) { + evPrevPrev = evPrev; + evPrev = ev; + } + + private synchronized void failure(String str) { + PassFailJFrame.forceFail("Test Failed : "+str); + } + + public void mouseClicked(MouseEvent ev) { + if (!(evPrev.getID() == MouseEvent.MOUSE_RELEASED && + evPrevPrev.getID() == MouseEvent.MOUSE_PRESSED)) { + failure("Got mouse click without press/release preceding."); + } + recordEv(ev); + } + + public void mousePressed(MouseEvent ev) { + recordEv(ev); + if (isPressed) { + failure("Got two mouse presses without a release."); + } + isPressed = true; + } + + public void mouseReleased(MouseEvent ev) { + recordEv(ev); + if (!isPressed) { + failure("Got mouse release without being pressed."); + } + isPressed = false; + } + + public void mouseEntered(MouseEvent ev) { + recordEv(ev); + Point mousePt = ev.getPoint(); + Component comp = (Component) ev.getSource(); + Dimension size = comp.getSize(); + boolean inBounds = + (mousePt.x >= 0 && mousePt.x <= size.width && + mousePt.y >= 0 && mousePt.y <= size.height); + + if (!inBounds) { + failure("Got mouse entered, but mouse not inside component."); + } + } + + public void mouseExited(MouseEvent ev) { + recordEv(ev); + Point mousePt = ev.getPoint(); + Component comp = (Component) ev.getSource(); + if (comp instanceof Frame) { + return; + } + Dimension size = comp.getSize(); + boolean isOnChild = (comp != comp.getComponentAt(mousePt)); + boolean inBounds = + (mousePt.x >= 0 && mousePt.x <= size.width && + mousePt.y >= 0 && mousePt.y <= size.height); + if (!isOnChild && inBounds) { + failure("Got mouse exit, but mouse still inside component."); + } + } + + public void mouseDragged(MouseEvent ev) { + recordEv(ev); + if (!isPressed) { + failure("Got drag without a press first."); + } + } + + public void mouseMoved(MouseEvent ev) { + recordEv(ev); + } +} diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest.java new file mode 100644 index 0000000000000..059ad5c054829 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest.java @@ -0,0 +1,174 @@ +/* + * 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. + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Robot; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/* + * @test + * @bug 4050138 + * @key headful + * @summary Test to verify Lightweight components don't get + * enter/exit during drags + * @run main MouseEnterExitTest + */ + +class LWSquare extends Container { + int width; + int height; + + public LWSquare(Color color, int w, int h) { + setBackground(color); + setLayout(new FlowLayout()); + width = w; + height = h; + addMouseListener(new EnterExitAdapter(this)); + setName("LWSquare-" + color.toString()); + } + + public void paint(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, getSize().width, getSize().height); + super.paint(g); + } + + public Dimension getPreferredSize() { + return new Dimension(width, height); + } + + public Cursor getCursor() { + return new Cursor(Cursor.CROSSHAIR_CURSOR); + } +} + +class MouseFrame extends Frame { + public LWSquare lw; + + public MouseFrame() { + super("MouseEnterExitTest"); + setLayout(new FlowLayout()); + + lw = new LWSquare(Color.red, 75, 75); + add(lw); + setBounds(50, 50, 300, 200); + setVisible(true); + System.out.println(getInsets()); + + addMouseListener(new EnterExitAdapter(this)); + addWindowListener( + new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + dispose(); + } + } + ); + addKeyListener( + new KeyAdapter() { + public void keyPressed(KeyEvent ev) { + MouseEnterExitTest.getFrame().setTitle("MouseEnterExitTest"); + } + } + ); + } +} + + +public class MouseEnterExitTest { + static MouseFrame testFrame; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> testFrame = new MouseFrame()); + if (testFrame.lw.getBackground() != Color.red) { + throw new RuntimeException("Initial Background color not matching"); + } + robot.waitForIdle(); + robot.delay(100); + EventQueue.invokeAndWait(() -> robot.mouseMove( + testFrame.getLocationOnScreen().x + testFrame.getSize().width / 2, + testFrame.getLocationOnScreen().y + testFrame.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(100); + + if (testFrame.lw.getBackground() != Color.green) { + throw new RuntimeException("Initial Background color not matching"); + } + EventQueue.invokeAndWait(() -> robot.mouseMove( + testFrame.getLocationOnScreen().x + testFrame.getSize().width * 2, + testFrame.getLocationOnScreen().y + testFrame.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(100); + + if (testFrame.lw.getBackground() != Color.red) { + throw new RuntimeException("Initial Background color not matching"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (testFrame != null) { + testFrame.dispose(); + } + }); + } + } + + public static Frame getFrame() { + return testFrame; + } +} + +class EnterExitAdapter extends MouseAdapter { + Component compToColor; + Color colorNormal; + + EnterExitAdapter(Component comp) { + compToColor = comp; + colorNormal = comp.getBackground(); + } + + public void mouseEntered(MouseEvent ev) { + compToColor.setBackground(Color.green); + compToColor.repaint(); + } + + public void mouseExited(MouseEvent ev) { + compToColor.setBackground(colorNormal); + compToColor.repaint(); + } +} diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java new file mode 100644 index 0000000000000..e09ac333447f6 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java @@ -0,0 +1,140 @@ +/* + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +/* + * @test + * @bug 4150851 + * @summary Tests enter and exit events when a lightweight component is on a border + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseEnterExitTest2 + */ + +public class MouseEnterExitTest2 { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Verify that white component turns black whenever mouse enters the frame, + except when it enters the red rectangle. + 2. When the mouse enters the red part of the frame the component should stay white. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(EntryExitTest.initialize()) + .build() + .awaitAndCheck(); + } +} + +class EntryExitTest extends Component { + boolean inWin; + + public Dimension getPreferredSize() { + return new Dimension(200, 150); + } + + public void paint(Graphics g) { + Color c1, c2; + String s; + if (inWin) { + c1 = Color.black; + c2 = Color.white; + s = "IN"; + } else { + c2 = Color.black; + c1 = Color.white; + s = "OUT"; + } + g.setColor(c1); + Rectangle r = getBounds(); + g.fillRect(0, 0, r.width, r.height); + g.setColor(c2); + g.drawString(s, r.width / 2, r.height / 2); + } + + public static Frame initialize() { + EntryExitTest test = new EntryExitTest(); + MouseListener frameEnterExitListener = new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + test.inWin = true; + test.repaint(); + } + + public void mouseExited(MouseEvent e) { + test.inWin = false; + test.repaint(); + } + }; + + Frame f = new Frame("Mouse Modifier Test"); + + f.add(test); + Component jc = new Component() { + public Dimension getPreferredSize() { + return new Dimension(100, 50); + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(Color.red); + g.fillRect(0, 0, d.width, d.height); + } + }; + final Container cont = new Container() { + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } + }; + cont.setLayout(new GridLayout(2, 1)); + cont.add(jc); + jc.addMouseListener(new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + //System.out.println("Component entered"); + } + public void mouseExited(MouseEvent e) { + //System.out.println("Component exited"); + } + }); + + f.add(cont, BorderLayout.NORTH); + f.addMouseListener(frameEnterExitListener); + f.pack(); + return f; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java new file mode 100644 index 0000000000000..d5096d7acf022 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java @@ -0,0 +1,84 @@ +/* + * 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.Button; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import javax.swing.JButton; + +/* + * @test + * @bug 4431868 + * @summary Tests that hw container doesn't receive mouse enter/exit events when mouse + * is moved between its lw and hw children + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseEnterExitTest3 + */ + +public class MouseEnterExitTest3 { + static final Button button = new Button("Button"); + static final JButton jbutton = new JButton("JButton"); + static final Frame frame = new Frame("Mouse Enter/Exit Test"); + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Move the mouse between Button and JButton + 2. Verify that the frame doesn't receive enter/exit events + (Enter/exit events are dumped to the area below) + 4. If you see enter/exit events dumped the test fails + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(4) + .build() + .awaitAndCheck(); + } + + final static MouseListener listener = new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + PassFailJFrame.log(e.toString()); + } + + public void mouseExited(MouseEvent e) { + PassFailJFrame.log(e.toString()); + } + }; + + public static Frame initialize() { + frame.setLayout(new GridLayout(2, 1)); + frame.add(button); + frame.add(jbutton); + frame.addMouseListener(listener); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java new file mode 100644 index 0000000000000..2ee3993ae4ede --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java @@ -0,0 +1,96 @@ +/* + * 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.Button; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.Window; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +/* + * @test + * @bug 4431868 + * @key headful + * @summary Tests that window totally obscured by its child doesn't receive + * enter/exit events when located over another frame + * @run main MouseEnterExitTest4 + */ + +public class MouseEnterExitTest4 { + static Button button = new Button("Button"); + static Frame frame = new Frame("Mouse Enter/Exit test"); + static Window window = new Window(frame); + static MouseListener listener = new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + throw new RuntimeException("Test failed due to Mouse Enter event"); + } + + public void mouseExited(MouseEvent e) { + throw new RuntimeException("Test failed due to Mouse Exit event"); + } + }; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> { + button.setBackground(Color.red); + window.add(button); + frame.setBounds(100, 100, 300, 300); + window.setBounds(200, 200, 100, 100); + window.addMouseListener(listener); + window.setVisible(true); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(200); + EventQueue.invokeAndWait(() -> robot.mouseMove( + frame.getLocationOnScreen().x + frame.getSize().width / 2, + frame.getLocationOnScreen().y + frame.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(200); + EventQueue.invokeAndWait(() -> robot.mouseMove( + window.getLocationOnScreen().x + window.getSize().width * 2, + window.getLocationOnScreen().y + window.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(500); + System.out.println("Test Passed"); + + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + if (window != null) { + window.dispose(); + } + }); + } + } +} diff --git a/test/jdk/java/awt/Mouse/MousePressedTest.java b/test/jdk/java/awt/Mouse/MousePressedTest.java new file mode 100644 index 0000000000000..721d69bd5ddf0 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MousePressedTest.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +import java.awt.Container; +import java.awt.GridLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JToggleButton; + +/* + * @test + * @bug 4268759 + * @summary Tests whether clicking on the edge of a lightweight button + * causes sticking behavior + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MousePressedTest + */ + +public class MousePressedTest { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Click and hold on the very bottom border (2-pixel-wide border) of the + JButton. Then drag the mouse straight down out of the JButton and + into the JRadioButton, and release the mouse button + 2. If the component remains highlighted as if the mouse button is still + down, the test fails + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static JFrame initialize() { + JFrame f = new JFrame("JButton Test"); + JPanel p = new JPanel(); + p.setLayout(new GridLayout(2, 2)); + JButton b = new JButton("JButton"); + p.add(b); + JCheckBox cb = new JCheckBox("JCheckBox"); + p.add(cb); + JRadioButton rb = new JRadioButton("JRadioButton"); + p.add(rb); + p.add(new JToggleButton("JToggleButton")); + + JScrollPane j = new JScrollPane(p, + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + Container c = f.getContentPane(); + c.setLayout(new GridLayout(1, 1)); + c.add(j); + f.pack(); + return f; + } +} diff --git a/test/jdk/java/awt/Panel/PanelRepaint/PanelRepaint.java b/test/jdk/java/awt/Panel/PanelRepaint/PanelRepaint.java new file mode 100644 index 0000000000000..da8de3947be9a --- /dev/null +++ b/test/jdk/java/awt/Panel/PanelRepaint/PanelRepaint.java @@ -0,0 +1,455 @@ +/* + * 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 4148078 + * @summary Repainting problems in scrolled panel + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PanelRepaint + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Scrollbar; +import java.awt.TextField; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +public class PanelRepaint extends Panel implements FocusListener { + static ScrollPanel sPanel; + static Panel panel; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Using scrollbars or tab keys to scroll the panel and + the panel is messy sometimes, e.g. one row bumps into + another. If all components painted correctly, the test passes. + Otherwise, the test fails. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(PanelRepaint::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Panel Repaint Test"); + f.setLayout(new FlowLayout()); + f.setSize(620, 288); + PanelRepaint pr = new PanelRepaint(); + + panel = new Panel(); + panel.setLayout(null); + panel.setSize(500, 500); + sPanel = new ScrollPanel(panel); + + Button btn = new Button("Open"); + pr.addComp(btn); + btn.setBounds(400, 10, 60, 20); + btn.setActionCommand("OPEN"); + + Button btn1 = new Button("Close"); + pr.addComp(btn1); + btn1.setBounds(400, 50, 60, 20); + btn1.setActionCommand("CLOSE"); + + TextField t1 = new TextField("1"); + pr.addComp(t1); + t1.setBounds(10, 10, 100, 20); + TextField t2 = new TextField("2"); + pr.addComp(t2); + t2.setBounds(10, 50, 100, 20); + TextField t3 = new TextField("3"); + pr.addComp(t3); + t3.setBounds(10, 90, 100, 20); + TextField t4 = new TextField("4"); + pr.addComp(t4); + t4.setBounds(10, 130, 100, 20); + TextField t5 = new TextField("5"); + pr.addComp(t5); + t5.setBounds(10, 170, 100, 20); + TextField t6 = new TextField("6"); + pr.addComp(t6); + t6.setBounds(10, 210, 100, 20); + TextField t7 = new TextField("7"); + pr.addComp(t7); + t7.setBounds(10, 250, 100, 20); + TextField t8 = new TextField("8"); + pr.addComp(t8); + t8.setBounds(10, 290, 100, 20); + TextField t9 = new TextField("9"); + pr.addComp(t9); + t9.setBounds(10, 330, 100, 20); + + TextField t11 = new TextField("1"); + pr.addComp(t11); + t11.setBounds(120, 10, 100, 20); + TextField t12 = new TextField("2"); + pr.addComp(t12); + t12.setBounds(120, 50, 100, 20); + TextField t13 = new TextField("3"); + pr.addComp(t13); + t13.setBounds(120, 90, 100, 20); + TextField t14 = new TextField("4"); + pr.addComp(t14); + t14.setBounds(120, 130, 100, 20); + TextField t15 = new TextField("5"); + pr.addComp(t15); + t15.setBounds(120, 170, 100, 20); + TextField t16 = new TextField("6"); + pr.addComp(t16); + t16.setBounds(120, 210, 100, 20); + TextField t17 = new TextField("7"); + pr.addComp(t17); + t17.setBounds(120, 250, 100, 20); + TextField t18 = new TextField("8"); + pr.addComp(t18); + t18.setBounds(120, 290, 100, 20); + TextField t19 = new TextField("9"); + pr.addComp(t19); + t19.setBounds(120, 330, 100, 20); + + + TextField t21 = new TextField("1"); + pr.addComp(t21); + t21.setBounds(240, 10, 100, 20); + TextField t22 = new TextField("2"); + pr.addComp(t22); + t22.setBounds(240, 50, 100, 20); + TextField t23 = new TextField("3"); + pr.addComp(t23); + t23.setBounds(240, 90, 100, 20); + TextField t24 = new TextField("4"); + pr.addComp(t24); + t24.setBounds(240, 130, 100, 20); + TextField t25 = new TextField("5"); + pr.addComp(t25); + t25.setBounds(240, 170, 100, 20); + TextField t26 = new TextField("6"); + pr.addComp(t26); + t26.setBounds(240, 210, 100, 20); + TextField t27 = new TextField("7"); + pr.addComp(t27); + t27.setBounds(240, 250, 100, 20); + TextField t28 = new TextField("8"); + pr.addComp(t28); + t28.setBounds(240, 290, 100, 20); + TextField t29 = new TextField("9"); + pr.addComp(t29); + t29.setBounds(240, 330, 100, 20); + + pr.add(sPanel); + f.add(pr); + sPanel.setBounds(100, 100, 500, 250); + sPanel.doLayout(); + return f; + } + + public void addComp(Component c) { + panel.add(c); + c.addFocusListener(this); + } + + public void focusGained(FocusEvent e) { + sPanel.showComponent(e.getComponent()); + } + + public void focusLost(FocusEvent e) { + } +} + +class ScrollPanel extends Panel implements AdjustmentListener { + /** + * Constructor + */ + public ScrollPanel(Component c) { + setLayout(null); + setBackground(Color.lightGray); + add(hScroll = new Scrollbar(Scrollbar.HORIZONTAL)); + add(vScroll = new Scrollbar(Scrollbar.VERTICAL)); + add(square = new Panel()); + square.setBackground(Color.lightGray); + add(c); + } + + /** + * Scroll up/down/left/right to show the component specified + * + * @param comp is the component to be shown + */ + public void showComponent(Component comp) { + Component view = getComponent(3); + Rectangle viewRect = view.getBounds(); + Rectangle scrollRect = getBounds(); + Rectangle rect = comp.getBounds(); + while (comp != null) { + Component parent = comp.getParent(); + if (parent == null || parent == view) { + break; + } + Point p = parent.getLocation(); + rect.x += p.x; + rect.y += p.y; + comp = parent; + } + + int i = viewRect.y + rect.y; + int j = (viewRect.y + rect.y + rect.height + ScrollPanel.H_HEIGHT) + - (scrollRect.height); + + if (i < 0) { + vertUpdate(i); + } else if (j > 0) { + vertUpdate(j); + } + + i = viewRect.x + rect.x; + j = (viewRect.x + rect.x + rect.width + (V_WIDTH * 2)) - (scrollRect.width); + + if (i < 0) { + horzUpdate(i); + } else if (j > 0) { + horzUpdate(j); + } + } + + /** + * Returns the panel component of ScrollPanel + * + * @return the panel component of ScrollPanel + */ + public Component getScrolled() { + return getComponent(3); + } + + /** + * updates the scroll panel vertically with value i passed + * + * @param i the value to be updated with + */ + public void vertUpdate(int i) { + update(true, vScroll.getValue() + i); + } + + /** + * updates the scroll panel horizontally with value i passed + * + * @param i the value to be updated with + */ + public void horzUpdate(int i) { + update(false, hScroll.getValue() + i); + } + + /** + * updates the scroll panel vertically if bVert is true else horizontally + * + * @param n is the value + */ + public void update(boolean bVert, int n) { + if (n < 0) n = 0; + if (bVert) { + if (n > max.height) { + n = max.height; + } + if (offset.y != n) { + offset.y = n; + vScroll.setValue(n); + } + } else { + if (n > max.width) { + n = max.width; + } + if (offset.x != n) { + offset.x = n; + hScroll.setValue(n); + } + } + getScrolled().setLocation(-offset.x, -offset.y); + } + + /** + * Implementation of AdjustmentListener + */ + public void adjustmentValueChanged(AdjustmentEvent e) { + boolean bVert = e.getSource() == vScroll; + update(bVert, e.getValue()); + } + + /** + * Reimplementation of Component Methods + */ + public void addNotify() { + super.addNotify(); + vScroll.addAdjustmentListener(this); + hScroll.addAdjustmentListener(this); + } + + public void removeNotify() { + super.removeNotify(); + vScroll.removeAdjustmentListener(this); + hScroll.removeAdjustmentListener(this); + } + + public void setBounds(int x, int y, int w, int h) { + super.setBounds(x, y, w, h); + doLayout(); + } + + public void doLayout() { + Component c = getScrolled(); + Dimension d = c.getSize(); + if (d.width == 0 || d.height == 0) { + d = c.getPreferredSize(); + } + vert = 0; + horz = 0; + Dimension m = getSize(); + if (d.height > m.height || isScroll(true, m.height - horz, 0, d.height)) { + vert = V_WIDTH; + } + if (d.width + vert > m.width || isScroll(false, m.width - vert, 0, d.width)) { + horz = H_HEIGHT; + } + if (d.height + horz > m.height || isScroll(true, m.height - horz, 0, d.height)) { + vert = V_WIDTH; + } + if (d.width + vert > m.width || isScroll(false, m.width - vert, 0, d.width)) { + horz = H_HEIGHT; + } + if (horz != 0) { + if (m.width <= 0) { + m.width = 1; + } + hScroll.setBounds(0, m.height - H_HEIGHT, m.width - vert, H_HEIGHT); + hScroll.setValues(offset.x, m.width - vert, 0, d.width); + int i = d.width / 10; + if (i < 2) { + i = 2; + } + hScroll.setBlockIncrement(i); + i = d.width / 50; + if (i < 1) { + i = 1; + } + hScroll.setUnitIncrement(i); + max.width = d.width; + hScroll.setVisible(true); + } else { + offset.x = 0; + } + if (vert != 0) { + if (m.height <= 0) { + m.height = 1; + } + vScroll.setBounds(m.width - V_WIDTH, 0, V_WIDTH, m.height - horz); + vScroll.setValues(offset.y, m.height - horz, 0, d.height); + int i = d.height / 10; + if (i < 2) i = 2; + vScroll.setBlockIncrement(i); + i = d.height / 50; + if (i < 1) i = 1; + vScroll.setUnitIncrement(i); + max.height = d.height; + vScroll.setVisible(true); + } else { + offset.y = 0; + } + if (horz != 0 && vert != 0) { + square.setBounds(m.width - V_WIDTH, m.height - H_HEIGHT, V_WIDTH, H_HEIGHT); + square.setVisible(true); + } else { + square.setVisible(false); + } + c.setBounds(-offset.x, -offset.y, d.width, d.height); + c.repaint(); + updateScroll(true, offset.y); + updateScroll(false, offset.x); + } + + public Dimension getPreferredSize() { + return getScrolled().getPreferredSize(); + } + + public Dimension getMinimumSize() { + return getScrolled().getMinimumSize(); + } + + boolean isScroll(boolean bVert, int visible, int min, int max) { + int tot = max - min; + int net = tot - visible; + if (net <= 0) { + return false; + } + return true; + } + + void updateScroll(boolean bVert, int n) { + Component c = getScrolled(); + Dimension d = c.getSize(); + Dimension m = getSize(); + m.width -= vert; + m.height -= horz; + if (bVert) { + if (n >= 0 && d.height > m.height) { + if (n + m.height > d.height) + n = d.height - m.height; + } else + n = 0; + update(true, n); + } else { + if (n >= 0 && d.width > m.width) { + if (n + m.width > d.width) + n = d.width - m.width; + } else + n = 0; + update(false, n); + } + } + + static Scrollbar hScroll; + static Scrollbar vScroll; + static int vert = 0; + static int horz = 0; + + static Point offset = new Point(); + static Dimension max = new Dimension(); + // ScrollTimer timer; + static Component square; + final static int V_WIDTH = 17; + final static int H_HEIGHT = 17; +} diff --git a/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java b/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java new file mode 100644 index 0000000000000..51c12964e6295 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java @@ -0,0 +1,220 @@ +/* + * 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. + */ + +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.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Robot; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import java.util.Hashtable; + +/* + * @test + * @bug 4214550 + * @summary Tests that there is no seg fault on repeatedly showing + * PopupMenu by right-clicking Label, Panel or Button + * @key headful + * @run main ActivePopupCrashTest + */ + +public class ActivePopupCrashTest { + private static Frame f; + private static Label l; + private static Button b; + private static Panel p; + + private static volatile Point labelCenter; + private static volatile Point buttonCenter; + private static volatile Point panelCenter; + + public static void main(String[] args) throws Exception { + final int REPEAT_COUNT = 5; + try { + Robot robot = new Robot(); + robot.setAutoDelay(50); + EventQueue.invokeAndWait(ActivePopupCrashTest::createAndShowUI); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + labelCenter = getCenterPoint(l); + buttonCenter = getCenterPoint(b); + panelCenter = getCenterPoint(p); + }); + + for (int i = 0; i < REPEAT_COUNT; i++) { + robot.mouseMove(labelCenter.x, labelCenter.y); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(buttonCenter.x, buttonCenter.y); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(panelCenter.x, panelCenter.y); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + } + + // To close the popup, otherwise test fails on windows with timeout error + robot.mouseMove(panelCenter.x - 5, panelCenter.y - 5); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static Point getCenterPoint(Component component) { + Point p = component.getLocationOnScreen(); + Dimension size = component.getSize(); + return new Point(p.x + size.width / 2, p.y + size.height / 2); + } + + public static void createAndShowUI() { + f = new Frame("ActivePopupCrashTest Test"); + MenuItem item = new MenuItem("file-1"); + item.addActionListener(ActivePopupCrashTest::logActionEvent); + Menu m = new Menu("file"); + m.add(item); + item = new MenuItem("file-2"); + m.add(item); + MenuBar mb = new MenuBar(); + mb.add(m); + + f.setMenuBar(mb); + f.setSize(200, 200); + f.setLayout(new BorderLayout()); + + l = new Label("label"); + addPopup(l, "label"); + f.add(l, BorderLayout.NORTH); + + p = new Panel(); + addPopup(p, "panel"); + f.add(p, BorderLayout.CENTER); + + b = new Button("button"); + addPopup(b, "button"); + f.add(b, BorderLayout.SOUTH); + + f.setSize(400, 300); + f.setLocationRelativeTo(null); + f.setVisible(true); + } + + static void addPopup(Component c, String name) { + PopupMenu pm = new PopupMenu(); + MenuItem mi = new MenuItem(name + "-1"); + mi.addActionListener(ActivePopupCrashTest::logActionEvent); + pm.add(mi); + + mi = new MenuItem(name + "-2"); + pm.add(mi); + + setHash(c, pm); + c.add(pm); + c.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + mouseAction("mouseClicked", e); + } + + @Override + public void mousePressed(MouseEvent e) { + mouseAction("mousePressed", e); + } + + @Override + public void mouseReleased(MouseEvent e) { + mouseAction("mouseReleased", e); + } + }); + } + + static void logActionEvent(ActionEvent e) { + System.out.println("actionPerformed, event=" + e + ", mod=" + getMods(e)); + System.out.println("command=" + e.getActionCommand()); + System.out.println("param=" + e.paramString()); + System.out.println("source=" + e.getSource()); + } + + static String getMods(ActionEvent e) { return getMods(e.getModifiers()); } + + static String getMods(MouseEvent e) { return getMods(e.getModifiers()); } + + static String getMods(int mods) { + String modstr = ""; + if ((mods & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK) { + modstr += (" SHIFT"); + } else if ((mods & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK) { + modstr += (" ALT"); + } else if ((mods & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) { + modstr += (" CTRL"); + } else if ((mods & ActionEvent.META_MASK) == ActionEvent.META_MASK) { + modstr += (" META"); + } + return modstr; + } + + static void mouseAction(String which, MouseEvent e) { + Component c = e.getComponent(); + System.out.println(which + " e = " + e + " , mods = " + getMods(e) + + " , component = " + c); + if (e.isPopupTrigger()) { + System.out.println("isPopup"); + PopupMenu pm = getHash(c); + pm.show(c, c.getWidth() / 2, c.getHeight() / 2); + } + } + + static Hashtable popupTable = new Hashtable<>(); + + static void setHash(Component c, PopupMenu p) { + popupTable.put(c, p); + } + + static PopupMenu getHash(Component c) { + return popupTable.get(c); + } + +} diff --git a/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java b/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java new file mode 100644 index 0000000000000..4d1d4e8f8319b --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java @@ -0,0 +1,126 @@ +/* + * 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 + * 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.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuItem; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Robot; + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 5021183 + * @summary Tests Key Traversal doesn't crash PopupMenu + * @key headful + * @run main KeyTraversalCrash + */ + +public class KeyTraversalCrash { + private static Frame f; + private static Label label; + + private static volatile Point loc; + private static volatile Dimension dim; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); + EventQueue.invokeAndWait(KeyTraversalCrash::createAndShowUI); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + loc = label.getLocationOnScreen(); + dim = label.getSize(); + }); + + robot.mouseMove(loc.x + 20, loc.y + 20); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(loc.x + 25, loc.y + 25); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.keyPress(KeyEvent.VK_LEFT); + robot.keyRelease(KeyEvent.VK_LEFT); + + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + + // To close the popup, otherwise test fails on windows with timeout error + robot.mouseMove(loc.x + dim.width - 20, loc.y + dim.height - 20); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + public static void createAndShowUI() { + f = new Frame("KeyTraversalCrash Test"); + final PopupMenu popup = new PopupMenu(); + for (int i = 0; i < 10; i++) { + Menu menu = new Menu("Menu " + i); + for(int j = 0; j < 10; j++) { + MenuItem menuItem = new MenuItem("MenuItem " + j); + menu.add(menuItem); + } + popup.add(menu); + } + label = new Label("Label"); + f.add(label); + f.add(popup); + label.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent me) { + if (me.isPopupTrigger()) { + popup.show(me.getComponent(), me.getX(), me.getY()); + } + } + + @Override + public void mouseReleased(MouseEvent me) { + if (me.isPopupTrigger()) { + popup.show(me.getComponent(), me.getX(), me.getY()); + } + } + }); + f.setSize(200, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + } +} diff --git a/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java b/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java new file mode 100644 index 0000000000000..f939186ca072e --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java @@ -0,0 +1,86 @@ +/* + * 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.AWTEvent; +import java.awt.Button; +import java.awt.Frame; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4186663 4265525 + * @summary Tests that multiple PopupMenus cannot appear at the same time + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiplePopupMenusTest + */ + +public class MultiplePopupMenusTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click the right mouse button on the button + If multiple popups appear at the same time the + test fails else passes. + """; + + PassFailJFrame.builder() + .title("MultiplePopupMenusTest Instruction") + .instructions(INSTRUCTIONS) + .columns(30) + .testUI(MultiplePopupMenusTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame fr = new Frame("MultiplePopupMenusTest Test"); + TestButton button = new TestButton("button"); + fr.add(button); + fr.setSize(200, 200); + return fr; + } + + static class TestButton extends Button { + public TestButton(String title) { + super(title); + enableEvents(AWTEvent.MOUSE_EVENT_MASK); + } + + @Override + public void processMouseEvent(MouseEvent e) { + if (e.isPopupTrigger()) { + for (int i = 0; i < 10; i++) { + PopupMenu pm = new PopupMenu("Popup " + i); + pm.add(new MenuItem("item 1")); + pm.add(new MenuItem("item 2")); + add(pm); + pm.show(this, e.getX() + i * 5, e.getY() + i * 5); + } + } + super.processMouseEvent(e); + } + } +} diff --git a/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java b/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java new file mode 100644 index 0000000000000..7ba738b21d276 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java @@ -0,0 +1,106 @@ +/* + * 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. + */ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4281273 + * @summary PopupMenu crashed in Java. Simplified testcase. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @requires (os.family == "windows") + * @run main/manual PopupMenuCrash + */ + +public class PopupMenuCrash { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This tests a windows specific problem. + When you see a frame titled "PopupMenuCrash Test", right-click on it + several times for a few seconds. Then wait about 10 seconds before the + PopupMenus start to appear. Then dispose them one by one by clicking on them. + When PopupMenus do not appear anymore, press Pass. + In case of a failure, you'll see a crash. + """; + + PassFailJFrame.builder() + .title("PopupMenuCrash Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(PopupMenuCrash::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + final Frame f = new Frame("PopupMenuCrash Test"); + f.setLayout(new FlowLayout()); + f.add(new Label("Press right mouse button inside this frame.")); + f.add(new Label("A pop-up menu should appear.")); + f.addMouseListener(new MouseAdapter() { + PopupMenu popup; + boolean firstPress = true; + + @Override + public void mousePressed(MouseEvent evt) { + if (firstPress) { + firstPress = false; + try { + Thread.sleep(10000); + } catch (InterruptedException ignored) { + } + } + + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { + popup = new PopupMenu("Popup Menu Title"); + MenuItem mi = new MenuItem("MenuItem"); + popup.add(mi); + f.add(popup); + popup.show(evt.getComponent(), evt.getX(), evt.getY()); + } + } + + @Override + public void mouseReleased(MouseEvent evt) { + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { + if (popup != null) { + f.remove(popup); + popup = null; + } + } + } + }); + + f.setSize(400, 350); + return f; + } +} diff --git a/test/jdk/java/awt/PopupMenu/StressTest.java b/test/jdk/java/awt/PopupMenu/StressTest.java new file mode 100644 index 0000000000000..221aa252aa0b7 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/StressTest.java @@ -0,0 +1,142 @@ +/* + * 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.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Robot; + +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4083400 + * @key headful + * @summary Tests that excessive popping up and down does not crash or + * throw an exception. + * @run main StressTest + */ + +public class StressTest { + private static Frame fr; + private static PopupTestPanel panel; + + private static volatile Point panelCenter; + + public static void main(String[] args) throws Exception { + final int REPEAT_COUNT = 5; + try { + Robot robot = new Robot(); + robot.setAutoDelay(50); + EventQueue.invokeAndWait(StressTest::createAndShowUI); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point loc = panel.getLocationOnScreen(); + Dimension dim = panel.getSize(); + panelCenter = new Point(loc.x + dim.width / 2, loc.y + dim.height / 2); + }); + + for (int i = 0; i < REPEAT_COUNT; i++) { + robot.mouseMove(panelCenter.x + i * 2, panelCenter.y + i * 2); + + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(panelCenter.x - i * 2, panelCenter.y - i * 2); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (fr != null) { + fr.dispose(); + } + }); + } + } + + public static void createAndShowUI() { + fr = new Frame("PopupMenu Test"); + panel = new PopupTestPanel(); + fr.add(panel); + fr.setSize(300, 200); + fr.setVisible(true); + } + + static class PopupTestPanel extends Panel { + + static class Item extends MenuItem { + public Item(String text) { + super(text); + } + + public boolean isEnabled() { + try { + Thread.sleep(100); + } catch (InterruptedException ignored) { + } + return super.isEnabled(); + } + } + + final PopupMenu popup; + + public PopupTestPanel() { + popup = new PopupMenu(); + popup.add(new Item("Soap")); + popup.add(new Item("Sponge")); + popup.add(new Item("Flannel")); + popup.add(new Item("Mat")); + popup.add(new Item("Towel")); + add(popup); + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (e.isPopupTrigger()) { + showPopup(e); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) { + showPopup(e); + } + } + + private void showPopup(MouseEvent e) { + popup.show((Component) e.getSource(), e.getX(), e.getY()); + } + }); + } + } +} diff --git a/test/jdk/java/awt/Rectangle/IntersectionTest.java b/test/jdk/java/awt/Rectangle/IntersectionTest.java new file mode 100644 index 0000000000000..41680b2e7b6b1 --- /dev/null +++ b/test/jdk/java/awt/Rectangle/IntersectionTest.java @@ -0,0 +1,88 @@ +/* + * 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 4147957 + * @key headful + * @summary Test to verify setClip with invalid rect changes rect to valid + * @run main IntersectionTest + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.Robot; + +public class IntersectionTest { + public static Frame frame; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + robot.setAutoDelay(100); + EventQueue.invokeAndWait(() -> { + TestFrame panel = new TestFrame(); + frame = new Frame("Rectangle Intersection Test"); + frame.add(panel); + + frame.pack(); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(200); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } +} + +class TestFrame extends Panel { + @Override + public void paint(Graphics g) { + Rectangle r1 = new Rectangle(0, 0, 100, 100); + Rectangle r2 = new Rectangle(200, 200, 20, 20); + Rectangle r3 = r1.intersection(r2); + System.out.println("intersect:(" + (int) r3.getX() + "," + + (int) r3.getY() + "," + (int) r3.getWidth() + "," + + (int) r3.getHeight() + ")"); + g.setClip(r3); + Rectangle r4 = g.getClipBounds(); + System.out.println("getClipBounds:(" + (int) r4.getX() + "," + + (int) r4.getY() + "," + (int) r4.getWidth() + "," + + (int) r4.getHeight() + ")"); + + if ((r4.getWidth() <= 0) || (r4.getHeight() <= 0)) { + System.out.println("Test Passed"); + } else { + throw new RuntimeException("IntersectionTest failed. " + + "Non-empty clip bounds."); + } + } +} diff --git a/test/jdk/java/awt/TextArea/PrintTextTest.java b/test/jdk/java/awt/TextArea/PrintTextTest.java new file mode 100644 index 0000000000000..8cf1477473285 --- /dev/null +++ b/test/jdk/java/awt/TextArea/PrintTextTest.java @@ -0,0 +1,98 @@ +/* + * 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 + * 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.Frame; +import java.awt.Graphics; +import java.awt.Label; +import java.awt.Panel; +import java.awt.PrintJob; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4075786 + * @key printer + * @summary Test that container prints multiline text properly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PrintTextTest +*/ + +public class PrintTextTest extends Frame implements ActionListener { + Panel p; + + static final String INSTRUCTIONS = """ + Press "Print" button and check that multiline test + printed correctly. If so press Pass, otherwise Fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("PrintTextTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(PrintTextTest::new) + .build() + .awaitAndCheck(); + } + + public PrintTextTest() { + p = new Panel(); + p.setLayout(new BorderLayout()); + TextArea text_area = new TextArea("multi\nline\ntext\nfield\nis \nhere\n!!!!\n"); + + TextField text_field = new TextField("single line textfield"); + Button button = new Button("button"); + Label label = new Label("single line label"); + p.add("South", text_area); + p.add("North", new TextArea("one single line of textarea")); + p.add("Center", text_field); + p.add("West", button); + + add("North", p); + + Button b = new Button("Print"); + b.addActionListener(this); + add("South", b); + pack(); + } + + public void actionPerformed(ActionEvent e) { + PrintJob pjob = getToolkit().getPrintJob(this, "Print", null); + if (pjob != null) { + Graphics pg = pjob.getGraphics(); + + if (pg != null) { + p.printAll(pg); + pg.dispose(); //flush page + } + pjob.end(); + } + } +} diff --git a/test/jdk/java/awt/TextArea/ScrollBarArrowScrollTest.java b/test/jdk/java/awt/TextArea/ScrollBarArrowScrollTest.java new file mode 100644 index 0000000000000..cf54bd5758558 --- /dev/null +++ b/test/jdk/java/awt/TextArea/ScrollBarArrowScrollTest.java @@ -0,0 +1,65 @@ +/* + * 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 + * 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.TextArea; + +/* + * @test + * @bug 6175401 + * @summary Keeping the left arrow pressedon horiz scrollbar + * does not scroll the text in TextArea, XToolkit + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollBarArrowScrollTest +*/ + + +public class ScrollBarArrowScrollTest extends Frame { + private static final String INSTRUCTIONS = """ + 1) Make sure, that the TextArea component has focus. + 2) Press 'END' key in order to keep cursor at the end + of the text of the TextArea component. + 3) Click on the left arrow on the horizontal scrollbar + of the TextArea component and keep it pressed. + 4) If the text just scrolls once and stops, the test failed. + Otherwise, the test passed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ScrollBarArrowScrollTest") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(ScrollBarArrowScrollTest::new) + .build() + .awaitAndCheck(); + } + + public ScrollBarArrowScrollTest() { + TextArea textarea = new TextArea("Very very very long string !!!! ", 10, 3); + add(textarea); + pack(); + + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaAppendScrollTest.java b/test/jdk/java/awt/TextArea/TextAreaAppendScrollTest.java new file mode 100644 index 0000000000000..f506f54f6f141 --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaAppendScrollTest.java @@ -0,0 +1,98 @@ +/* + * 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 + * 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.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 5003402 + * @summary TextArea must scroll automatically when calling append and select, even when not in focus + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaAppendScrollTest + */ + +public class TextAreaAppendScrollTest extends Frame implements ActionListener { + int phase; + int pos1, pos2; + TextArea area; + private static final String INSTRUCTIONS = """ + Press "Click Here" button. + The word "First" should be visible in the TextArea. + + Press "Click Here" button again. + The word "Next" should be visible in the TextArea. + + Press "Click Here" button again. + The word "Last" should be visible in the TextArea. + If you have seen all three words, press Pass, else press Fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextAreaAppendScrollTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(TextAreaAppendScrollTest::new) + .build() + .awaitAndCheck(); + } + + public TextAreaAppendScrollTest() { + area = new TextArea(); + add("Center", area); + Button bt1 = new Button("Click Here"); + add("South", bt1); + String filler = ""; + for (int i = 0; i < 100; i++) { + filler = filler + i + "\n"; + } + String text = filler; + pos1 = text.length(); + text = text + "First\n" + filler; + pos2 = text.length(); + text = text + "Next\n" + filler; + area.setText(text); + phase = 0; + bt1.addActionListener(this); + pack(); + } + + public void actionPerformed(ActionEvent ev) { + if (phase == 0) { + area.select(pos1, pos1); + phase = 1; + } else if (phase == 1) { + area.select(pos2, pos2); + phase = 2; + } else { + area.append("Last\n"); + phase = 0; + } + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaAppendScrollTest2.java b/test/jdk/java/awt/TextArea/TextAreaAppendScrollTest2.java new file mode 100644 index 0000000000000..2f0e44b415e1f --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaAppendScrollTest2.java @@ -0,0 +1,68 @@ +/* + * 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 + * 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.Frame; +import java.awt.TextArea; + +/* + * @test + * @bug 6192116 + * @summary Auto-scrolling does not work properly for TextArea when appending some text, on XToolkit + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaAppendScrollTest2 + */ + +public class TextAreaAppendScrollTest2 extends Frame { + TextArea area; + private static final String INSTRUCTIONS = """ + Press pass if you see exclamation marks in the bottom of textarea. + Press fail if you don't. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextAreaAppendScrollTest2") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(TextAreaAppendScrollTest2::new) + .build() + .awaitAndCheck(); + } + + public TextAreaAppendScrollTest2() { + setLayout(new BorderLayout()); + area = new TextArea("AWT is cool ", 3, 3, TextArea.SCROLLBARS_NONE); + add("Center", area); + setSize(200, 200); + StringBuilder coolStr = new StringBuilder(""); + // I count 15 lines with 12 cools per line + for (int i = 0; i < 12 * 15; i++) { + coolStr.append("cool "); + } + coolStr.append("!!!!!!!"); + area.append(coolStr.toString()); + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaAppendTest.java b/test/jdk/java/awt/TextArea/TextAreaAppendTest.java new file mode 100644 index 0000000000000..c47d621e788a6 --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaAppendTest.java @@ -0,0 +1,68 @@ +/* + * 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.Frame; +import java.awt.TextArea; + +/* + * @test + * @bug 4118915 + * @summary Test appending to a TextArea after the peer is created + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaAppendTest + */ + +public class TextAreaAppendTest { + private static final String INSTRUCTIONS = """ + If all four lines are visible in TextArea, the test passed. + If the last two lines have only one character visible, the test failed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextAreaAppendTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(TextAreaAppendTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Frame f = new Frame("TextAreaAppendTest"); + TextArea ta = new TextArea(); + f.add(ta); + ta.append("line 1 (added before drawing)\n"); + ta.append("line 2 (added before drawing)\n"); + + f.pack(); + f.show(); + + ta.append("line 3 (added after drawing)\n"); + ta.append("line 4 (added after drawing)\n"); + + return f; + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaCRLFAutoDetectManualTest.java b/test/jdk/java/awt/TextArea/TextAreaCRLFAutoDetectManualTest.java new file mode 100644 index 0000000000000..c8c3f0662a5c2 --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaCRLFAutoDetectManualTest.java @@ -0,0 +1,106 @@ +/* + * 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. + */ + +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4800187 + * @summary REGRESSION:show the wrong selection when there are \r characters in the text + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaCRLFAutoDetectManualTest + */ + +public class TextAreaCRLFAutoDetectManualTest { + static int flag = 1; + + private static final String INSTRUCTIONS = """ + Please click the button several times. + If you see the text '679' selected on the left TextArea + and the same text on the right TextArea + each time you press the button, + the test passed, else failed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextAreaCRLFAutoDetectManualTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(TextAreaCRLFAutoDetectManualTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Frame f = new Frame("TextAreaCRLFAutoDetectManualTest"); + + TextArea ta1 = new TextArea(5, 20); + TextArea ta2 = new TextArea(5, 20); + + TextField tf1 = new TextField("123", 20); + TextField tf2 = new TextField("567", 20); + TextField tf3 = new TextField("90", 20); + + Button b = new Button("Click Me Several Times"); + + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + ta1.setText(""); + ta2.setText(""); + flag++; + String eoln = ((flag % 2) != 0) ? "\r\n" : "\n"; + ta1.setText(eoln + tf1.getText() + eoln + tf2.getText() + eoln + tf3.getText() + eoln); + ta1.select(6, 10); + ta2.setText(ta1.getSelectedText()); + ta1.requestFocus(); + } + }); + + f.setLayout(new FlowLayout()); + + Panel tfpanel = new Panel(); + tfpanel.setLayout(new GridLayout(3, 1)); + tfpanel.add(tf1); + tfpanel.add(tf2); + tfpanel.add(tf3); + f.add(tfpanel); + + f.add(ta1); + f.add(ta2); + f.add(b); + + f.pack(); + return f; + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaCursorTest.java b/test/jdk/java/awt/TextArea/TextAreaCursorTest.java new file mode 100644 index 0000000000000..ec342e38a155c --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaCursorTest.java @@ -0,0 +1,86 @@ +/* + * 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 + * 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.Cursor; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4060320 + * @summary Test TextArea cursor shape on its scrollbars + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaCursorTest + */ + +public class TextAreaCursorTest { + private static final String INSTRUCTIONS = """ + Move the cursor into textarea and on scrollbar. Verify that the shape of + cursor on scrollbar should not be I-beam. Also, when the cursor in textarea + is set to some other shape, it does not affect the cursor shape on the + scrollbars. + """; + + public static void main(String args[]) throws Exception { + PassFailJFrame.builder() + .title("TextAreaCursorTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(TextAreaCursorTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI () { + Frame f = new Frame("TextAreaCursorTest"); + BorderLayout layout = new BorderLayout(); + f.setLayout(layout); + + TextArea ta = new TextArea("A test to make sure that cursor \n" + + "on scrollbars has the correct shape\n\n" + + "Press button to change the textarea\n" + + "cursor to Hand_Cursor\n" + + "Make sure that the cursor on scrollbars\n" + + "remains the same", 10, 30); + + Button bu = new Button("Change Cursor"); + + f.add(ta, BorderLayout.NORTH); + f.add(bu, BorderLayout.SOUTH); + bu.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Cursor curs1 = new Cursor(Cursor.HAND_CURSOR); + ta.setCursor(curs1); + } + }); + f.pack(); + return f; + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaHScrollbarTest.java b/test/jdk/java/awt/TextArea/TextAreaHScrollbarTest.java new file mode 100644 index 0000000000000..3bf1c6997638e --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaHScrollbarTest.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +import java.awt.Frame; +import java.awt.TextArea; + +/* + * @test + * @bug 4648702 + * @summary TextArea horizontal scrollbar behavior is incorrect + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaHScrollbarTest + */ + +public class TextAreaHScrollbarTest { + private static final String INSTRUCTIONS = """ + Please look at the frame. + If the vertical and horizontal scrollbars are visible + the test passed else failed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextAreaHScrollbarTest") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TextAreaHScrollbarTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Frame test = new Frame(); + test.add(new TextArea("TextAreaHScrollbarTest", 5, 60, + TextArea.SCROLLBARS_BOTH)); + test.setSize(200, 100); + return test; + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaKeypadTest.java b/test/jdk/java/awt/TextArea/TextAreaKeypadTest.java new file mode 100644 index 0000000000000..24fabdd01ab80 --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaKeypadTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextArea; + +/* + * @test + * @bug 6240876 + * @summary Number pad up & down arrows don't work in XToolkit TextArea + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaKeypadTest + */ + +public class TextAreaKeypadTest { + private static final String INSTRUCTIONS = """ + Press pass if you can move the caret in the textarea with _number pad_ UP/DOWN keys. + Press fail if you don't. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextAreaKeypadTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(TextAreaKeypadTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Frame frame = new Frame("TextAreaKeypadTest"); + frame.setLayout(new BorderLayout()); + TextArea area = new TextArea("One\nTwo\nThree", 3, 3, TextArea.SCROLLBARS_NONE); + frame.add("Center", area); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaLimit.java b/test/jdk/java/awt/TextArea/TextAreaLimit.java new file mode 100644 index 0000000000000..424305c90ead1 --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaLimit.java @@ -0,0 +1,70 @@ +/* + * 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 + * 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.Frame; +import java.awt.TextArea; + +/* + * @test + * @bug 4341196 + * @summary Tests that TextArea can handle more than 64K of text + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaLimit + */ + +public class TextAreaLimit extends Frame { + static TextArea text; + private static final String INSTRUCTIONS = """ + You will see a text area with 40000 lines of text + each with its own line number. If you see the caret after line 39999 + then test passes. Otherwise it fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextAreaLimit") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(TextAreaLimit::new) + .build() + .awaitAndCheck(); + } + + public TextAreaLimit() { + setLayout(new BorderLayout()); + + text = new TextArea(); + add(text); + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < 40000; i++) { + buf.append(i + "\n"); + } + text.setText(buf.toString()); + text.setCaretPosition(buf.length()); + text.requestFocus(); + setSize(200, 200); + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaLineScrollWrapTest.java b/test/jdk/java/awt/TextArea/TextAreaLineScrollWrapTest.java new file mode 100644 index 0000000000000..72ec7c08a6ce4 --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaLineScrollWrapTest.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +import java.awt.Frame; +import java.awt.TextArea; + +/* + * @test + * @bug 4776535 + * @summary Regression: line should not wrap around into multi lines in TextArea. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaLineScrollWrapTest + */ + +public class TextAreaLineScrollWrapTest { + private static final String INSTRUCTIONS = """ + You should see a frame "TextAreaLineScrollWrapTest" with + a TextArea that contains a very long line. + If the line is wrapped the test is failed. + + Insert a lot of text lines and move a caret to the last one. + If a caret hides and a content of the TextArea + does not scroll the test is failed + else the test is passed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextAreaLineScrollWrapTest") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TextAreaLineScrollWrapTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Frame f = new Frame("TextAreaLineScrollWrapTest"); + f.add(new TextArea("long long long long long long long line...........", + 3, 4)); + f.setSize(100, 100); + return f; + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaScrollbarTest.java b/test/jdk/java/awt/TextArea/TextAreaScrollbarTest.java new file mode 100644 index 0000000000000..ee61922fdb16b --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaScrollbarTest.java @@ -0,0 +1,116 @@ +/* + * 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.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.TextArea; + +/* + * @test + * @bug 4158997 + * @key headful + * @summary Make sure that the TextArea has both horizontal and + * vertical scrollbars when bad scrollbar arguments are passed + * into the constructor. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaScrollbarTest + */ + +public class TextAreaScrollbarTest { + private static final String INSTRUCTIONS = """ + Check to see that each TextArea has the specified + number and placement of scrollbars, i.e., both scrollbars, + horizontal only, vertical only, or no scrollbars at all. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextAreaScrollbarTest") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(TestFrame::new) + .build() + .awaitAndCheck(); + } +} + +class TestFrame extends Frame { + private String both = "Both Scrollbars Both Scrollbars Both Scrollbars\n"; + private String horiz = "Horizontal Scrollbar Only Horizontal Scrollbar Only\n"; + private String vert = "Vertical Scrollbar Only Vertical Scrollbar Only\n"; + private String none = "No Scrollbars No Scrollbars No Scrollbars No Scrollbars\n"; + + public TestFrame() { + super("Test frame"); + + // sets a GridLayout w/ 2 columns and an unspecified # of rows + setLayout(new GridLayout(0, 2, 15, 5)); + + TextArea t1 = new TextArea(both + both + both + both + both + both, 3, 8, 0); + add(new Label("TA should have both scrollbars: arg = 0")); + add(t1); + + TextArea t2 = new TextArea(both + both + both + both + both + both, 3, 8, -1); + add(new Label("TA should have both scrollbars: arg = -1")); + add(t2); + + TextArea t3 = new TextArea(both + both + both + both + both + both, 3, 8, 4); + add(new Label("TA should have both scrollbars: arg = 4")); + add(t3); + + TextArea t4 = new TextArea(horiz + horiz + horiz + horiz + horiz + horiz, 3, 8, 2); + add(new Label("TA should have horizontal scrollbar: arg = 2")); + add(t4); + + TextArea t5 = new TextArea(vert + vert + vert + vert + vert + vert, 3, 8, 1); + add(new Label("TA should have vertical scrollbar: arg = 1")); + add(t5); + + TextArea t6 = new TextArea(none + none + none + none + none + none, 3, 8, 3); + add(new Label("TA should have no scrollbars: arg = 3")); + add(t6); + + TextArea t7 = new TextArea(); + t7.setText(both + both + both + both + both + both); + add(new Label("Both scrollbars: TextArea()")); + add(t7); + + TextArea t8 = new TextArea(both + both + both + both + both + both); + add(new Label("Both scrollbars: TextArea(String text)")); + add(t8); + + TextArea t9 = new TextArea(3, 8); + t9.setText(both + both + both + both + both + both); + add(new Label("Both scrollbars: TextArea(int rows, int columns)")); + add(t9); + + TextArea t10 = new TextArea(both + both + both + both + both + both, 3, 8); + add(new Label("Both scrollbars: TextArea(text, rows, columns)")); + add(t10); + + setSize(600, 600); + } +} + diff --git a/test/jdk/java/awt/TextArea/TextAreaSelectionTest.java b/test/jdk/java/awt/TextArea/TextAreaSelectionTest.java new file mode 100644 index 0000000000000..ed6ccb34fa253 --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextAreaSelectionTest.java @@ -0,0 +1,111 @@ +/* + * 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 + * 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.FlowLayout; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.TextArea; +import java.awt.TextField; + +/* + * @test + * @bug 4095946 + * @summary 592677:TEXTFIELD TAB SELECTION CONFUSING; REMOVE ES_NOHIDESEL STYLE IN + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAreaSelectionTest + */ + +public class TextAreaSelectionTest { + private static final String INSTRUCTIONS = """ + Please look at the 'TextAreaSelectionTest' frame. + + If you see that the all TextFields and TextAreas have + the highlighted selections, the test FAILED. Else, if + you see that the text of the focused component is + highlighted, it is ok. + + Try to traverse the focus through all components by + pressing CTRL+TAB. If the focused component highlights + its selection, the test is passed for a while. + + Please select the entire/part of the text of some component + by mouse and choose some menu item. If the highlighted + selection is hidden, the test FAILED. + + Please select the entire/part of the text of some component + by mouse and click right mouse button. A context menu + should appear. Please check its items. + Press ESC to hide the context menu. If the selection + of the text component is not visible, the test FAILED. + + Please double click on the word 'DoubleClickMe' in the + first text area. If there are several words selected, the + test FAILED, if the word 'DoubleClickMe' is selected only, + the test PASSED! + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextAreaSelectionTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(TextAreaSelectionTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Frame f = new Frame("TextAreaSelectionTest"); + f.setLayout(new FlowLayout()); + + MenuBar mb = new MenuBar(); + String name = "Submenu"; + Menu m = new Menu(name, false); + m.add(new MenuItem(name + " item 1")); + m.add(new MenuItem(name + " item 2")); + m.add(new MenuItem(name + " item 3")); + mb.add(m); + + TextField tf1, tf2; + TextArea ta1, ta2; + f.setMenuBar(mb); + f.add(tf1 = new TextField("some text")); + f.add(tf2 = new TextField("more text")); + String eoln = System.getProperty("line.separator", "\n"); + f.add(ta1 = new TextArea("some text" + eoln + eoln + "DoubleClickMe")); + f.add(ta2 = new TextArea("more text")); + + tf1.selectAll(); + tf2.selectAll(); + ta1.selectAll(); + ta2.selectAll(); + + f.pack(); + return f; + } + +} diff --git a/test/jdk/java/awt/TextArea/TextScrollTest.java b/test/jdk/java/awt/TextArea/TextScrollTest.java new file mode 100644 index 0000000000000..4a92391e7af58 --- /dev/null +++ b/test/jdk/java/awt/TextArea/TextScrollTest.java @@ -0,0 +1,69 @@ +/* + * 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.BorderLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; + +/* + * @test + * @bug 4127272 + * @summary TextArea displays head of text when scrolling horizontal bar. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextScrollTest + */ + +public class TextScrollTest extends Frame { + private static final String INSTRUCTIONS = """ + 1. A TextArea whose content starts with the text ", + 'Scroll till the' will appear on the applet ", + 2. Use the Horizontal thumb button of the TextArea to view the entire", + content of the TextArea", + 3. While scrolling, if the text 'Scroll till the' appears repeatedly, Click Fail ", + else Click Pass" + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TextScrollTest") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TextScrollTest::new) + .build() + .awaitAndCheck(); + } + + public TextScrollTest() { + this.setLayout(new BorderLayout()); + + Panel p = new Panel(); + TextArea ta = new TextArea("Scroll till the right end of the " + + "TextArea is reached. Action Done?\n", 10, 20); + + p.add(ta); + add("Center", p); + setSize(200, 200); + } +} diff --git a/test/jdk/java/awt/TextArea/WordWrappingTest.java b/test/jdk/java/awt/TextArea/WordWrappingTest.java new file mode 100644 index 0000000000000..7309bc5100823 --- /dev/null +++ b/test/jdk/java/awt/TextArea/WordWrappingTest.java @@ -0,0 +1,66 @@ +/* + * 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 + * 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.FlowLayout; +import java.awt.Frame; +import java.awt.TextArea; + +/* + * @test + * @bug 4992455 + * @summary REGRESSION: TextArea does not wrap text in JDK 1.5 as JDK 1.4.x + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual WordWrappingTest +*/ + +public class WordWrappingTest { + private static final String INSTRUCTIONS = """ + Please look at the frame 'WordWrappingTest' + It contains two TextAreas that have text 'This text should be wrapped.' + One of them has a vertical scrollbar only. Another has no + scrollbars at all. + If their text is not wrapped at word boundaries and you partially see + mentioned text, the test failed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("WordWrappingTest") + .instructions(INSTRUCTIONS) + .testUI(WordWrappingTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Frame f = new Frame("WordWrappingTest"); + f.setLayout(new FlowLayout()); + f.add(new TextArea("This text should be wrapped.", 5, 10, + TextArea.SCROLLBARS_VERTICAL_ONLY)); + f.add(new TextArea("This text should be wrapped.", 5, 10, + TextArea.SCROLLBARS_NONE)); + f.pack(); + return f; + } +} diff --git a/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java b/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java new file mode 100644 index 0000000000000..e97f645bec594 --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6267936 + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary Tests that the previous image in TrayIcon is cleared + * when a new image is set + * @run main/manual ClearPrevImageTest + */ + +public class ClearPrevImageTest { + private static SystemTray tray; + private static TrayIcon icon; + private static final String INSTRUCTIONS = """ + This test checks that the previous image in TrayIcon is cleared + when a new image is set. + + When the test starts, a RED square TrayIcon is added + to the SystemTray (also, called Taskbar Status Area in MS Windows, + Notification Area in, GNOME and System Tray in KDE). + + You should see it change into YELLOW after 5 seconds. + If you still see RED TrayIcon after 5 seconds, + press FAIL, otherwise press PASS + """; + + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + + PassFailJFrame passFailJFrame + = PassFailJFrame.builder() + .title("TrayIcon Change Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .build(); + + EventQueue.invokeAndWait(ClearPrevImageTest::createAndShowTrayIcon); + try { + changeTrayIcon(); + passFailJFrame.awaitAndCheck(); + } catch (Exception e) { + throw new RuntimeException("Test failed: ", e); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static void createAndShowTrayIcon() { + Image img1 = createIcon(Color.RED); + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(img1); + icon.setImageAutoSize(true); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + } + + private static void changeTrayIcon() { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Image img2 = createIcon(Color.YELLOW); + icon.setImage(img2); + } + + private static Image createIcon(Color color) { + BufferedImage image = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setColor(color); + g.fillRect(0, 0, 16, 16); + g.dispose(); + return image; + } +} diff --git a/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java b/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java new file mode 100644 index 0000000000000..bd831ce94e4c0 --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.SystemTray; +import java.awt.TextArea; +import java.awt.TrayIcon; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6269309 + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary Tests that focus is transferred properly back + * to toplevel after clicking on a tray icon. + * @run main/manual FocusLostAfterTrayTest + */ + +public class FocusLostAfterTrayTest { + private static SystemTray tray; + private static TrayIcon icon; + + private static final String INSTRUCTIONS = """ + This test checks that focus is transferred properly back + to top-level after clicking on a tray icon. + + When the test starts, a Frame with a text area & a RED tray icon + are shown. If you don't see a tray icon please make sure that + the tray area (also called Taskbar Status Area on MS Windows + Notification Area on Gnome or System Tray on KDE) is visible. + + Click with a mouse inside a text area and make sure that it has + received input focus. Then click on the tray icon and then back + on the text area and verify that it has input focus again. Repeat + the last step several times. Ensure that the text area always + has the input focus and there are no "FOCUS LOST" event + for text area in the log section. + + If above is true, Press PASS, else FAIL. + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + + try { + PassFailJFrame.builder() + .title("FocusLostAfterTrayTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(FocusLostAfterTrayTest::createAndShowTrayIcon) + .logArea() + .build() + .awaitAndCheck(); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static Frame createAndShowTrayIcon() { + Frame frame = new Frame("FocusLostAfterTrayTest"); + frame.setBounds(100, 300, 200, 200); + frame.setLayout(new BorderLayout()); + TextArea ta = new TextArea(); + ta.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + PassFailJFrame.log("FOCUS GAINED: " + + e.getComponent().getClass().toString()); + } + @Override + public void focusLost(FocusEvent e) { + PassFailJFrame.log("FOCUS LOST !! " + + e.getComponent().getClass().toString()); + } + }); + frame.add(ta); + + BufferedImage image = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setColor(Color.RED); + g.fillRect(0, 0, 16, 16); + g.dispose(); + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(image); + icon.setImageAutoSize(true); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + return frame; + } +} diff --git a/test/jdk/java/awt/TrayIcon/MouseMoveTest.java b/test/jdk/java/awt/TrayIcon/MouseMoveTest.java new file mode 100644 index 0000000000000..51d80ff127b1b --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/MouseMoveTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6267980 + * @summary PIT:Spurious MouseMoved events are triggered by Tray Icon + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @run main/manual MouseMoveTest + */ + +public class MouseMoveTest { + private static SystemTray tray; + private static TrayIcon icon; + private static final String INSTRUCTIONS = """ + 1) You will see a tray icon (white square) in notification area, + 2) Move mouse pointer to the icon and leave it somewhere inside the icon, + 3) Verify that MOUSE_MOVE events are NOT triggered after you have STOPPED + moving mouse. + 4) If events are still triggered Press FAIL else PASS. + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + + PassFailJFrame passFailJFrame + = PassFailJFrame.builder() + .title("TrayIcon Change Test Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .logArea() + .build(); + + try { + EventQueue.invokeAndWait(MouseMoveTest::createAndShowTrayIcon); + passFailJFrame.awaitAndCheck(); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static void createAndShowTrayIcon() { + BufferedImage img = new BufferedImage(32, 32, + BufferedImage.TYPE_INT_ARGB); + Graphics g = img.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, 32, 32); + g.dispose(); + + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(img); + icon.setImageAutoSize(true); + + icon.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseMoved(MouseEvent me){ + PassFailJFrame.log(me.toString()); + } + }); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + } +} diff --git a/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java b/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java new file mode 100644 index 0000000000000..5e41f54638236 --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6267943 + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary Tests the possibility of selecting a tray icon with the keyboard. + * @run main/manual TrayIconKeySelectTest + */ + +public class TrayIconKeySelectTest { + private static SystemTray tray; + private static TrayIcon icon; + private static final String INSTRUCTIONS = """ + Tests that TrayIcon is selectable with the keyboard + When the test is started you will see three-color icon + in the system tray. + + 1. Bring the focus to the icon with TAB. Press ENTER key. + - One or more ActionEvent should be generated + (see the output area of the test) + + 2. Bring the focus again to the icon. Press SPACE key twice. + - One or more ActionEvent should be generated. + + 3. Bring the focus again to the icon. Click on the icon with + the LEFT mouse button twice. + - One or more ActionEvent should be generated. + + 4. Again bring the focus to the icon. Click on the icon with + the LEFT mouse button just once. + - NO ActionEvent should be generated. + + 5. Repeat the 4th step with other mouse buttons. + + If all the above are true press PASS, else FAIL + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + PassFailJFrame passFailJFrame; + try { + passFailJFrame + = PassFailJFrame.builder() + .title("TrayIconKeySelectTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build(); + + EventQueue.invokeAndWait(TrayIconKeySelectTest::createAndShowTrayIcon); + passFailJFrame.awaitAndCheck(); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static void createAndShowTrayIcon() { + BufferedImage im = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics gr = im.createGraphics(); + gr.setColor(Color.white); + gr.fillRect(0, 0, 16, 5); + gr.setColor(Color.blue); + gr.fillRect(0, 5, 16, 10); + gr.setColor(Color.red); + gr.fillRect(0, 10, 16, 16); + gr.dispose(); + + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(im); + icon.setImageAutoSize(true); + icon.addActionListener(e -> PassFailJFrame.log(e.toString())); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + } +} diff --git a/test/jdk/java/awt/TrayIcon/TrayIconTest.java b/test/jdk/java/awt/TrayIcon/TrayIconTest.java new file mode 100644 index 0000000000000..c78f6c134fed3 --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/TrayIconTest.java @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Container; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Label; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.RenderingHints; +import java.awt.SystemTray; +import java.awt.TextField; +import java.awt.Toolkit; +import java.awt.TrayIcon; +import java.awt.TrayIcon.MessageType; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeEvent; +import java.util.HashMap; +import java.util.Map; +import jtreg.SkippedException; + +/* + * @test + * @key headful + * @bug 4310333 + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary A unit test for TrayIcon RFE + * @run main/manual TrayIconTest + */ + +public class TrayIconTest { + private static SystemTray tray; + static Frame frame = new Frame("TrayIcon Test"); + private static final String INSTRUCTIONS = """ + The test frame contains CheckboxGroup of tray icons. + A selected checkbox represents the TrayIcon (or null + TrayIcon) whose functionality is currently tested. + + If you are under Linux make sure your Application Panel has + System Tray (on Gnome it is called Notification Area). + + Perform all the cases (1-7) documented below. + + CASE 1: Testing ADD/REMOVE/PropertyChange functionality. + -------------------------------------------------------- + 1. Select null TrayIcon and pressAdd button: + - NullPointerException should be thrown. + 2. Select some of the valid TrayIcons and press Add button: + - The selected TrayIcon should appear in the SystemTray. + - PropertyChangeEvent should be fired (the property is + an array of TrayIcons added to the system tray). + 3. Press Add button again: + - IllegalArgumentException should be thrown. + - No PropertyChangeEvent should be fired. + 4. Press Remove button: + - The TrayIcon should disappear from the SystemTray. + - PropertyChangeEvent should be fired. + 5. Press Remove button again: + - It should have no effect. + - No PropertyChangeEvent should be fired. + 6. Add all the valid TrayIcons (by selecting everyone and pressing Add + button): + - All the TrayIcons should appear in the SystemTray. + - PropertyChangeEvent should be fired on each adding. + 7. Remove all the TrayIcons (again by selecting everyone and pressing + Remove): + - All the TrayIcons should disappear from the SystemTray. + - PropertyChangeEvent should be fired on each removing. + 8. Not for Windows! Remove the system tray (Notification Area) from + the desktop. Try to add some valid TrayIcon: + - AWTException should be thrown. + - No PropertyChangeEvent should be fired. + 9. Not for Windows! Add the system tray back to the desktop. Add all the + valid TrayIcons: + - All the TrayIcons should appear in the system tray. + - PropertyChangeEvent should be fired on each adding. + 11. Not for Windows! Remove the system tray from the desktop: + - All the TrayIcons should disappear. + - PropertyChangeEvent should be fired for each TrayIcon + removal. + - PropertyChangeEvent should be fired for SystemTray removal. + 12. Add the system tray and go to the next step. + - All the TrayIcons should appear again. + - PropertyChangeEvent should be fired for SystemTray addition. + - PropertyChangeEvent shouldn't be fired for TrayIcon removal. + + CASE 2: Testing RESIZE functionality. + ------------------------------------- + 1. Select some of the TrayIcons and add it. Then press resize button: + - The TrayIcon selected should be resized to fit the area it occupies. + 2. Press resize button again: + - The TrayIcon should be resized to the original size. + 3. Repeat the 1-2 steps for other TrayIcons: + - The TrayIcons should be resized appropriately. + + CASE 3: Testing EVENTS functionality + --------------------------------- + 1. Select some of the TrayIcons and add it. Select MouseEvent from the + group of checkboxes at the top-right of the test frame. + Click on the TrayIcon in the SystemTray: + - MOUSE_PRESSED MOUSE_RELEASED and MOUSE_CLICKED events should be + generated. + 2. Press mouse inside the TrayIcon dragging mouse and releasing it. + - Make sure that MOUSE_CLICKED event is not triggered. + 3. Click on the TrayIcon with different modification keys: + - there should be appropriate modifiers in the events. + 4. Keep clicking on the TrayIcon: + - there should be correct absolute coordinates in the events. + 5. Only for Windows! Focus the system tray using keyboard: + - press WIN key once to bring up the start menu then press ESC once to + close the menu the focus should be on the start button + - press TAB key for several times until you focus on the system + tray then use ARROW keys to move to the TrayIcon + - press ENTER or SPACE should trigger ACTION_PERFORMED message + make sure that mouse events are not triggered. + 6. Select MouseMotionEvent checkbox. Move mouse over the TrayIcon: + - MOUSE_MOVED event should be generated. It should contain + correct coordinates. + 7. Deselect both the checkboxes and then select AWTEventListener. + Click on the TrayIcon and then move mouse over it: + - Appropriate mouse events should be generated (catched by the + AWTEventListener). + 8. Deselect all the checkboxes and go to the following step. + + CASE 4: Testing DISPLAY MESSAGE functionality. + ---------------------------------------------- + 1. Select some of the TrayIcons and add it. Then press Display message + button: + - A balloon message should appear near the TrayIcon. + 2. After the message is displayed wait for some period: + - The message window should be closed automatically. + 3. Display the message again. Close it by pressing X in its top-right + corner: + - The message window should be closed immediately. + 4. Display the message again. Click inside it: + - The message should be closed an ACTION_PERFORMED event should be + generated with correct information and an Ok dialog should appear. + Close the dialog. + 5. Select a message type from the Type choice and display the message + again: + - It should contain an icon appropriate to the message type selected + or no icon if NONE is selected. + 6. Change the content of the Message and Caption text fields and + display the message: + - The message content should be changed in the accordance with the text + typed. + 7. Not for Windows! Type some too long or too short text for the Caption + and Message: + - The message should process the text correctly. The long text should + be cut. + 8. Not for Windows! Type null in the Message text field and display + the message: + - The message body should contain no text. + 9. Type null in the Caption text field and display the message: + - The message caption should contain no text. + 10. Type null in the both Message and Caption fields and display + the message: + - NullPointerException should be generated and no message should be + displayed. + 11. Try to hide the taskbar. Click Display message for several times. + Then restore the taskbar. Click on the TrayIcon: + - No message should appear. + Try to display the message once more: + - It should appear appropriately. + 12. Try to display the message for other TrayIcons: + - The messages should be displayed appropriately. + + CASE 5: Testing POPUP MENU functionality. + ----------------------------------------- + 1. Add some TrayIcon to the system tray. Press Set button in the + Popup menu test area. Trigger the popup menu for the TrayIcon with + the mouse: + - A popup menu should appear. Make sure it behaves properly. + - Make sure the 'duke.gif' image is animated while the popup menu is shown. + 2. Press Remove button for the popup menu and try to trigger it again: + - No popup menu should appear. + 3. Perform 1-2 steps for other TrayIcons: + - Make sure the popup menu behaves properly. + 4. Add more than one TrayIcons to the system tray. Press Set button in + the PopupMenu test area for some of the TrayIcon added. Trigger + the popup menu for this TrayIcon: + - A popup menu should appear properly. + 5. Try to set the popup menu to the same TrayIcon again: + - It should have no effect + 6. Try to set the popup menu for other TrayIcons you've added to the system + tray: + - for each one IllegalArgumentException should be thrown. + + CASE 6: Testing TOOLTIP functionality. + -------------------------------------- + 1. Type something in the Tooltip text field and press Set button. + Then move mouse cursor over the TrayIcon and wait for a second: + - A tooltip should appear containing the text typed. + 2. Show a tooltip again and keep your mouse over the TrayIcon for some period: + - The tooltip should disappear automatically. + 3. Show a tooltip again and leave the TrayIcon: + - The tooltip should disappear immediately. + 4. Type null in the Tooltip field and press set then move your + mouse to the SystemTray: + - The tooltip shouldn't appear. + 5. Type something too long in the Tooltip field and show the tooltip: + - The tooltip text should be cut. + + CASE 7: Testing ACTION functionality. + ------------------------------------- + 1. Add some TrayIcon to the system tray. Double click it with the left mouse + button: + - An ACTION_PERFORMED event should be generated. + 2. Double click the TrayIcon with the left mouse button several times: + - Several ACTION_PERFORMED events should be generated + - Make sure that the time-stamp of each event ('when' field) is increased. + + If all the above cases work as expected Press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + try { + PassFailJFrame.builder() + .title("TrayIconTest Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .rows(40) + .testUI(TrayIconTest::createAndShowUI) + .logArea(10) + .build() + .awaitAndCheck(); + + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + //Remove any remaining tray icons before ending the test. + TrayIcon[] icons = tray.getTrayIcons(); + for (TrayIcon icon : icons) { + tray.remove(icon); + } + } + }); + } + } + + private static Frame createAndShowUI() { + final TrayIconControl ctrl = new TrayIconControl(); + frame.setLayout(new BorderLayout()); + frame.add(ctrl.cont, BorderLayout.CENTER); + frame.setBackground(Color.LIGHT_GRAY); + + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + ctrl.dispose(); + } + }); + + frame.pack(); + return frame; + } + + private static class TrayIconControl { + final String RED_ICON = "RED ICON"; + final String BLUE_ICON = "BLUE ICON"; + final String GREEN_ICON = "GREEN ICON"; + + CheckboxGroup cbg = new CheckboxGroup(); + Button addButton = new PackedButton(" Add "); + Button remButton = new PackedButton("Remove"); + Button resizeButton = new PackedButton("Resize"); + Button balloonButton = new PackedButton("Display message"); + Choice balloonChoice = new Choice(); + String[] balloonTypes = new String[] { "ERROR", "WARNING", "INFO", "NONE" }; + + TextField balloonText = new TextField( + "A TrayIcon can generate various MouseEvents and" + + " supports adding corresponding listeners to receive" + + " notification of these events. TrayIcon processes" + + " some of the events by itself. For example," + + " by default, when the right-mouse click", 70); + TextField balloonCaption = new TextField("TrayIcon", 70); + + MessageType[] typeArr = new MessageType[] { MessageType.ERROR, MessageType.WARNING, + MessageType.INFO, MessageType.NONE }; + Checkbox mouseListenerCbox = new Checkbox("MouseEvent"); + Checkbox motionListenerCbox = new Checkbox(" MouseMotionEvent"); + Checkbox awtListenerCbox = new Checkbox(" AWTEventListener"); + TextField tipText = new TextField("TrayIcon", 50); + Button tipButton = new PackedButton("Set"); + Button setPopupButton = new PackedButton("Set"); + Button remPopupButton = new PackedButton("Remove"); + + PopupMenu popupMenu = new PopupMenu(); + + Map resToObjMap = new HashMap<>(); + + Container cont = new Container(); + + TrayIconControl() { + Toolkit.getDefaultToolkit().addAWTEventListener(e -> { + if (e.getSource() instanceof TrayIcon && awtListenerCbox.getState()) { + PassFailJFrame.log(e.toString()); + } + }, MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK | + ActionEvent.ACTION_EVENT_MASK); + + cont.setLayout(new GridLayout(4, 1)); + + Container raw1 = new Container(); + raw1.setLayout(new GridLayout(1, 4)); + cont.add(raw1); + + InsetsPanel cbgPanel = new InsetsPanel(); + cbgPanel.setLayout(new GridLayout(4, 1)); + Checkbox nullCbox = new Checkbox("null", cbg, true); + Checkbox redCbox = new Checkbox(RED_ICON, cbg, false); + Checkbox blueCbox = new Checkbox(BLUE_ICON, cbg, false); + Checkbox greenCbox = new Checkbox(GREEN_ICON, cbg, false); + cbgPanel.add(nullCbox); + cbgPanel.add(redCbox); + cbgPanel.add(blueCbox); + cbgPanel.add(greenCbox); + cbgPanel.addTo(raw1); + + InsetsPanel addremPanel = new InsetsPanel(); + addremPanel.setLayout(new BorderLayout()); + addremPanel.add(addButton.getParent(), BorderLayout.NORTH); + addremPanel.add(remButton.getParent(), BorderLayout.SOUTH); + addremPanel.addTo(raw1); + + InsetsPanel resizePanel = new InsetsPanel(); + resizePanel.add(resizeButton); + resizePanel.addTo(raw1); + + InsetsPanel lstPanel = new InsetsPanel(); + lstPanel.setLayout(new GridLayout(3, 1)); + lstPanel.add(mouseListenerCbox); + lstPanel.add(motionListenerCbox); + lstPanel.add(awtListenerCbox); + lstPanel.addTo(raw1); + + Container raw2 = new Container(); + raw2.setLayout(new BorderLayout()); + cont.add(raw2); + + InsetsPanel balloonPanel = new InsetsPanel(); + balloonPanel.setLayout(new BorderLayout()); + balloonPanel.add(balloonButton.getParent(), BorderLayout.NORTH); + Container bc = new Container(); + bc.setLayout(new FlowLayout()); + bc.add(new Label(" Type:")); + bc.add(balloonChoice); + balloonPanel.add(bc, BorderLayout.SOUTH); + balloonPanel.addTo(raw2, BorderLayout.WEST); + + InsetsPanel blnTextPanel = new InsetsPanel(); + blnTextPanel.setLayout(new GridLayout(2, 2)); + Container c1 = new Panel(); + c1.setLayout(new FlowLayout()); + blnTextPanel.add(c1); + c1.add(new Label("Message:")); + c1.add(balloonText); + + Container c2 = new Panel(); + c2.setLayout(new FlowLayout()); + blnTextPanel.add(c2); + c2.add(new Label("Caption:")); + c2.add(balloonCaption); + blnTextPanel.addTo(raw2, BorderLayout.CENTER); + + + Container raw3 = new Container(); + raw3.setLayout(new BorderLayout()); + cont.add(raw3); + + InsetsPanel popupPanel = new InsetsPanel(); + popupPanel.setLayout(new FlowLayout()); + popupPanel.add(new Label("Popup menu:")); + popupPanel.add(setPopupButton); + popupPanel.add(remPopupButton); + popupPanel.addTo(raw3); + + + Container raw4 = new Container(); + raw4.setLayout(new BorderLayout()); + cont.add(raw4); + + InsetsPanel tipPanel = new InsetsPanel(); + tipPanel.setLayout(new FlowLayout()); + tipPanel.add(new Label("Tooltip:")); + tipPanel.add(tipText); + tipPanel.add(tipButton); + tipPanel.addTo(raw4); + + addButton.addActionListener(e -> { + try { + tray.add(getCurIcon()); + } catch (NullPointerException npe) { + if (npe.getMessage() == null) { + PassFailJFrame.log("Probably wrong path to the images."); + throw npe; // if wrong images path was set + } + PassFailJFrame.log(npe.toString()); + } catch (IllegalArgumentException iae) { + PassFailJFrame.log(iae.toString()); + } catch (AWTException ise) { + PassFailJFrame.log(ise.toString()); + } + }); + remButton.addActionListener(e -> tray.remove(getCurIcon())); + + resizeButton.addActionListener( + e -> getCurIcon().setImageAutoSize(!getCurIcon().isImageAutoSize())); + + balloonButton.addActionListener(e -> { + String text = null, caption = null; + if (balloonText.getText().compareToIgnoreCase("null") != 0) { + text = balloonText.getText(); + } + if (balloonCaption.getText().compareToIgnoreCase("null") != 0) { + caption = balloonCaption.getText(); + } + try { + getCurIcon().displayMessage(caption, text, typeArr[balloonChoice.getSelectedIndex()]); + } catch (NullPointerException npe) { + PassFailJFrame.log(npe.toString()); + } + }); + + tipButton.addActionListener(e -> { + String tip = null; + if (tipText.getText().compareToIgnoreCase("null") != 0) { + tip = tipText.getText(); + } + getCurIcon().setToolTip(tip); + }); + + setPopupButton.addActionListener(e -> { + try { + getCurIcon().setPopupMenu(popupMenu); + } catch (IllegalArgumentException iae) { + PassFailJFrame.log(iae.toString()); + } + }); + + remPopupButton.addActionListener(e -> getCurIcon().setPopupMenu(null)); + for (String s: balloonTypes) { + balloonChoice.add(s); + } + + init(); + } + + void init() { + tray = SystemTray.getSystemTray(); + tray.addPropertyChangeListener("trayIcons", + e -> printPropertyChangeEvent(e)); + + tray.addPropertyChangeListener("systemTray", + e -> printPropertyChangeEvent(e)); + + configureTrayIcon(RED_ICON); + configureTrayIcon(BLUE_ICON); + configureTrayIcon(GREEN_ICON); + + for (String s: balloonTypes) { + popupMenu.add(new MenuItem(s)); + } + } + + void printPropertyChangeEvent(PropertyChangeEvent e) { + String name = e.getPropertyName(); + Object oldValue = e.getOldValue(); + Object newValue = e.getNewValue(); + + PassFailJFrame.log("PropertyChangeEvent[name=" + name + + ",oldValue=" + oldValue + ",newValue=" + newValue + "]"); + } + + void configureTrayIcon(String icon) { + Color color = Color.WHITE; + switch (icon) { + case "RED ICON" -> color = Color.RED; + case "BLUE ICON" -> color = Color.BLUE; + case "GREEN ICON" -> color = Color.GREEN; + } + Image image = createIcon(color); + TrayIcon trayIcon = new TrayIcon(image); + + trayIcon.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + if (mouseListenerCbox.getState()) + PassFailJFrame.log(e.toString()); + } + public void mouseReleased(MouseEvent e) { + if (mouseListenerCbox.getState()) + PassFailJFrame.log(e.toString()); + } + public void mouseClicked(MouseEvent e) { + if (mouseListenerCbox.getState()) + PassFailJFrame.log(e.toString()); + } + }); + trayIcon.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseMoved(MouseEvent e) { + if (motionListenerCbox.getState()) + PassFailJFrame.log(e.toString()); + } + }); + trayIcon.addActionListener(e -> PassFailJFrame.log(e.toString())); + + resToObjMap.remove(icon); + resToObjMap.put(icon, trayIcon); + } + + String getCurImgName() { + return cbg.getSelectedCheckbox().getLabel(); + } + + TrayIcon getCurIcon() { + return resToObjMap.get(getCurImgName()); + } + + public void dispose() { + tray.remove(getCurIcon()); + } + + private static Image createIcon(Color color) { + BufferedImage image = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setColor(color); + g.fillRect(0, 0, 16, 16); + g.dispose(); + return image; + } + + } + + private static class InsetsPanel extends Panel { + Container parent = new Container() { + public Insets getInsets() { + return new Insets(2, 2, 2, 2); + } + }; + + InsetsPanel() { + parent.setLayout(new BorderLayout()); + setBackground(new Color(240, 240, 240)); + } + + void addTo(Container c) { + parent.add(this); + c.add(parent); + } + + void addTo(Container c, String pos) { + parent.add(this); + c.add(parent, pos); + } + } + + private static class PackedButton extends Button { + Container parent = new Container(); + PackedButton(String l) { + super(l); + parent.setLayout(new FlowLayout()); + parent.add(this); + } + } +} + diff --git a/test/jdk/java/awt/Window/BadConfigure/BadConfigure.java b/test/jdk/java/awt/Window/BadConfigure/BadConfigure.java new file mode 100644 index 0000000000000..a25ab9b91b9a5 --- /dev/null +++ b/test/jdk/java/awt/Window/BadConfigure/BadConfigure.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6261336 + * @summary Tests that Choice inside ScrollPane opens at the right location + * after resize + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BadConfigure +*/ + +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Frame; + +public class BadConfigure +{ + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Please resize the BadConfigure window using the left border. + Now click on choice. Its popup will be opened. + Please verify that the popup is opened right under the choice. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + private static Frame initialize() { + Frame f = new Frame("BadConfigure"); + f.setLayout(new BorderLayout()); + Choice ch = new Choice(); + f.add(ch, BorderLayout.NORTH); + ch.add("One"); + ch.add("One"); + ch.add("One"); + ch.add("One"); + ch.add("One"); + ch.add("One"); + f.setSize(200, 200); + f.validate(); + return f; + } +} diff --git a/test/jdk/java/awt/Window/InvalidFocusLostEventTest/InvalidFocusLostEventTest.java b/test/jdk/java/awt/Window/InvalidFocusLostEventTest/InvalidFocusLostEventTest.java new file mode 100644 index 0000000000000..569d59f146d38 --- /dev/null +++ b/test/jdk/java/awt/Window/InvalidFocusLostEventTest/InvalidFocusLostEventTest.java @@ -0,0 +1,101 @@ +/* + * 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 4397883 + * @summary Tests that non-focusable Window doesn't grab focus + * @key headful + * @run main InvalidFocusLostEventTest + */ + +import java.awt.Button; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; + +public class InvalidFocusLostEventTest implements ActionListener { + private static Frame f; + private static Button b; + private static KeyboardFocusManager fm; + private static volatile Point bp; + private static volatile int width, height; + private static Robot robot; + + public static void main(String[] args) throws Exception { + try { + InvalidFocusLostEventTest test = new InvalidFocusLostEventTest(); + EventQueue.invokeAndWait(() -> test.createUI()); + runTest(); + // we should check focus after all events are processed, + // since focus transfers are asynchronous + robot.waitForIdle(); + if (fm.getFocusOwner() != b) { + throw new RuntimeException("Failed: focus was lost"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private void createUI() { + f = new Frame("InvalidFocusLostEventTest"); + b = new Button("Press me"); + fm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + b.addActionListener(this); + f.add(b); + f.pack(); + f.setLocationRelativeTo(null); + f.setVisible(true); + } + + private static void runTest() throws Exception { + robot = new Robot(); + robot.setAutoDelay(100); + robot.setAutoWaitForIdle(true); + EventQueue.invokeAndWait(() -> { + bp = b.getLocationOnScreen(); + width = b.getWidth(); + height = b.getHeight(); + }); + robot.mouseMove(bp.x + width / 2, bp.y + height / 2 ); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + public void actionPerformed(ActionEvent ev) { + // pop up a non-focusable window + Window win = new Window(f); + win.setFocusableWindowState(false); + } +} diff --git a/test/jdk/java/awt/Window/LocationByPlatform/TestLocationByPlatform.java b/test/jdk/java/awt/Window/LocationByPlatform/TestLocationByPlatform.java new file mode 100644 index 0000000000000..33b9d048ef2a9 --- /dev/null +++ b/test/jdk/java/awt/Window/LocationByPlatform/TestLocationByPlatform.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6318630 + * @summary Test that location by platform works + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestLocationByPlatform + */ + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; + +public class TestLocationByPlatform { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + You should see two frames. One has locationByPlatform set, it + should be displayed somewhere on the screen most probably without + intersecting other Frames or stacked over normal frame with some + offset. Another has its location explicitly set to (0, 450). + Please verify that the frames are located correctly on the screen. + + Also verify that the picture inside of frames looks the same + and consists of red descending triangle occupying exactly the bottom + half of the frame. Make sure that there is a blue rectangle exactly + surrounding the client area of frame with no pixels between it and + the frame's decorations. Press Pass if this all is true, + otherwise press Fail. + """; + + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows(13) + .columns(40) + .build(); + EventQueue.invokeAndWait(TestLocationByPlatform::createUI); + passFailJFrame.awaitAndCheck(); + } + private static void createUI() { + Frame frame = new Frame("Normal"); + frame.setLocation(0, 450); + Canvas c = new MyCanvas(); + frame.add(c, BorderLayout.CENTER); + frame.pack(); + PassFailJFrame.addTestWindow(frame); + frame.setVisible(true); + + frame = new Frame("Location by platform"); + frame.setLocationByPlatform(true); + c = new MyCanvas(); + frame.add(c, BorderLayout.CENTER); + frame.pack(); + PassFailJFrame.addTestWindow(frame); + frame.setVisible(true); + } + + static class MyCanvas extends Canvas { + @Override + public Dimension getPreferredSize() { + return new Dimension(400, 400); + } + + @Override + public void paint(Graphics g) { + g.setColor(Color.red); + for (int i = 399; i >= 0; i--) { + g.drawLine(400 - i - 1, 400 - i - 1, + 400 - i - 1, 399); + } + g.setColor(Color.blue); + g.drawLine(0, 0, 399, 0); + g.drawLine(0, 0, 0, 399); + g.drawLine(0, 399, 399, 399); + g.drawLine(399, 0, 399, 399); + } + } +} diff --git a/test/jdk/java/awt/Window/LocationByPlatformWithControls/TestLocationByPlatformWithControls.java b/test/jdk/java/awt/Window/LocationByPlatformWithControls/TestLocationByPlatformWithControls.java new file mode 100644 index 0000000000000..bfdba97e4eb99 --- /dev/null +++ b/test/jdk/java/awt/Window/LocationByPlatformWithControls/TestLocationByPlatformWithControls.java @@ -0,0 +1,270 @@ +/* + * 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 4102292 + * @summary Tests that location by platform works with other APIs + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestLocationByPlatformWithControls + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.Vector; + +public class TestLocationByPlatformWithControls extends Frame + implements ActionListener, ItemListener { + Panel northP; + Panel centerP; + Checkbox undecoratedCB; + Checkbox defaultLocationCB; + Checkbox visibleCB; + Checkbox iconifiedCB; + Checkbox maximizedCB; + Button createB; + Button packB; + Button moveB; + Button resizeB; + Button reshapeB; + Button disposeB; + Vector frames; + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test is to check that LocationByPlatform works with other + controls API. + 1) Create New Frame by clicking on "Create" Button in + "TestLocationByPlatformWithControls" window. + 2) Initially this Frame will not be visible, Click on checkbox + "LocationByPlatform" to set default platform location for the frame + and then click on checkbox "Visible" to see that Frame is displayed + at default offsets. + 3) Now you can play with different controls like Iconified, + Maximized, Pack, Move, Resize and Reshape to verify that these + controls work properly with the Frame. + 4) At the end dispose the Frame by clicking on "Dispose" button. + 5) Also we can do verify this for Undecorated Frame but for that we + need to follow same steps but in step 2 before we click on checkbox + "Visible", select "Undecorated" checkbox along with + "LocationByPlatform". + 6) If everything works properly test is passed, otherwise failed. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TestLocationByPlatformWithControls::new) + .logArea(4) + .build() + .awaitAndCheck(); + } + + public TestLocationByPlatformWithControls() { + northP = new Panel(); + centerP = new Panel(); + + undecoratedCB = new Checkbox("Undecorated"); + defaultLocationCB = new Checkbox("LocationByPlatform"); + visibleCB = new Checkbox("Visible"); + iconifiedCB = new Checkbox("Iconified"); + maximizedCB = new Checkbox("Maximized"); + + createB = new Button("Create"); + packB = new Button("Pack"); + moveB = new Button("Move"); + resizeB = new Button("Resize"); + reshapeB = new Button("Reshape"); + disposeB = new Button("Dispose"); + + frames = new Vector(10); + this.setTitle("TestLocationByPlatformWithControls"); + this.setLayout(new BorderLayout()); + this.add(northP, BorderLayout.NORTH); + + northP.add(new Label("New Frame")); + + createB.addActionListener(this); + northP.add(createB); + + centerP.setEnabled(false); + this.add(centerP, BorderLayout.CENTER); + + centerP.add(new Label("Last Frame")); + + centerP.add(defaultLocationCB); + defaultLocationCB.addItemListener(this); + + centerP.add(undecoratedCB); + undecoratedCB.addItemListener(this); + + centerP.add(iconifiedCB); + iconifiedCB.addItemListener(this); + + centerP.add(maximizedCB); + maximizedCB.addItemListener(this); + + centerP.add(visibleCB); + visibleCB.addItemListener(this); + + packB.addActionListener(this); + centerP.add(packB); + + moveB.addActionListener(this); + centerP.add(moveB); + + resizeB.addActionListener(this); + centerP.add(resizeB); + + reshapeB.addActionListener(this); + centerP.add(reshapeB); + + disposeB.addActionListener(this); + centerP.add(disposeB); + this.pack(); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == createB) { + Frame frame = new Frame(); + frame.setSize(200, 200); + frames.add(frame); + updateControls(frame); + Panel panel = new Panel(); + frame.add(panel); + panel.add(new Button ("Test Button")); + panel.add(new Button ("Test Button 1")); + panel.add(new Button ("Test Button 2")); + panel.add(new Button ("Test Button 3")); + centerP.setEnabled(true); + return; + } + + if (frames.isEmpty()) { + return; + } + + Frame last = (Frame)frames.lastElement(); + + if (e.getSource() == packB) { + last.pack(); + } else + if (e.getSource() == moveB) { + int x = (int)(Math.random() * 200); + int y = (int)(Math.random() * 200); + last.setLocation(x, y); + } else + if (e.getSource() == resizeB) { + int w = (int)(Math.random() * 200); + int h = (int)(Math.random() * 200); + last.setSize(w, h); + } else + if (e.getSource() == reshapeB) { + int x = (int)(Math.random() * 200); + int y = (int)(Math.random() * 200); + int w = (int)(Math.random() * 200); + int h = (int)(Math.random() * 200); + last.setBounds(x, y, w, h); + } else + if (e.getSource() == disposeB) { + last.dispose(); + frames.remove(frames.size() - 1); + if (frames.isEmpty()) { + updateControls(null); + centerP.setEnabled(false); + return; + } + last = (Frame)frames.lastElement(); + } + updateControls(last); + } + + public void updateControls(Frame f) { + undecoratedCB.setState(f != null ? + f.isUndecorated() : false); + defaultLocationCB.setState(f != null ? + f.isLocationByPlatform() : false); + visibleCB.setState(f != null ? + f.isVisible() : false); + iconifiedCB.setState(f != null ? + (f.getExtendedState() & Frame.ICONIFIED) != 0 : false); + maximizedCB.setState(f != null ? + (f.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 : false); + } + + public void itemStateChanged(ItemEvent e) { + Frame last = (Frame)frames.lastElement(); + try { + boolean state = e.getStateChange() == ItemEvent.SELECTED; + if (e.getSource() == visibleCB) { + last.setVisible(state); + } else + if (e.getSource() == defaultLocationCB) { + last.setLocationByPlatform(state); + } else + if (e.getSource() == undecoratedCB) { + last.setUndecorated(state); + } else + if (e.getSource() == iconifiedCB) { + if (state) { + last.setExtendedState(last.getExtendedState() | + Frame.ICONIFIED); + } else { + last.setExtendedState(last.getExtendedState() & + ~Frame.ICONIFIED); + } + } else + if (e.getSource() == maximizedCB) { + if (state) { + last.setExtendedState(last.getExtendedState() | + Frame.MAXIMIZED_BOTH); + } else { + last.setExtendedState(last.getExtendedState() & + ~Frame.MAXIMIZED_BOTH); + } + } + } catch (Throwable ex) { + PassFailJFrame.log(ex.getMessage()); + } finally { + updateControls(last); + } + } + + @Override + public void dispose() { + while (!frames.isEmpty()) { + Frame last = (Frame)frames.lastElement(); + last.dispose(); + frames.remove(frames.size() - 1); + } + } +} diff --git a/test/jdk/java/awt/Window/NoResizeEvent/NoResizeEvent.java b/test/jdk/java/awt/Window/NoResizeEvent/NoResizeEvent.java new file mode 100644 index 0000000000000..50b264acde970 --- /dev/null +++ b/test/jdk/java/awt/Window/NoResizeEvent/NoResizeEvent.java @@ -0,0 +1,82 @@ +/* + * 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 4942457 + * @key headful + * @summary Verifies that filtering of resize events on native level works. + * I.E.after Frame is shown no additional resize events are generated. + * @library /java/awt/patchlib ../../regtesthelpers + * @build java.desktop/java.awt.Helper + * @build Util + * @run main NoResizeEvent + */ + +import test.java.awt.regtesthelpers.Util; + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; + +public class NoResizeEvent { + //Mutter can send window insets too late, causing additional resize events. + private static final boolean IS_MUTTER = Util.getWMID() == Util.MUTTER_WM; + private static final int RESIZE_COUNT_LIMIT = IS_MUTTER ? 5 : 3; + private static Frame frame; + static int resize_count = 0; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(() -> createUI()); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + if (resize_count > RESIZE_COUNT_LIMIT) { + throw new RuntimeException("Resize event arrived: " + + resize_count + " times."); + } + } + } + + private static void createUI() { + frame = new Frame("NoResizeEvent"); + frame.addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent e) { + System.out.println(e); + resize_count++; + } + }); + frame.setVisible(true); + + try { + Thread.sleep(3000); + } catch (InterruptedException ie) { + } + System.out.println("Resize count: " + resize_count); + } +} diff --git a/test/hotspot/jtreg/gc/x/TestAlwaysPreTouch.java b/test/jdk/java/awt/Window/OwnedWindowShowTest/OwnedWindowShowTest.java similarity index 52% rename from test/hotspot/jtreg/gc/x/TestAlwaysPreTouch.java rename to test/jdk/java/awt/Window/OwnedWindowShowTest/OwnedWindowShowTest.java index b6ba6bf7a0593..c8b5ad4a619d0 100644 --- a/test/hotspot/jtreg/gc/x/TestAlwaysPreTouch.java +++ b/test/jdk/java/awt/Window/OwnedWindowShowTest/OwnedWindowShowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,21 +21,34 @@ * questions. */ -package gc.x; - /* - * @test TestAlwaysPreTouch - * @requires vm.gc.ZSinglegen - * @summary Test ZGC parallel pre-touch - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xlog:gc* -XX:-AlwaysPreTouch -Xms128M -Xmx128M gc.x.TestAlwaysPreTouch - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=1 -Xms2M -Xmx128M gc.x.TestAlwaysPreTouch - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=8 -Xms2M -Xmx128M gc.x.TestAlwaysPreTouch - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=1 -Xms128M -Xmx128M gc.x.TestAlwaysPreTouch - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=8 -Xms128M -Xmx128M gc.x.TestAlwaysPreTouch + * @test + * @bug 4177156 + * @key headful + * @summary Tests that multiple level of window ownership doesn't cause + * NullPointerException when showing a Window + * @run main OwnedWindowShowTest */ -public class TestAlwaysPreTouch { +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Window; + +public class OwnedWindowShowTest { public static void main(String[] args) throws Exception { - System.out.println("Success"); + EventQueue.invokeAndWait(OwnedWindowShowTest::runTest); + } + + static void runTest() { + Frame parent = new Frame("OwnedWindowShowTest"); + try { + Window owner = new Window(parent); + Window window = new Window(owner); + // Showing a window with multiple levels of ownership + // should not throw NullPointerException + window.setVisible(true); + } finally { + parent.dispose(); + } } } diff --git a/test/jdk/java/awt/Window/ProxyCrash/PopupProxyCrash.java b/test/jdk/java/awt/Window/ProxyCrash/PopupProxyCrash.java new file mode 100644 index 0000000000000..b17b934a70280 --- /dev/null +++ b/test/jdk/java/awt/Window/ProxyCrash/PopupProxyCrash.java @@ -0,0 +1,192 @@ +/* + * 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 4381561 + * @key headful + * @summary Tests that when we show the popup window AWT doesn't crash due to + * the problems with focus proxy window code + * @run main PopupProxyCrash + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; + +import javax.swing.Box; +import javax.swing.JComboBox; +import javax.swing.JTextField; +import javax.swing.plaf.basic.BasicComboBoxUI; +import javax.swing.plaf.basic.BasicComboPopup; +import javax.swing.plaf.basic.ComboPopup; + +public class PopupProxyCrash implements ActionListener { + private static JTextField jtf; + private static Button tf; + private static Panel panel; + private static Font[] fonts; + private static Robot robot; + + private static JComboBox cb; + + private static MyComboBoxUI comboBoxUI; + private static Frame frame; + private static int TEST_COUNT = 10; + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + robot.setAutoDelay(100); + EventQueue.invokeAndWait(() -> createUI()); + robot.waitForIdle(); + runTest(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createUI() { + frame = new Frame("PopupProxyCrash"); + Font dialog = new Font("Dialog", Font.PLAIN, 12); + Font serif = new Font("Serif", Font.PLAIN, 12); + Font monospaced = new Font("Monospaced", Font.PLAIN, 12); + + fonts = new Font[] { dialog, serif, monospaced }; + + cb = new JComboBox(fonts); + + cb.setLightWeightPopupEnabled(false); + comboBoxUI = new MyComboBoxUI(); + cb.setUI(comboBoxUI); + jtf = new JTextField("JTextField"); + jtf.setFont(fonts[1]); + tf = new Button("TextField"); + tf.setFont(fonts[1]); + cb.addActionListener(new PopupProxyCrash()); + + panel = new Panel() { + public Dimension getPreferredSize() { + return new Dimension(100, 20); + } + public void paint(Graphics g) { + System.out.println("Painting with font " + getFont()); + g.setColor(Color.white); + g.fillRect(0, 0, getWidth(), getHeight()); + g.setColor(Color.black); + g.setFont(getFont()); + g.drawString("LightWeight", 10, 10); + } + }; + panel.setFont(fonts[1]); + + Container parent = Box.createVerticalBox(); + parent.add(jtf); + parent.add(tf); + parent.add(panel); + parent.add(cb); + + frame.add(parent, BorderLayout.CENTER); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static Point getComboBoxLocation() throws Exception { + final Point[] result = new Point[1]; + + EventQueue.invokeAndWait(() -> { + Point point = cb.getLocationOnScreen(); + Dimension size = cb.getSize(); + + point.x += size.width / 2; + point.y += size.height / 2; + result[0] = point; + }); + return result[0]; + } + + private static Point getItemPointToClick(final int item) throws Exception { + final Point[] result = new Point[1]; + + EventQueue.invokeAndWait(() -> { + BasicComboPopup popup = (BasicComboPopup)comboBoxUI.getComboPopup(); + Point point = popup.getLocationOnScreen(); + Dimension size = popup.getSize(); + + int step = size.height / fonts.length; + point.x += size.width / 2; + point.y += step / 2 + step * item; + result[0] = point; + }); + return result[0]; + } + + static void runTest() throws Exception { + for (int i = 0; i < TEST_COUNT; i++) { + Point point = getComboBoxLocation(); + robot.mouseMove(point.x, point.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(500); + + point = getItemPointToClick(i % fonts.length); + robot.mouseMove(point.x, point.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(500); + } + } + public void actionPerformed(ActionEvent ae) { + System.out.println("Font selected"); + Font font = fonts[((JComboBox)ae.getSource()).getSelectedIndex()]; + + tf.setFont(font); + jtf.setFont(font); + panel.setFont(font); + panel.repaint(); + } + + private static class MyComboBoxUI extends BasicComboBoxUI { + public ComboPopup getComboPopup() { + return popup; + } + } +} diff --git a/test/jdk/java/awt/Window/ResizeTest/ResizeTest.java b/test/jdk/java/awt/Window/ResizeTest/ResizeTest.java new file mode 100644 index 0000000000000..a9191f8bd0536 --- /dev/null +++ b/test/jdk/java/awt/Window/ResizeTest/ResizeTest.java @@ -0,0 +1,80 @@ +/* + * 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 4225955 + * @summary Tests that focus lost is delivered to a lightweight component + * in a disposed window + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ResizeTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; + +public class ResizeTest +{ + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1) Push button A to create modal dialog 2. + 2) Resize dialog 2, then click button B to hide it. + 3) Push button A again. Dialog B should be packed to its original + size. + 4) Push button B again to hide, and A to reshow. + Dialog B should still be the same size, then test is passed, + otherwise failed. + 5) Push button B to hide the modal dialog and then select pass/fail. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(ResizeTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("1"); + Dialog d = new Dialog(f, "2", true); + d.setLocationRelativeTo(null); + Button b2 = new Button("B"); + b2.addActionListener(e -> d.setVisible(false)); + d.setLayout(new BorderLayout()); + d.add(b2, BorderLayout.CENTER); + + Button b = new Button("A"); + f.add(b, BorderLayout.CENTER); + b.addActionListener(e -> { + d.pack(); + d.setVisible(true); + }); + f.pack(); + return f; + } +} diff --git a/test/jdk/java/awt/Window/ShowWindowTest/ShowWindowTest.java b/test/jdk/java/awt/Window/ShowWindowTest/ShowWindowTest.java new file mode 100644 index 0000000000000..4857929c94ebc --- /dev/null +++ b/test/jdk/java/awt/Window/ShowWindowTest/ShowWindowTest.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4084997 + * @summary See if Window can be created without its size explicitly set + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ShowWindowTest + */ + +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ShowWindowTest implements ActionListener +{ + private static Window window; + private static Button showButton; + private static Button hideButton; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. You should see a Frame with a "Show" and a "Hide" button in it. + 2. Click on the "Show" button. A window with a "Hello World" Label + should appear + 3. If the window does not appear, the test failed, otherwise passed. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(ShowWindowTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame("ShowWindowTest"); + frame.setLayout(new FlowLayout()); + frame.setSize(100,100); + frame.add(showButton = new Button("Show")); + frame.add(hideButton = new Button("Hide")); + + ActionListener handler = new ShowWindowTest(); + showButton.addActionListener(handler); + hideButton.addActionListener(handler); + + window = new Window(frame); + window.add("Center", new Label("Hello World")); + window.setLocationRelativeTo(null); + return frame; + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == showButton) { + window.pack(); + window.setVisible(true); + } else if (e.getSource() == hideButton) + window.setVisible(false); + } +} diff --git a/test/jdk/java/awt/Window/WindowToFrontTest/WindowToFrontTest.java b/test/jdk/java/awt/Window/WindowToFrontTest/WindowToFrontTest.java new file mode 100644 index 0000000000000..e6bbadcb546db --- /dev/null +++ b/test/jdk/java/awt/Window/WindowToFrontTest/WindowToFrontTest.java @@ -0,0 +1,83 @@ +/* + * 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 4488209 + * @summary JFrame toFront causes the entire frame to be repainted, causes UI + * to flash + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual WindowToFrontTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class WindowToFrontTest implements ActionListener { + static Frame frame; + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1) Click the "toFront" button, this causes the + "WindowToFrontTest" frame to move front and gets repainted + completely. + 2) Move "WindowToFrontTest" window and continue to click on "toFront + multiple times. If the "WindowToFrontTest" Frame content is not + drawn properly and continues to blink, test is failed + otherwise passed. + """; + + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows(13) + .columns(40) + .build(); + EventQueue.invokeAndWait(() -> createUI()); + passFailJFrame.awaitAndCheck(); + } + + private static void createUI() { + frame = new Frame("WindowToFrontTest"); + frame.setLayout(new BorderLayout()); + frame.setSize(512, 512); + PassFailJFrame.addTestWindow(frame); + frame.setVisible(true); + + Frame buttonFrame = new Frame("Test Button"); + Button push = new Button("toFront"); + push.addActionListener(new WindowToFrontTest()); + buttonFrame.add(push); + buttonFrame.pack(); + PassFailJFrame.addTestWindow(buttonFrame); + buttonFrame.setVisible(true); + } + + public void actionPerformed(ActionEvent e) { + frame.toFront(); + } +} diff --git a/test/jdk/java/awt/Window/bug4189244.java b/test/jdk/java/awt/Window/bug4189244.java new file mode 100644 index 0000000000000..df37d2fce0e2b --- /dev/null +++ b/test/jdk/java/awt/Window/bug4189244.java @@ -0,0 +1,120 @@ +/* + * 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 + * 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 4189244 + * @summary Swing Popup menu is not being refreshed (cleared) under a Dialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @requires (os.family == "windows") + * @run main/manual bug4189244 +*/ + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; + +public class bug4189244 { + + private static final String INSTRUCTIONS = """ + This is Windows only test! + + Click right button on frame to show popup menu. + (menu should be placed inside frame otherwise bug is not reproducible) + click on any menu item (dialog will be shown). + close dialog. + if you see part of popupmenu, under dialog, before it is closed, + then test failed, else passed."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4189244 Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(bug4189244::createTestUI) + .build() + .awaitAndCheck(); + } + + + private static JFrame createTestUI() { + RefreshBug panel = new RefreshBug(); + JFrame frame = new JFrame("Popup refresh bug"); + + frame.add(panel, BorderLayout.CENTER); + panel.init(); + frame.setSize(400, 400); + return frame; + } +} + +class RefreshBug extends JPanel implements ActionListener { + JPopupMenu _jPopupMenu = new JPopupMenu(); + + public void init() { + JMenuItem menuItem; + JButton jb = new JButton("Bring the popup here and select an item"); + + this.add(jb, BorderLayout.CENTER); + + for(int i = 1; i < 10; i++) { + menuItem = new JMenuItem("Item " + i); + menuItem.addActionListener(this); + _jPopupMenu.add(menuItem); + } + + MouseListener ml = new MouseAdapter() { + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) { + _jPopupMenu.show(e.getComponent(), + e.getX(), e.getY()); + } + } + }; + this.addMouseListener(ml); + + jb.addMouseListener(ml); + + } + + // An action is requested by the user + public void actionPerformed(java.awt.event.ActionEvent e) { + JOptionPane.showMessageDialog(this, + "Check if there is some popup left under me\n"+ + "if not, retry and let the popup appear where i am", + "WARNING", + JOptionPane.WARNING_MESSAGE); + + } +} diff --git a/test/jdk/java/awt/a11y/AccessibleJTableTest.java b/test/jdk/java/awt/a11y/AccessibleJTableTest.java index fc62259ca385e..0f05dd4e09e65 100644 --- a/test/jdk/java/awt/a11y/AccessibleJTableTest.java +++ b/test/jdk/java/awt/a11y/AccessibleJTableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,22 +26,22 @@ * @test * @bug 8267388 * @summary Test implementation of NSAccessibilityTable protocol peer - * @author Artem.Semenov@jetbrains.com * @run main/manual AccessibleJTableTest * @requires (os.family == "windows" | os.family == "mac") */ -import javax.swing.*; -import javax.swing.event.TableModelEvent; -import javax.swing.event.TableModelListener; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.TableModel; - -import java.awt.*; +import java.awt.FlowLayout; +import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; public class AccessibleJTableTest extends AccessibleComponentTest { private static final String[] columnNames = {"One", "Two", "Three"}; @@ -67,6 +67,7 @@ public void createUI() { + "If you can hear table cells ctrl+tab further and press PASS, otherwise press FAIL.\n"; JTable table = new JTable(data, columnNames); + table.setPreferredScrollableViewportSize(table.getPreferredSize()); JPanel panel = new JPanel(); panel.setLayout(new FlowLayout()); JScrollPane scrollPane = new JScrollPane(table); @@ -82,12 +83,13 @@ public void createUIDraggable() { + "Turn screen reader on, and Tab to the table.\n" + "Using arrow keys navigate to the last cell in the first row in the table." + "Screen reader should announce it as \"Column 3 row 1\"\n\n" - + "Using mouse drag the header of the last culumn so the last column becomes the first one." + + "Using mouse drag the header of the last column so the last column becomes the first one." + "Wait for the screen reader to finish announcing new position in table.\n\n" + "If new position in table corresponds to the new table layout ctrl+tab further " + "and press PASS, otherwise press FAIL.\n"; JTable table = new JTable(data, columnNames); + table.setPreferredScrollableViewportSize(table.getPreferredSize()); JPanel panel = new JPanel(); panel.setLayout(new FlowLayout()); JScrollPane scrollPane = new JScrollPane(table); @@ -105,7 +107,9 @@ public void createUINamed() { + "If you can hear second table name: \"second table\" - ctrl+tab further and press PASS, otherwise press FAIL.\n"; JTable table = new JTable(data, columnNames); + table.setPreferredScrollableViewportSize(table.getPreferredSize()); JTable secondTable = new JTable(data, columnNames); + secondTable.setPreferredScrollableViewportSize(secondTable.getPreferredSize()); secondTable.getAccessibleContext().setAccessibleName("Second table"); JPanel panel = new JPanel(); panel.setLayout(new FlowLayout()); @@ -126,8 +130,8 @@ public void createUIWithChangingContent() { + "If you hear changes in the table - ctrl+tab further and press PASS, otherwise press FAIL.\n"; JTable table = new JTable(new TestTableModel(3, 3)); - - JPanel panel = new JPanel(); + table.setPreferredScrollableViewportSize(table.getPreferredSize()); + JPanel panel = new JPanel(); panel.setLayout(new FlowLayout()); JScrollPane scrollPane = new JScrollPane(table); panel.add(scrollPane); diff --git a/test/jdk/java/awt/dnd/CustomDragCursorTest.java b/test/jdk/java/awt/dnd/CustomDragCursorTest.java new file mode 100644 index 0000000000000..9e5e006b31c81 --- /dev/null +++ b/test/jdk/java/awt/dnd/CustomDragCursorTest.java @@ -0,0 +1,289 @@ +/* + * 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.Button; +import java.awt.Component; +import java.awt.Cursor; +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.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/* + * @test + * @bug 4451328 + * @summary tests that a custom drag cursor is not changed + to the default drag cursor + * @key headful + * @run main CustomDragCursorTest + */ + +public class CustomDragCursorTest { + private static Frame frame; + private static final DragSourcePanel dragSourcePanel = new DragSourcePanel(); + private static final DropTargetPanel dropTargetPanel = new DropTargetPanel(); + + private static volatile Point srcPoint; + private static volatile Point dstPoint; + private static volatile boolean passed = true; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + EventQueue.invokeAndWait(CustomDragCursorTest::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point p = dragSourcePanel.getLocationOnScreen(); + Dimension d = dragSourcePanel.getSize(); + p.translate(d.width / 2, d.height / 2); + srcPoint = p; + + p = dropTargetPanel.getLocationOnScreen(); + d = dropTargetPanel.getSize(); + p.translate(d.width / 2, d.height / 2); + dstPoint = p; + }); + + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (; !srcPoint.equals(dstPoint); + srcPoint.translate(sign(dstPoint.x - srcPoint.x), + sign(dstPoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.delay(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + robot.delay(1000); + + if (!passed) { + throw new RuntimeException("Custom drag cursor changed to default."); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + frame = new Frame("CustomDragCursorTest"); + frame.setLayout(new GridLayout(2, 1)); + frame.add(dragSourcePanel); + frame.add(dropTargetPanel); + frame.setLocationRelativeTo(null); + frame.setSize(300, 400); + frame.setVisible(true); + } + + public static void failed() { + passed = false; + } + + private static int sign(int n) { + return Integer.compare(n, 0); + } + + private static class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + private final DataFlavor dataflavor = + new DataFlavor(Button.class, "DragSourceButton"); + private final Cursor dragCursor = new Cursor(Cursor.HAND_CURSOR); + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(dragCursor, this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dragExit(DragSourceEvent dse) { + if (!dragCursor.equals(dse.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dragOver(DragSourceDragEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + Object retObj; + + ByteArrayOutputStream baoStream = new ByteArrayOutputStream(); + ObjectOutputStream ooStream = new ObjectOutputStream(baoStream); + ooStream.writeObject(this); + + ByteArrayInputStream baiStream = new ByteArrayInputStream(baoStream.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(baiStream); + try { + retObj = ois.readObject(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e.toString()); + } + + return retObj; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { dataflavor }; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } + } + + private static class DragSourcePanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 100); + + public DragSourcePanel() { + setLayout(new GridLayout(1, 1)); + add(new DragSourceButton()); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + } + + private static class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 100); + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, this)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) {} + + public void dragExit(DropTargetEvent dte) {} + + public void dragOver(DropTargetDragEvent dtde) {} + + public void dropActionChanged(DropTargetDragEvent dtde) {} + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if(dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component)transfer.getTransferData(dfs[0]); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + } + } + dtc.dropComplete(true); + add(comp); + } + } +} diff --git a/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDAcceptanceTest.java b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDAcceptanceTest.java new file mode 100644 index 0000000000000..700187f9dce49 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDAcceptanceTest.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Panel; + +/* + * @test + * @bug 4166541 4225247 4297663 + * @summary Tests Basic DnD functionality + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DnDAcceptanceTest + */ + +public class DnDAcceptanceTest { + private static final String INSTRUCTIONS = """ + When test runs a Frame which contains a yellow button labeled + "Drag ME!" and a RED Panel will appear. + + Click on the button and drag to the red panel. + When the mouse enters the red panel + during the drag the panel should turn yellow. + + Release the mouse button, panel should turn red again and + a yellow button labeled Drag ME! should appear inside the panel. + You should be able to repeat this operation multiple times. + + If above is true press PASS, else press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(38) + .testUI(DnDAcceptanceTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame("DnDAcceptanceTest"); + Panel mainPanel; + Component dragSource, dropTarget; + + frame.setSize(400, 400); + frame.setLayout(new BorderLayout()); + + mainPanel = new Panel(); + mainPanel.setLayout(new BorderLayout()); + + mainPanel.setBackground(Color.BLACK); + + dropTarget = new DnDTarget(Color.RED, Color.YELLOW); + dragSource = new DnDSource("Drag ME!"); + + mainPanel.add(dragSource, "North"); + mainPanel.add(dropTarget, "Center"); + frame.add(mainPanel, BorderLayout.CENTER); + frame.setAlwaysOnTop(true); + return frame; + } +} diff --git a/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java new file mode 100644 index 0000000000000..a35ccd9ee12cb --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java @@ -0,0 +1,155 @@ +/* + * 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. + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Container; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.MouseDragGestureRecognizer; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.InvalidDnDOperationException; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +class DnDSource extends Button implements Transferable, + DragGestureListener, + DragSourceListener { + private DataFlavor df; + private transient int dropAction; + + DnDSource(String label) { + super(label); + Toolkit.getDefaultToolkit().createDragGestureRecognizer(MouseDragGestureRecognizer.class, + DragSource.getDefaultDragSource(), + this, DnDConstants.ACTION_COPY, this); + setBackground(Color.yellow); + setForeground(Color.blue); + df = new DataFlavor(DnDSource.class, "DnDSource"); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + System.err.println("starting Drag"); + try { + dge.startDrag(null, this, this); + } catch (InvalidDnDOperationException e) { + e.printStackTrace(); + } + } + + public void dragEnter(DragSourceDragEvent dsde) { + System.err.println("[Source] dragEnter"); + dsde.getDragSourceContext().setCursor(DragSource.DefaultCopyDrop); + } + + public void dragOver(DragSourceDragEvent dsde) { + System.err.println("[Source] dragOver"); + dropAction = dsde.getDropAction(); + System.out.println("dropAction = " + dropAction); + } + + public void dragGestureChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dragGestureChanged"); + dropAction = dsde.getDropAction(); + System.out.println("dropAction = " + dropAction); + } + + public void dragExit(DragSourceEvent dsde) { + System.err.println("[Source] dragExit"); + dsde.getDragSourceContext().setCursor(null); + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + System.err.println("[Source] dragDropEnd"); + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dropActionChanged"); + dropAction = dsde.getDropAction(); + System.out.println("dropAction = " + dropAction); + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] {df}; + } + + public boolean isDataFlavorSupported(DataFlavor sdf) { + return df.equals(sdf); + } + + public Object getTransferData(DataFlavor tdf) throws UnsupportedFlavorException, IOException { + + Object copy = null; + + if (!df.equals(tdf)) { + throw new UnsupportedFlavorException(tdf); + } + Container parent = getParent(); + switch (dropAction) { + case DnDConstants.ACTION_COPY: + try { + copy = this.clone(); + } catch (CloneNotSupportedException e) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + + oos.writeObject(this); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + try { + copy = ois.readObject(); + } catch (ClassNotFoundException cnfe) { + // do nothing + } + } + + parent.add(this); + return copy; + + case DnDConstants.ACTION_MOVE: + synchronized(this) { + if (parent != null) parent.remove(this); + } + return this; + + case DnDConstants.ACTION_LINK: + return this; + + default: + //throw new IOException("bad operation"); + return this; // workaround for: 4135456 getDropAction() always return 0 + } + } +} diff --git a/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java new file mode 100644 index 0000000000000..d147741f0d225 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Panel; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.io.IOException; + +class DnDTarget extends Panel implements DropTargetListener { + Color bgColor; + Color htColor; + + DnDTarget(Color bgColor, Color htColor) { + super(); + this.bgColor = bgColor; + this.htColor = htColor; + setBackground(bgColor); + setDropTarget(new DropTarget(this, this)); + } + + public void dragEnter(DropTargetDragEvent e) { + System.err.println("[Target] dragEnter"); + e.acceptDrag(DnDConstants.ACTION_COPY); + setBackground(htColor); + repaint(); + } + + public void dragOver(DropTargetDragEvent e) { + System.err.println("[Target] dragOver"); + e.acceptDrag(DnDConstants.ACTION_COPY); + } + + public void dragExit(DropTargetEvent e) { + System.err.println("[Target] dragExit"); + setBackground(bgColor); + repaint(); + } + + public void drop(DropTargetDropEvent dtde) { + System.err.println("[Target] drop"); + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + return; + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + if (dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + Object obj; + try { + obj = transfer.getTransferData(dfs[0]); + } catch (IOException | UnsupportedFlavorException ex) { + System.err.println(ex.getMessage()); + dtc.dropComplete(false); + return; + } + + if (obj != null) { + Button button; + try { + button = (Button) obj; + } catch (Exception e) { + System.err.println(e.getMessage()); + dtc.dropComplete(false); + return; + } + add(button); + repaint(); + } + } + setBackground(bgColor); + invalidate(); + validate(); + repaint(); + dtc.dropComplete(true); + } + + public void dropActionChanged(DropTargetDragEvent e) { + System.err.println("[Target] dropActionChanged"); + } +} diff --git a/test/jdk/java/awt/dnd/DnDClipboardDeadlockTest.java b/test/jdk/java/awt/dnd/DnDClipboardDeadlockTest.java new file mode 100644 index 0000000000000..ab2bff8ecc5a5 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDClipboardDeadlockTest.java @@ -0,0 +1,441 @@ +/* + * 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 4388802 + * @summary tests that clipboard operations during drag-and-drop don't deadlock + * @key headful + * @run main DnDClipboardDeadlockTest + */ + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +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.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.AWTEventListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; + +public class DnDClipboardDeadlockTest { + + public static final int CODE_NOT_RETURNED = -1; + public static final int CODE_OK = 0; + public static final int CODE_FAILURE = 1; + + private int returnCode = CODE_NOT_RETURNED; + + final Frame frame = new Frame(); + Robot robot = null; + Panel panel = null; + + public static void main(String[] args) throws Exception { + DnDClipboardDeadlockTest test = new DnDClipboardDeadlockTest(); + if (args.length == 4) { + test.run(args); + } else { + test.start(); + } + } + + public void run(String[] args) throws InterruptedException, AWTException { + try { + if (args.length != 4) { + throw new RuntimeException("Incorrect command line arguments."); + } + + int x = Integer.parseInt(args[0]); + int y = Integer.parseInt(args[1]); + int w = Integer.parseInt(args[2]); + int h = Integer.parseInt(args[3]); + + Transferable t = new StringSelection("TEXT"); + panel = new DragSourcePanel(t); + + frame.setTitle("DragSource frame"); + frame.setLocation(300, 200); + frame.add(panel); + frame.pack(); + frame.setVisible(true); + + Util.waitForInit(); + + Point sourcePoint = panel.getLocationOnScreen(); + Dimension d = panel.getSize(); + sourcePoint.translate(d.width / 2, d.height / 2); + + Point targetPoint = new Point(x + w / 2, y + h / 2); + + robot = new Robot(); + + if (!Util.pointInComponent(robot, sourcePoint, panel)) { + throw new RuntimeException("WARNING: Cannot locate source panel"); + } + + robot.mouseMove(sourcePoint.x, sourcePoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (; !sourcePoint.equals(targetPoint); + sourcePoint.translate(sign(targetPoint.x - sourcePoint.x), + sign(targetPoint.y - sourcePoint.y))) { + robot.mouseMove(sourcePoint.x, sourcePoint.y); + Thread.sleep(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + if (frame != null) { + frame.dispose(); + } + + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } // run() + + public static int sign(int n) { + return n < 0 ? -1 : n == 0 ? 0 : 1; + } + + public void start() { + panel = new DropTargetPanel(); + + frame.setTitle("DropTarget frame"); + frame.setLocation(10, 200); + frame.add(panel); + + frame.pack(); + frame.setVisible(true); + + try { + Util.waitForInit(); + + Point p = panel.getLocationOnScreen(); + Dimension d = panel.getSize(); + + try { + Robot robot = new Robot(); + Point center = new Point(p); + center.translate(d.width / 2, d.height / 2); + if (!Util.pointInComponent(robot, center, panel)) { + System.err.println("WARNING: Cannot locate target panel"); + return; + } + } catch (AWTException awte) { + awte.printStackTrace(); + return; + } + + String javaPath = System.getProperty("java.home", ""); + String command = javaPath + File.separator + "bin" + + File.separator + "java -cp " + + System.getProperty("java.class.path", ".") + + " DnDClipboardDeadlockTest " + + p.x + " " + p.y + " " + d.width + " " + d.height; + + Process process = Runtime.getRuntime().exec(command); + returnCode = process.waitFor(); + + InputStream errorStream = process.getErrorStream(); + int count = errorStream.available(); + if (count > 0) { + byte[] b = new byte[count]; + errorStream.read(b); + System.err.println("========= Child VM System.err ========"); + System.err.print(new String(b)); + System.err.println("======================================"); + } + + } catch (Throwable e) { + e.printStackTrace(); + } + switch (returnCode) { + case CODE_NOT_RETURNED: + System.err.println("Child VM: failed to start"); + break; + case CODE_OK: + System.err.println("Child VM: normal termination"); + break; + case CODE_FAILURE: + System.err.println("Child VM: abnormal termination"); + break; + } + if (returnCode != CODE_OK) { + throw new RuntimeException("The test failed."); + } + if (frame != null) { + frame.dispose(); + } + } // start() +} // class DnDClipboardDeadlockTest + +class Util implements AWTEventListener { + private static final Toolkit tk = Toolkit.getDefaultToolkit(); + private static final Object SYNC_LOCK = new Object(); + private Component clickedComponent = null; + private static final int PAINT_TIMEOUT = 10000; + private static final int MOUSE_RELEASE_TIMEOUT = 10000; + private static final Util util = new Util(); + + static { + tk.addAWTEventListener(util, 0xFFFFFFFF); + } + + private 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(); + } + } + } + + public static boolean pointInComponent(Robot robot, Point p, Component comp) + throws InterruptedException { + return util.isPointInComponent(robot, p, comp); + } + + private boolean isPointInComponent(Robot robot, Point p, Component comp) + throws InterruptedException { + tk.sync(); + 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; + } + + public static void waitForInit() throws InterruptedException { + final Frame f = new Frame() { + public void paint(Graphics g) { + dispose(); + synchronized (SYNC_LOCK) { + SYNC_LOCK.notifyAll(); + } + } + }; + f.setBounds(600, 400, 200, 200); + synchronized (SYNC_LOCK) { + f.setVisible(true); + SYNC_LOCK.wait(PAINT_TIMEOUT); + } + tk.sync(); + } +} + +class DragSourceButton extends Button implements Serializable, + DragGestureListener, + DragSourceListener { + static final Clipboard systemClipboard = + Toolkit.getDefaultToolkit().getSystemClipboard(); + final Transferable transferable; + + public DragSourceButton(Transferable t) { + super("DragSourceButton"); + + this.transferable = t; + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, transferable, this); + } + + public void dragEnter(DragSourceDragEvent dsde) { + } + + public void dragExit(DragSourceEvent dse) { + } + + public void dragOver(DragSourceDragEvent dsde) { + try { + Transferable t = systemClipboard.getContents(null); + if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { + String str = (String) t.getTransferData(DataFlavor.stringFlavor); + } + systemClipboard.setContents(new StringSelection("SOURCE"), null); + } catch (IOException ioe) { + ioe.printStackTrace(); + if (!ioe.getMessage().equals("Owner failed to convert data")) { + throw new RuntimeException("Owner failed to convert data"); + } + } catch (IllegalStateException e) { + // IllegalStateExceptions do not indicate a bug in this case. + // They result from concurrent modification of system clipboard + // contents by the parent and child processes. + // These exceptions are numerous, so we avoid dumping their + // backtraces to prevent blocking child process io, which + // causes test failure on timeout. + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + System.exit(DnDClipboardDeadlockTest.CODE_OK); + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + } +} + +class DragSourcePanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 200); + + public DragSourcePanel(Transferable t) { + setLayout(new GridLayout(1, 1)); + add(new DragSourceButton(t)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } +} + +class DropTargetPanel extends Panel implements DropTargetListener { + + static final Clipboard systemClipboard = + Toolkit.getDefaultToolkit().getSystemClipboard(); + final Dimension preferredDimension = new Dimension(200, 200); + + public DropTargetPanel() { + setBackground(Color.green); + setDropTarget(new DropTarget(this, this)); + setLayout(new GridLayout(1, 1)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) { + dtde.acceptDrag(DnDConstants.ACTION_COPY); + } + + public void dragExit(DropTargetEvent dte) { + } + + public void dragOver(DropTargetDragEvent dtde) { + dtde.acceptDrag(DnDConstants.ACTION_COPY); + try { + Transferable t = systemClipboard.getContents(null); + if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { + String str = (String) t.getTransferData(DataFlavor.stringFlavor); + } + systemClipboard.setContents(new StringSelection("TARGET"), null); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + return; + } + + removeAll(); + final List list = new List(); + add(list); + + Transferable t = dtde.getTransferable(); + DataFlavor[] dfs = t.getTransferDataFlavors(); + + for (int i = 0; i < dfs.length; i++) { + + DataFlavor flavor = dfs[i]; + String str = null; + + if (DataFlavor.stringFlavor.equals(flavor)) { + try { + str = (String) t.getTransferData(flavor); + } catch (Exception e) { + e.printStackTrace(); + } + } + + list.add(str + ":" + flavor.getMimeType()); + } + + dtc.dropComplete(true); + validate(); + } + + public void dropActionChanged(DropTargetDragEvent dtde) { + } +} diff --git a/test/jdk/java/awt/dnd/DnDCursorCrashTest.java b/test/jdk/java/awt/dnd/DnDCursorCrashTest.java new file mode 100644 index 0000000000000..7b1f4483ef991 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDCursorCrashTest.java @@ -0,0 +1,231 @@ +/* + * 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 + * 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 4343300 + * @summary tests that drag attempt doesn't cause crash when + * custom cursor is used + * @key headful + * @run main DnDCursorCrashTest + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +public class DnDCursorCrashTest { + static final Frame frame = new Frame(); + static final DragSourcePanel dragSourcePanel = new DragSourcePanel(); + static final DropTargetPanel dropTargetPanel = new DropTargetPanel(); + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(() -> { + frame.setTitle("DnD Cursor Test Frame"); + frame.setLocation(200, 200); + frame.setLayout(new GridLayout(2, 1)); + frame.add(dragSourcePanel); + frame.add(dropTargetPanel); + frame.pack(); + frame.setVisible(true); + }); + + Robot robot = new Robot(); + robot.delay(1000); + robot.mouseMove(250, 250); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (int y = 250; y < 350; y += 5) { + robot.mouseMove(250, y); + robot.delay(100); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(() -> frame.dispose()); + } + } + } +} + +class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + private final DataFlavor dataflavor = + new DataFlavor(Button.class, "DragSourceButton"); + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(new Cursor(Cursor.HAND_CURSOR), this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) {} + + public void dragExit(DragSourceEvent dse) {} + + public void dragOver(DragSourceDragEvent dsde) {} + + public void dragDropEnd(DragSourceDropEvent dsde) {} + + public void dropActionChanged(DragSourceDragEvent dsde) {} + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + Object retObj; + + ByteArrayOutputStream baoStream = new ByteArrayOutputStream(); + ObjectOutputStream ooStream = new ObjectOutputStream(baoStream); + ooStream.writeObject(this); + + ByteArrayInputStream baiStream = new ByteArrayInputStream(baoStream.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(baiStream); + try { + retObj = ois.readObject(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e.toString()); + } + + return retObj; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { dataflavor }; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } +} + +class DragSourcePanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 100); + + public DragSourcePanel() { + setLayout(new GridLayout(1, 1)); + add(new DragSourceButton()); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } +} + +class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 100); + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, this)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) {} + + public void dragExit(DropTargetEvent dte) {} + + public void dragOver(DropTargetDragEvent dtde) {} + + public void dropActionChanged(DropTargetDragEvent dtde) {} + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if (dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component)transfer.getTransferData(dfs[0]); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + } + } + dtc.dropComplete(true); + + add(comp); + } +} diff --git a/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java new file mode 100644 index 0000000000000..8a39ce537056e --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Panel; + + +/* + * @test + * @bug 6392086 + * @summary Tests dnd to another screen + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DnDHTMLToOutlookTest + */ + +public class DnDHTMLToOutlookTest { + + private static final String INSTRUCTIONS = """ + The window contains a yellow button. Click on the button + to copy HTML from DnDSource.html file into the clipboard or drag + HTML context. Paste into or drop over the HTML capable editor in + external application such as Outlook, Word. + + When the mouse enters the editor, cursor should change to indicate + that copy operation is about to happen and then release the mouse + button. HTML text without tags should appear inside the document. + + You should be able to repeat this operation multiple times. + If the above is true Press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(DnDHTMLToOutlookTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame frame = new Frame("DnDHTMLToOutlookTest"); + Panel mainPanel; + Component dragSource; + + mainPanel = new Panel(); + mainPanel.setLayout(new BorderLayout()); + + mainPanel.setBackground(Color.YELLOW); + dragSource = new DnDSource("Drag ME (HTML)!"); + + mainPanel.add(dragSource, BorderLayout.CENTER); + frame.add(mainPanel); + frame.setSize(200, 200); + return frame; + } +} diff --git a/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.html b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.html new file mode 100644 index 0000000000000..0f1b9751decdb --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.html @@ -0,0 +1,25 @@ + + +

              DnDHTMLToOutlookTest
              HTML Drag & Paste problem

              +

              if you see the bold header above without HTML tags and without StartHTML as the first word, press PASS

              diff --git a/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.java b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.java new file mode 100644 index 0000000000000..58f17e9415c50 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; + +class DnDSource extends Button implements Transferable, + DragGestureListener, + DragSourceListener { + private DataFlavor m_df; + private transient int m_dropAction; + private ByteArrayInputStream m_data = null; + + DnDSource(String label) { + super(label); + setBackground(Color.yellow); + setForeground(Color.blue); + setSize(200, 120); + + try { + m_df = new DataFlavor("text/html; Class=" + InputStream.class.getName() + "; charset=UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } + + DragSource dragSource = new DragSource(); + dragSource.createDefaultDragGestureRecognizer( + this, + DnDConstants.ACTION_COPY_OR_MOVE, + this + ); + dragSource.addDragSourceListener(this); + + String dir = System.getProperty("test.src", "."); + + try { + m_data = new ByteArrayInputStream(Files.readAllBytes( + Paths.get(dir, "DnDSource.html"))); + m_data.mark(m_data.available()); + addActionListener( + new ActionListener(){ + public void actionPerformed(ActionEvent ae){ + Toolkit.getDefaultToolkit().getSystemClipboard() + .setContents( DnDSource.this, null); + } + } + ); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void dragGestureRecognized(DragGestureEvent dge) { + System.err.println("starting Drag"); + try { + dge.startDrag(null, this, this); + } catch (InvalidDnDOperationException e) { + e.printStackTrace(); + } + } + + public void dragEnter(DragSourceDragEvent dsde) { + System.err.println("[Source] dragEnter"); + } + + public void dragOver(DragSourceDragEvent dsde) { + System.err.println("[Source] dragOver"); + m_dropAction = dsde.getDropAction(); + System.out.println("m_dropAction = " + m_dropAction); + } + + public void dragExit(DragSourceEvent dsde) { + System.err.println("[Source] dragExit"); + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + System.err.println("[Source] dragDropEnd"); + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dropActionChanged"); + m_dropAction = dsde.getDropAction(); + System.out.println("m_dropAction = " + m_dropAction); + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] {m_df}; + } + + public boolean isDataFlavorSupported(DataFlavor sdf) { + System.err.println("[Source] isDataFlavorSupported" + m_df.equals(sdf)); + return m_df.equals(sdf); + } + + public Object getTransferData(DataFlavor tdf) throws UnsupportedFlavorException { + if (!m_df.equals(tdf)) { + throw new UnsupportedFlavorException(tdf); + } + System.err.println("[Source] Ok"); + m_data.reset(); + return m_data; + } +} diff --git a/test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java b/test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java new file mode 100644 index 0000000000000..1fc7c2e82b89c --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java @@ -0,0 +1,233 @@ +/* + * 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 + * 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 4357905 + * @summary Tests that removal of the focus owner component during + * drop processing doesn't cause crash + * @key headful + * @run main DnDRemoveFocusOwnerCrashTest + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.Serializable; + +public class DnDRemoveFocusOwnerCrashTest { + public static final int FRAME_ACTIVATION_TIMEOUT = 1000; + public static Frame frame; + public static Robot robot; + public static DragSourceButton dragSourceButton; + static volatile Point p; + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.delay(FRAME_ACTIVATION_TIMEOUT); + EventQueue.invokeAndWait(() -> { + frame = new Frame(); + dragSourceButton = new DragSourceButton(); + DropTargetPanel dropTargetPanel = + new DropTargetPanel(dragSourceButton); + frame.add(new Button("Test")); + frame.setTitle("Remove Focus Owner Test Frame"); + frame.setLocation(200, 200); + frame.add(dropTargetPanel); + frame.pack(); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(FRAME_ACTIVATION_TIMEOUT); + + EventQueue.invokeAndWait(() -> { + p = dragSourceButton.getLocationOnScreen(); + p.translate(10, 10); + }); + + robot.delay(FRAME_ACTIVATION_TIMEOUT); + robot.mouseMove(p.x, p.y); + robot.delay(FRAME_ACTIVATION_TIMEOUT); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (int dy = 0; dy < 50; dy++) { + robot.mouseMove(p.x, p.y + dy); + robot.delay(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + static class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + + private static DataFlavor dataflavor; + + static { + try { + dataflavor = + new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType); + dataflavor.setHumanPresentableName("Local Object Flavor"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + throw new ExceptionInInitializerError(); + } + } + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) { + } + + public void dragExit(DragSourceEvent dse) { + } + + public void dragOver(DragSourceDragEvent dsde) { + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + return this; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[]{dataflavor}; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } + } + + static class DropTargetPanel extends Panel implements DropTargetListener { + + public DropTargetPanel(DragSourceButton button) { + setLayout(new FlowLayout(FlowLayout.CENTER, 50, 50)); + add(button); + setDropTarget(new DropTarget(this, this)); + } + + public void dragEnter(DropTargetDragEvent dtde) { + } + + public void dragExit(DropTargetEvent dte) { + } + + public void dragOver(DropTargetDragEvent dtde) { + } + + public void dropActionChanged(DropTargetDragEvent dtde) { + } + + public void drop(DropTargetDropEvent dtde) { + removeAll(); + + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if (dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component) transfer.getTransferData(dfs[0]); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + } + } + dtc.dropComplete(true); + + add(comp); + validate(); + } + } +} diff --git a/test/jdk/java/awt/dnd/DnDToWordpadTest.java b/test/jdk/java/awt/dnd/DnDToWordpadTest.java new file mode 100644 index 0000000000000..181a6ee873a85 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDToWordpadTest.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6362095 + * @summary Tests basic DnD functionality to a wordpad + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DnDToWordpadTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Panel; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +import javax.imageio.ImageIO; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +public class DnDToWordpadTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + The test window contains a yellow button. Click on the button + to copy image into the clipboard or drag the image. + Paste or drop the image over Wordpad (when the mouse + enters the Wordpad during the drag, the application + should change the cursor to indicate that a copy operation is + about to happen; release the mouse button). + An image of a red rectangle should appear inside the document. + You should be able to repeat this operation multiple times. + Please, click "Pass" if above conditions are true, + otherwise click "Fail". + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(DnDToWordpadTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("DnD To WordPad Test"); + Panel mainPanel; + Component dragSource; + + mainPanel = new Panel(); + mainPanel.setLayout(null); + + mainPanel.setBackground(Color.black); + try { + dragSource = new DnDSource("Drag ME!"); + mainPanel.add(dragSource); + f.add(mainPanel); + } catch (IOException e) { + e.printStackTrace(); + } + + f.setSize(200, 200); + return f; + } +} + +class DnDSource extends Button implements Transferable, + DragGestureListener, + DragSourceListener { + private DataFlavor m_df; + private transient int m_dropAction; + private Image m_img; + + DnDSource(String label) throws IOException { + super(label); + + setBackground(Color.yellow); + setForeground(Color.blue); + setSize(200, 120); + + m_df = DataFlavor.imageFlavor; + + DragSource dragSource = new DragSource(); + dragSource.createDefaultDragGestureRecognizer( + this, + DnDConstants.ACTION_COPY_OR_MOVE, + this + ); + dragSource.addDragSourceListener(this); + + // Create test gif image to drag + Path p = Path.of(System.getProperty("test.classes", ".")); + BufferedImage bImg = new BufferedImage(79, 109, TYPE_INT_ARGB); + Graphics2D cg = bImg.createGraphics(); + cg.setColor(Color.RED); + cg.fillRect(0, 0, 79, 109); + ImageIO.write(bImg, "png", new File(p + java.io.File.separator + + "DnDSource_Red.gif")); + + m_img = Toolkit.getDefaultToolkit() + .getImage(System.getProperty("test.classes", ".") + + java.io.File.separator + "DnDSource_Red.gif"); + + addActionListener( + ae -> Toolkit.getDefaultToolkit().getSystemClipboard().setContents( + (Transferable) DnDSource.this, + null + ) + ); + } + + public void paint(Graphics g) { + g.drawImage(m_img, 10, 10, null); + } + + /** + * a Drag gesture has been recognized + */ + + public void dragGestureRecognized(DragGestureEvent dge) { + System.err.println("starting Drag"); + try { + dge.startDrag(null, this, this); + } catch (InvalidDnDOperationException e) { + e.printStackTrace(); + } + } + + /** + * as the hotspot enters a platform dependent drop site + */ + + public void dragEnter(DragSourceDragEvent dsde) { + System.err.println("[Source] dragEnter"); + } + + /** + * as the hotspot moves over a platform dependent drop site + */ + + public void dragOver(DragSourceDragEvent dsde) { + System.err.println("[Source] dragOver"); + m_dropAction = dsde.getDropAction(); + System.out.println("m_dropAction = " + m_dropAction); + } + + /** + * as the operation changes + */ + + public void dragGestureChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dragGestureChanged"); + m_dropAction = dsde.getDropAction(); + System.out.println("m_dropAction = " + m_dropAction); + } + + /** + * as the hotspot exits a platform dependent drop site + */ + + public void dragExit(DragSourceEvent dsde) { + System.err.println("[Source] dragExit"); + } + + /** + * as the operation completes + */ + + public void dragDropEnd(DragSourceDropEvent dsde) { + System.err.println("[Source] dragDropEnd"); + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dropActionChanged"); + m_dropAction = dsde.getDropAction(); + System.out.println("m_dropAction = " + m_dropAction); + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[]{m_df}; + } + + public boolean isDataFlavorSupported(DataFlavor sdf) { + System.err.println("[Source] isDataFlavorSupported" + m_df.equals(sdf)); + return m_df.equals(sdf); + } + + public Object getTransferData(DataFlavor tdf) throws UnsupportedFlavorException { + if (!m_df.equals(tdf)) { + throw new UnsupportedFlavorException(tdf); + } + System.err.println("[Source] Ok"); + return m_img; + } +} diff --git a/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java b/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java new file mode 100644 index 0000000000000..2ef778a18ba46 --- /dev/null +++ b/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java @@ -0,0 +1,257 @@ +/* + * 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.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.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/* + * @test + * @bug 4395290 + * @key headful + * @summary tests that dragExit() is not called before drop() + */ + +public class DragExitBeforeDropTest { + private static Frame frame; + private static final DragSourceButton dragSourceButton = new DragSourceButton(); + private static final DropTargetPanel dropTargetPanel = new DropTargetPanel(); + private static volatile Point srcPoint; + private static volatile Point dstPoint; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + EventQueue.invokeAndWait(DragExitBeforeDropTest::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point p = dragSourceButton.getLocationOnScreen(); + Dimension d = dragSourceButton.getSize(); + p.translate(d.width / 2, d.height / 2); + srcPoint = p; + + p = dropTargetPanel.getLocationOnScreen(); + d = dropTargetPanel.getSize(); + p.translate(d.width / 2, d.height / 2); + dstPoint = p; + }); + + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (; !srcPoint.equals(dstPoint); + srcPoint.translate(sign(dstPoint.x - srcPoint.x), + sign(dstPoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.delay(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + robot.delay(1000); + + if (!dropTargetPanel.getStatus()) { + throw new RuntimeException("The test failed: dragExit()" + + " is called before drop()"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + frame = new Frame("DragExitBeforeDropTest"); + frame.setLayout(new GridLayout(2, 1)); + frame.add(dragSourceButton); + frame.add(dropTargetPanel); + frame.setLocationRelativeTo(null); + frame.setSize(300, 400); + frame.setVisible(true); + } + + public static int sign(int n) { + return Integer.compare(n, 0); + } + + private static class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + private final DataFlavor dataflavor = + new DataFlavor(Button.class, "DragSourceButton"); + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) {} + + public void dragExit(DragSourceEvent dse) {} + + public void dragOver(DragSourceDragEvent dsde) {} + + public void dragDropEnd(DragSourceDropEvent dsde) {} + + public void dropActionChanged(DragSourceDragEvent dsde) {} + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + Object retObj; + + ByteArrayOutputStream baoStream = new ByteArrayOutputStream(); + ObjectOutputStream ooStream = new ObjectOutputStream(baoStream); + ooStream.writeObject(this); + + ByteArrayInputStream baiStream = + new ByteArrayInputStream(baoStream.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(baiStream); + try { + retObj = ois.readObject(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e.toString()); + } + + return retObj; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { dataflavor }; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } + } + + private static class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 100); + volatile boolean testPassed = true; + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, this)); + } + + public boolean getStatus() { + return testPassed; + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) {} + + public void dragExit(DropTargetEvent dte) { + testPassed = false; + } + + public void dragOver(DropTargetDragEvent dtde) {} + + public void dropActionChanged(DropTargetDragEvent dtde) {} + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if(dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component)transfer.getTransferData(dfs[0]); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + } + } + dtc.dropComplete(true); + add(comp); + } + } +} + + + diff --git a/test/jdk/java/awt/dnd/DragSourceMotionListenerTest.java b/test/jdk/java/awt/dnd/DragSourceMotionListenerTest.java new file mode 100644 index 0000000000000..25bf7ef03fd1e --- /dev/null +++ b/test/jdk/java/awt/dnd/DragSourceMotionListenerTest.java @@ -0,0 +1,242 @@ +/* + * 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.AWTEvent; +import java.awt.Component; +import java.awt.Container; +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.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.AWTEventListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/* + * @test + * @key headful + * @bug 4422345 + * @summary tests that DragSourceMotionListeners work correctly and + DragSourceEvents position is correct + */ + +public class DragSourceMotionListenerTest implements AWTEventListener { + static class TestPanel extends Panel { + final Dimension preferredDimension = new Dimension(200, 200); + public Dimension getPreferredSize() { + return preferredDimension; + } + } + + private static Frame frame; + private static final Panel source = new TestPanel(); + private static final Panel target = new TestPanel(); + private static final DragSource ds = DragSource.getDefaultDragSource(); + private static volatile CountDownLatch mouseReleaseEvent; + + static volatile boolean passedTest1 = false; + static volatile boolean passedTest2 = false; + + private static final Point testPoint1 = new Point(); + private static final Point testPoint2 = new Point(); + private static volatile Point srcPoint; + private static volatile Point dstOutsidePoint; + private static volatile Point dstInsidePoint; + + private static final Transferable t = new StringSelection("TEXT"); + private static final DragGestureListener gestureListener = e -> e.startDrag(null, t); + + private static final DragSourceAdapter sourceAdapter = new DragSourceAdapter() { + public void dragMouseMoved(DragSourceDragEvent dsde) { + if (Math.abs(dsde.getX() - testPoint1.getX()) < 5) { + passedTest1 = true; + } + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + if (Math.abs(dsde.getX() - testPoint2.getX()) < 5) { + passedTest2 = true; + } + } + }; + + private static final DropTargetListener targetAdapter = new DropTargetAdapter() { + public void drop(DropTargetDropEvent e) { + e.acceptDrop(DnDConstants.ACTION_COPY); + try { + final Transferable t = e.getTransferable(); + final String str = + (String) t.getTransferData(DataFlavor.stringFlavor); + e.dropComplete(true); + } catch (Exception ex) { + ex.printStackTrace(); + e.dropComplete(false); + } + } + }; + + private static final DropTarget dropTarget = new DropTarget(target, targetAdapter); + Component clickedComponent = null; + + private void createAndShowUI() { + frame = new Frame("DragSourceMotionListenerTest"); + ds.addDragSourceListener(sourceAdapter); + ds.addDragSourceMotionListener(sourceAdapter); + ds.createDefaultDragGestureRecognizer(source, DnDConstants.ACTION_COPY, gestureListener); + target.setDropTarget(dropTarget); + + frame.setLayout(new GridLayout(1, 2)); + + frame.add(source); + frame.add(target); + + Toolkit.getDefaultToolkit() + .addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK); + frame.pack(); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(10); + + DragSourceMotionListenerTest dsmObj = new DragSourceMotionListenerTest(); + EventQueue.invokeAndWait(dsmObj::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + srcPoint = getPoint(source, 1); + + dstOutsidePoint = getPoint(frame, 3); + testPoint1.setLocation(dstOutsidePoint); + + dstInsidePoint = getPoint(target, 1); + testPoint2.setLocation(dstInsidePoint); + }); + robot.waitForIdle(); + + if (!dsmObj.pointInComponent(robot, srcPoint, source)) { + throw new RuntimeException("WARNING: Couldn't locate source panel."); + } + + if (!dsmObj.pointInComponent(robot, dstInsidePoint, target)) { + throw new RuntimeException("WARNING: Couldn't locate target panel."); + } + + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (; !srcPoint.equals(dstOutsidePoint); + srcPoint.translate(sign(dstOutsidePoint.x - srcPoint.x), + sign(dstOutsidePoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + } + + for (int i = 0; i < 10; i++) { + robot.mouseMove(srcPoint.x, srcPoint.y++); + } + + for (;!srcPoint.equals(dstInsidePoint); + srcPoint.translate(sign(dstInsidePoint.x - srcPoint.x), + sign(dstInsidePoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + robot.delay(1000); + + if (!passedTest1) { + throw new RuntimeException("Failed first test."); + } + + if (!passedTest2) { + throw new RuntimeException("Failed second test."); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static Point getPoint(Container container, int multiple) { + Point p = container.getLocationOnScreen(); + Dimension d = container.getSize(); + p.translate(multiple * d.width / 2, d.height / 2); + return p; + } + + public static int sign(int n) { + return Integer.compare(n, 0); + } + + public void eventDispatched(AWTEvent e) { + if (e.getID() == MouseEvent.MOUSE_RELEASED) { + clickedComponent = (Component)e.getSource(); + mouseReleaseEvent.countDown(); + } + } + + boolean pointInComponent(Robot robot, Point p, Component comp) throws Exception { + robot.waitForIdle(); + clickedComponent = null; + mouseReleaseEvent = new CountDownLatch(1); + robot.mouseMove(p.x, p.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + if (!mouseReleaseEvent.await(2, TimeUnit.SECONDS)) { + throw new RuntimeException("Mouse Release Event not received"); + } + + Component c = clickedComponent; + while (c != null && c != comp) { + c = c.getParent(); + } + return c == comp; + } +} diff --git a/test/jdk/java/awt/dnd/DragThresholdTest.java b/test/jdk/java/awt/dnd/DragThresholdTest.java new file mode 100644 index 0000000000000..bcb3bbf91c2ce --- /dev/null +++ b/test/jdk/java/awt/dnd/DragThresholdTest.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; + +/* + @test + @key headful + @bug 4415175 + @summary tests DragSource.getDragThreshold() and + that the AWT default drag gesture recognizers + honor the drag gesture motion threshold +*/ + +public class DragThresholdTest { + private static Frame frame; + private static Panel panel; + private static MouseEvent lastMouseEvent; + private static volatile boolean failed; + private static volatile Point startPoint; + private static volatile Point endPoint; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(DragThresholdTest::createAndShowDnD); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point p = panel.getLocationOnScreen(); + p.translate(50, 50); + startPoint = p; + endPoint = new Point(p.x + 2 * DragSource.getDragThreshold(), + p.y + 2 * DragSource.getDragThreshold()); + }); + + robot.mouseMove(startPoint.x, startPoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (Point p = new Point(startPoint); !p.equals(endPoint); + p.translate(sign(endPoint.x - p.x), + sign(endPoint.y - p.y))) { + robot.mouseMove(p.x, p.y); + robot.delay(100); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(200); + + if (failed) { + throw new RuntimeException("drag gesture recognized too early"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowDnD() { + frame = new Frame("DragThresholdTest"); + panel = new Panel(); + // Mouse motion listener mml is added to the panel first. + // We rely on it that this listener will be called first. + panel.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseDragged(MouseEvent evt) { + lastMouseEvent = evt; + System.out.println(evt); + } + }); + frame.add(panel); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + + DragGestureListener dgl = dge -> { + Point dragOrigin = dge.getDragOrigin(); + int diffx = Math.abs(dragOrigin.x - lastMouseEvent.getX()); + int diffy = Math.abs(dragOrigin.y - lastMouseEvent.getY()); + System.out.println("dragGestureRecognized(): " + + " diffx=" + diffx + " diffy=" + diffy + + " DragSource.getDragThreshold()=" + + DragSource.getDragThreshold()); + if (diffx <= DragSource.getDragThreshold() && + diffy <= DragSource.getDragThreshold()) { + failed = true; + System.out.println("drag gesture recognized too early!"); + } + }; + + // Default drag gesture recognizer is a mouse motion listener. + // It is added to the panel second. + new DragSource().createDefaultDragGestureRecognizer( + panel, + DnDConstants.ACTION_COPY_OR_MOVE, dgl); + frame.setVisible(true); + } + + private static int sign(int n) { + return Integer.compare(n, 0); + } +} diff --git a/test/jdk/java/awt/dnd/DragToAnotherScreenTest.java b/test/jdk/java/awt/dnd/DragToAnotherScreenTest.java new file mode 100644 index 0000000000000..89f18061845fe --- /dev/null +++ b/test/jdk/java/awt/dnd/DragToAnotherScreenTest.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Label; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.util.List; + +import javax.swing.JOptionPane; + +/* + * @test + * @bug 6179157 + * @key multimon + * @summary Tests dnd to another screen + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DragToAnotherScreenTest + */ + +public class DragToAnotherScreenTest { + private static Label label0; + private static Label label1; + private static final int HGAP = 20; + + private static final String INSTRUCTIONS = """ + The following test is applicable for Single as well + as Multi-monitor screens. + + It is a semi-automated test, the test will prompt + the user whether the drag and drop action was successful or not + and automatically PASS/FAIL the test. + + If on multi-monitor screens then please position + the drag and drop windows on different screens. + + If you can not move the mouse from the frame "Drag Source" + to the frame "Drop Target" press PASS, + else proceed to the next step. + + Drag the label "Drag me" and drop it on the + label "Drop on me". + + If you can not drag to the second label (for example + if you can not drag across screens) press FAIL. + + After the drag and drop action, the test displays + Success/Failure msg in JOptionPane. + Click on OK button and the test is configured to + automatically PASS/FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(DragToAnotherScreenTest::createAndShowUI) + .positionTestUI(DragToAnotherScreenTest::positionMultiTestUI) + .logArea(10) + .build() + .awaitAndCheck(); + } + + private static List createAndShowUI() { + PassFailJFrame.log("----- System Configuration ----"); + PassFailJFrame.log("Toolkit:" + Toolkit.getDefaultToolkit() + .getClass() + .getName()); + + GraphicsDevice[] gd = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getScreenDevices(); + if (gd.length == 1) { + PassFailJFrame.log("Single Monitor"); + } else { + PassFailJFrame.log("Multi-Monitor"); + } + PassFailJFrame.log("--------------"); + PassFailJFrame.log("Test logs:\n"); + Frame frame0 = new Frame("Drag Source", gd[0].getDefaultConfiguration()); + frame0.setSize(300, 300); + label0 = new Label("Drag me"); + frame0.add(label0); + + Frame frame1 = new Frame("Drop Target", gd[(gd.length > 1 ? 1 : 0)].getDefaultConfiguration()); + frame1.setSize(300, 300); + label1 = new Label("Drop on me"); + frame1.add(label1); + + DragGestureListener dragGestureListener = dge -> dge.startDrag(null, new StringSelection(label0.getText()), null); + new DragSource().createDefaultDragGestureRecognizer(label0, + DnDConstants.ACTION_COPY, dragGestureListener); + + DropTargetAdapter dropTargetAdapter = new DropTargetAdapter() { + public void drop(DropTargetDropEvent dtde) { + Transferable t = dtde.getTransferable(); + if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + try { + String str = (String) t.getTransferData(DataFlavor.stringFlavor); + label1.setText(str); + JOptionPane.showMessageDialog(frame0, + "getTransferData was successful", + "Test Passed", JOptionPane.PLAIN_MESSAGE); + } catch (Exception e) { + dtde.dropComplete(false); + e.printStackTrace(); + PassFailJFrame.log("getTransferData() Failed"); + JOptionPane.showMessageDialog(frame0, + "getTransferData() Failed", + "Test Failed", JOptionPane.ERROR_MESSAGE); + PassFailJFrame.forceFail("getTransferData() Failed"); + } + dtde.dropComplete(true); + } else { + dtde.rejectDrop(); + PassFailJFrame.log("stringFlavor is not supported by Transferable"); + JOptionPane.showMessageDialog(frame0, + "stringFlavor is not supported by Transferable", + "Test Failed", JOptionPane.ERROR_MESSAGE); + PassFailJFrame.forceFail("stringFlavor is not supported by Transferable"); + } + } + }; + new DropTarget(label1, dropTargetAdapter); + return List.of(frame0, frame1); + } + + private static void positionMultiTestUI(List windows, + PassFailJFrame.InstructionUI instructionUI) { + int x = instructionUI.getLocation().x + instructionUI.getSize().width + HGAP; + for (Window w : windows) { + w.setLocation(x, instructionUI.getLocation().y); + x += w.getWidth() + HGAP; + } + } +} diff --git a/test/jdk/java/awt/dnd/NonAsciiFilenames.java b/test/jdk/java/awt/dnd/NonAsciiFilenames.java new file mode 100644 index 0000000000000..b508350c05ef3 --- /dev/null +++ b/test/jdk/java/awt/dnd/NonAsciiFilenames.java @@ -0,0 +1,158 @@ +/* + * 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 + * 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 4187490 + * @summary Verify that Non-ASCII file names can be dragged and dropped + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NonAsciiFilenames + */ + +import java.awt.Color; +import java.awt.datatransfer.DataFlavor; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.io.File; +import java.util.AbstractList; + +import javax.swing.JFrame; +import javax.swing.JLabel; + +public class NonAsciiFilenames { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test must be run on an OS which does not use ISO 8859-1 + as its default encoding. + + Open a native file browsing application, such as Windows + Explorer. Try to find a file whose name uses non-ISO 8859-1 + characters. Create a file and name it such that it contains + non-ISO 8859-1 characters (For ex. é, à, ö, €, ¥). Drag + the file from the native application and drop it on the test + Frame. If the file name appears normally, then the test passes. + If boxes or question marks appear for characters, or if you see + the word "Error", then the test fails. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(NonAsciiFilenames::createUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createUI() { + JFrame frame = new JFrame(); + frame.setTitle("DropLabel test"); + frame.getContentPane().add(new DropLabel("Drop here")); + frame.setSize(300, 100); + return frame; + } +} + +class DropLabel extends JLabel implements DropTargetListener { + public DropLabel(String s) { + setText(s); + new DropTarget(this, DnDConstants.ACTION_COPY, this, true); + showDrop(false); + } + + private void showDrop(boolean b) { + setForeground(b ? Color.white : Color.black); + } + + /** + * Configure to desired flavor of dropped data. + */ + private DataFlavor getDesiredFlavor() { + return DataFlavor.javaFileListFlavor; + } + + /** + * Check to make sure that the contains the expected object types. + */ + private void checkDroppedData(Object data) { + System.out.println("Got data: " + data.getClass().getName()); + if (data instanceof AbstractList) { + AbstractList files = (AbstractList) data; + if (((File) files.get(0)).isFile()) + setText(((File) files.get(0)).toString()); + else + setText("Error: not valid file: " + + ((File) files.get(0)).toString()); + } else { + System.out.println("Error: wrong type of data dropped"); + } + } + + private boolean isDragOk(DropTargetDragEvent e) { + boolean canDrop = false; + try { + canDrop = e.isDataFlavorSupported(getDesiredFlavor()); + } catch (Exception ex) { + } + + if (canDrop) + e.acceptDrag(DnDConstants.ACTION_COPY); + else + e.rejectDrag(); + showDrop(canDrop); + return canDrop; + } + + public void dragEnter(DropTargetDragEvent e) { + isDragOk(e); + } + + + public void dragOver(DropTargetDragEvent e) { + isDragOk(e); + } + + public void dropActionChanged(DropTargetDragEvent e) { + isDragOk(e); + } + + public void dragExit(DropTargetEvent e) { + showDrop(false); + } + + public void drop(DropTargetDropEvent e) { + try { + e.acceptDrop(DnDConstants.ACTION_COPY); + checkDroppedData(e.getTransferable(). + getTransferData(getDesiredFlavor())); + } catch (Exception err) { + } + e.dropComplete(true); + showDrop(false); + } +} diff --git a/test/jdk/java/awt/dnd/RejectDragTest.java b/test/jdk/java/awt/dnd/RejectDragTest.java new file mode 100644 index 0000000000000..c65612436bc38 --- /dev/null +++ b/test/jdk/java/awt/dnd/RejectDragTest.java @@ -0,0 +1,174 @@ +/* + * 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. + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.StringSelection; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.event.InputEvent; + +/* + * @test + * @key headful + * @bug 4407521 + * @summary Tests that DragSourceListener.dragEnter() and + DragSourceListener.dragOver() are not called after + drag rejecting, but DragSourceListener.dragExit() is. + */ + +public class RejectDragTest { + private static Frame frame; + private static Robot robot; + private static volatile boolean dragEnterCalled; + private static volatile boolean dragOverCalled; + private static volatile boolean dragExitCalledAtFirst; + private static volatile Point startPoint; + private static volatile Point endPoint; + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + + EventQueue.invokeAndWait(RejectDragTest::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(RejectDragTest::addDnDListeners); + robot.waitForIdle(); + + testDnD(); + robot.waitForIdle(); + robot.delay(200); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void addDnDListeners() { + final DragSourceListener dragSourceListener = new DragSourceAdapter() { + private boolean first = true; + + public void dragEnter(DragSourceDragEvent dsde) { + first = false; + dragEnterCalled = true; + } + + public void dragExit(DragSourceEvent dse) { + if (first) { + dragExitCalledAtFirst = true; + first = false; + } + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + first = false; + } + + public void dragOver(DragSourceDragEvent dsde) { + first = false; + dragOverCalled = true; + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + first = false; + } + }; + + DragGestureListener dragGestureListener = + dge -> dge.startDrag(null, new StringSelection("OKAY"), + dragSourceListener); + new DragSource().createDefaultDragGestureRecognizer(frame, + DnDConstants.ACTION_COPY, + dragGestureListener); + + DropTargetAdapter dropTargetListener = new DropTargetAdapter() { + public void dragEnter(DropTargetDragEvent dtde) { + dtde.rejectDrag(); + } + + public void drop(DropTargetDropEvent dtde) { + dtde.rejectDrop(); + } + }; + + new DropTarget(frame, dropTargetListener); + } + + private static void createAndShowUI() { + frame = new Frame("RejectDragTest"); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void testDnD() throws Exception { + EventQueue.invokeAndWait(() -> { + Point start = frame.getLocationOnScreen(); + start.translate(50, 50); + startPoint = start; + + Point end = new Point(start); + end.translate(150, 150); + endPoint = end; + }); + + robot.mouseMove(startPoint.x, startPoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (Point p = new Point(startPoint); !p.equals(endPoint); + p.translate(sign(endPoint.x - p.x), + sign(endPoint.y - p.y))) { + robot.mouseMove(p.x, p.y); + robot.delay(30); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + if (dragEnterCalled || dragOverCalled) { + throw new RuntimeException("Test failed: " + + (dragEnterCalled ? "DragSourceListener.dragEnter() was called; " : "") + + (dragOverCalled ? "DragSourceListener.dragOver() was called; " : "") + + (!dragExitCalledAtFirst ? "DragSourceListener.dragExit() was not " + + "called immediately after rejectDrag() " : "")); + } + } + + public static int sign(int n) { + return Integer.compare(n, 0); + } +} diff --git a/test/jdk/java/awt/dnd/URLDragTest.java b/test/jdk/java/awt/dnd/URLDragTest/URLDragTest.java similarity index 100% rename from test/jdk/java/awt/dnd/URLDragTest.java rename to test/jdk/java/awt/dnd/URLDragTest/URLDragTest.java diff --git a/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java b/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java new file mode 100644 index 0000000000000..5ae7dd3890d71 --- /dev/null +++ b/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +import java.awt.Frame; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceListener; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/* + * @test + * @bug 4414739 + * @requires (os.family == "windows") + * @summary verifies that getDropSuccess() returns correct value for moving + a file from a Java drag source to the Windows shell + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual WinMoveFileToShellTest + */ + +public class WinMoveFileToShellTest { + private static final String INSTRUCTIONS = """ + Drag from the frame titled "Drag Frame" and drop on to Windows Desktop. + After Drag and Drop, check for "Drop Success" status in the log area. + If "Drop Success" is true press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(WinMoveFileToShellTest::createAndShowUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame frame = new Frame("Drag Frame"); + final DragSourceListener dsl = new DragSourceAdapter() { + public void dragDropEnd(DragSourceDropEvent e) { + PassFailJFrame.log("Drop Success: " + e.getDropSuccess()); + } + }; + + DragGestureListener dgl = dge -> { + File file = new File(System.getProperty("test.classes", ".") + + File.separator + "move.me"); + try { + file.createNewFile(); + } catch (IOException exc) { + exc.printStackTrace(); + } + ArrayList list = new ArrayList<>(); + list.add(file); + dge.startDrag(null, new FileListSelection(list), dsl); + }; + + new DragSource().createDefaultDragGestureRecognizer(frame, + DnDConstants.ACTION_MOVE, dgl); + frame.setSize(200, 100); + return frame; + } + + private static class FileListSelection implements Transferable { + private static final int FL = 0; + + private static final DataFlavor[] flavors = + new DataFlavor[] { DataFlavor.javaFileListFlavor }; + + + private List data; + + public FileListSelection(List data) { + this.data = data; + } + + public DataFlavor[] getTransferDataFlavors() { + return flavors.clone(); + } + + public boolean isDataFlavorSupported(DataFlavor flavor) { + for (DataFlavor dataFlavor : flavors) { + if (flavor.equals(dataFlavor)) { + return true; + } + } + return false; + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException + { + if (flavor.equals(flavors[FL])) { + return data; + } else { + throw new UnsupportedFlavorException(flavor); + } + } + } +} diff --git a/test/jdk/java/awt/font/FontScaling/RotatedScaledFontTest.java b/test/jdk/java/awt/font/FontScaling/RotatedScaledFontTest.java new file mode 100644 index 0000000000000..3e17bbd92c18d --- /dev/null +++ b/test/jdk/java/awt/font/FontScaling/RotatedScaledFontTest.java @@ -0,0 +1,149 @@ +/* + * 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.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.File; + +import javax.imageio.ImageIO; + +/* + * @test + * @bug 8339974 + * @summary Verifies that text draws correctly using scaled and rotated fonts. + */ +public class RotatedScaledFontTest { + + public static void main(String[] args) throws Exception { + test(0); + test(1); + test(2); + test(3); + test(4); + } + + private static void test(int quadrants) throws Exception { + + int size = 2000; + int center = size / 2; + Font base = new Font("SansSerif", Font.PLAIN, 10); + BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_BYTE_BINARY); + Graphics2D g2d = image.createGraphics(); + + try { + for (int scale = 1; scale <= 100; scale++) { + AffineTransform at = AffineTransform.getQuadrantRotateInstance(quadrants); + at.scale(scale, scale); + Font font = base.deriveFont(at); + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, image.getWidth(), image.getHeight()); + g2d.setColor(Color.BLACK); + g2d.setFont(font); + g2d.drawString("TEST", center, center); + Rectangle bounds = findTextBoundingBox(image); + if (bounds == null) { + saveImage("bounds", image); + throw new RuntimeException("Text missing: scale=" + scale + + ", quadrants=" + quadrants + ", center=" + center); + } + boolean horizontal = (bounds.width > bounds.height); + boolean expectedHorizontal = (quadrants % 2 == 0); + if (horizontal != expectedHorizontal) { + saveImage("orientation", image); + throw new RuntimeException("Wrong orientation: scale=" + scale + + ", quadrants=" + quadrants + ", center=" + center + + ", bounds=" + bounds + ", horizontal=" + horizontal + + ", expectedHorizontal=" + expectedHorizontal); + } + if (!roughlyEqual(center, bounds.x, scale) && !roughlyEqual(center, bounds.x + bounds.width, scale)) { + saveImage("xedge", image); + throw new RuntimeException("No x-edge at center: scale=" + scale + + ", quadrants=" + quadrants + ", center=" + center + + ", bounds=" + bounds); + } + if (!roughlyEqual(center, bounds.y, scale) && !roughlyEqual(center, bounds.y + bounds.height, scale)) { + saveImage("yedge", image); + throw new RuntimeException("No y-edge at center: scale=" + scale + + ", quadrants=" + quadrants + ", center=" + center + + ", bounds=" + bounds); + } + } + } finally { + g2d.dispose(); + } + } + + private static Rectangle findTextBoundingBox(BufferedImage image) { + int minX = Integer.MAX_VALUE; + int minY = Integer.MAX_VALUE; + int maxX = Integer.MIN_VALUE; + int maxY = Integer.MIN_VALUE; + int width = image.getWidth(); + int height = image.getHeight(); + int[] rowPixels = new int[width]; + for (int y = 0; y < height; y++) { + image.getRGB(0, y, width, 1, rowPixels, 0, width); + for (int x = 0; x < width; x++) { + boolean white = (rowPixels[x] == -1); + if (!white) { + if (x < minX) { + minX = x; + } + if (y < minY) { + minY = y; + } + if (x > maxX) { + maxX = x; + } + if (y > maxY) { + maxY = y; + } + } + } + } + if (minX != Integer.MAX_VALUE) { + return new Rectangle(minX, minY, maxX - minX, maxY - minY); + } else { + return null; + } + } + + private static boolean roughlyEqual(int x1, int x2, int scale) { + return Math.abs(x1 - x2) <= Math.ceil(scale / 2d) + 1; // higher scale = higher allowed variance + } + + private static void saveImage(String name, BufferedImage image) { + try { + String dir = System.getProperty("test.classes", "."); + String path = dir + File.separator + name + ".png"; + File file = new File(path); + ImageIO.write(image, "png", file); + } catch (Exception e) { + // we tried, and that's enough + } + } +} diff --git a/test/jdk/java/awt/grab/CursorTest.java b/test/jdk/java/awt/grab/CursorTest.java new file mode 100644 index 0000000000000..f08008cbd8f76 --- /dev/null +++ b/test/jdk/java/awt/grab/CursorTest.java @@ -0,0 +1,101 @@ +/* + * 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 + * 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 6364746 6400007 + * @summary Cursor should be changed correctly while Swing menu is open (input is grabbed). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CursorTest +*/ + +import java.awt.FlowLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; + +public class CursorTest { + + static final String INSTRUCTIONS = """ + After the test starts you will see a frame titled "Cursor Test Window", + with two menus in the menubar (menu1 and menu2), and a textfield and + a button, labeled "JButton". + 1. Open menu1 (it should be small and fit within the border of the frame), + 2. Verify that the pointer image (cursor) is the default desktop cursor. + 3. Move the mouse over the text field - the cursor should change its shape to caret, + 4. Move the mouse over the button - the cursor should be default one, + 5. Move the mouse to the border of the frame - cursor should be a resize one + (exact shape is dependent on the border you move over), + 6. Move the mouse out of the frame - cursor should be default one, + 7. Perform steps 2-6 in reverse order (after this the mouse should be over the open menu1), + 8. Open menu2, it should be big enough to not fit within the frame, + 9. Repeat steps 2-7 (you should end up with mouse over opened menu2 :), + 10. Close the menu. + 11. If on every step the cursor was as described, press Pass, press Fail otherwise. + """; + + static JFrame createUI() { + + JButton but = new JButton("JButton"); + JPanel panel = new JPanel(); + JTextField jtf = new JTextField("JTextField", 20); + + JFrame.setDefaultLookAndFeelDecorated(true); + JFrame frame = new JFrame("Cursor Test Window"); + frame.setLayout(new FlowLayout()); + panel.add(but); + + frame.getContentPane().add(jtf); + frame.getContentPane().add(panel); + + JMenu menu1 = new JMenu("menu1"); + menu1.add(new JMenuItem("menu1,item1")); + JMenuBar mb = new JMenuBar(); + mb.add(menu1); + JMenu menu2 = new JMenu("menu2"); + for (int i = 0; i < 10; i++) { + menu2.add(new JMenuItem("menu2,item"+i)); + } + mb.add(menu2); + frame.setJMenuBar(mb); + frame.pack(); + return frame; + } + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Cursor Test") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(CursorTest::createUI) + .build() + .awaitAndCheck(); + + } +} diff --git a/test/jdk/java/awt/grab/SystemMenuTest.java b/test/jdk/java/awt/grab/SystemMenuTest.java new file mode 100644 index 0000000000000..07676b3191124 --- /dev/null +++ b/test/jdk/java/awt/grab/SystemMenuTest.java @@ -0,0 +1,141 @@ +/* + * 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 + * 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 6364741 + * @key headful + * @requires (os.family == "windows") + * @summary REG: Using frame's menu actions does not make swing menu disappear on WinXP, + * since Mustang-b53 + */ + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.Point; +import java.awt.Robot; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; + +public class SystemMenuTest implements MenuListener { + + static volatile JMenu menu; + static volatile JMenu sub_menu; + static volatile JFrame frame; + + static volatile int selectCount = 0; + static volatile int deselectCount = 0; + static volatile boolean failed = false; + static volatile String reason = "none"; + + static void createUI() { + SystemMenuTest smt = new SystemMenuTest(); + sub_menu = new JMenu("SubMenu"); + sub_menu.addMenuListener(smt); + sub_menu.add(new JMenuItem("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); + sub_menu.add(new JMenuItem("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB")); + menu = new JMenu("Menu"); + menu.addMenuListener(smt); + menu.add(sub_menu); + JMenuBar mb = new JMenuBar(); + mb.add(menu); + + frame = new JFrame("JFrame"); + frame.setJMenuBar(mb); + frame.pack(); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + + Robot robot = new Robot(); + + SwingUtilities.invokeAndWait(SystemMenuTest::createUI); + + try { + robot.waitForIdle(); + robot.delay(2000); + + Point p = menu.getLocationOnScreen(); + robot.mouseMove(p.x + menu.getWidth() / 2, p.y + menu.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(2000); + + p = sub_menu.getLocationOnScreen(); + robot.mouseMove(p.x + sub_menu.getWidth() / 2, p.y + sub_menu.getHeight() /2 ); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + robot.delay(2000); + + // Alt-Space to invoke System Menu, should close Swing menus. + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_SPACE); + robot.delay(50); + robot.keyRelease(KeyEvent.VK_SPACE); + robot.keyRelease(KeyEvent.VK_ALT); + robot.waitForIdle(); + robot.delay(2000); + + if (selectCount != 2 || deselectCount != 2) { + throw new RuntimeException("unexpected selection count " + selectCount + ", " + deselectCount); + } + if (failed) { + throw new RuntimeException("Failed because " + reason); + } + } finally { + if (frame != null) { + SwingUtilities.invokeAndWait(frame::dispose); + } + } + } + + public void menuCanceled(MenuEvent e) { + System.out.println("cancelled"+e.getSource()); + } + + public void menuDeselected(MenuEvent e) { + deselectCount++; + if (selectCount != 2) { + failed = true; + reason = "deselect without two selects"; + } + System.out.println("deselected"+e.getSource()); + } + + public void menuSelected(MenuEvent e) { + if (deselectCount != 0) { + failed = true; + reason = "select without non-zero deselects"; + } + selectCount++; + System.out.println("selected"+e.getSource()); + } +} diff --git a/test/jdk/java/awt/print/PrinterJob/AlphaPrintTest.java b/test/jdk/java/awt/print/PrinterJob/AlphaPrintTest.java index 5214ab11ec581..9a1ff616ee93f 100644 --- a/test/jdk/java/awt/print/PrinterJob/AlphaPrintTest.java +++ b/test/jdk/java/awt/print/PrinterJob/AlphaPrintTest.java @@ -22,23 +22,13 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @bug 8240654 * @summary Test printing alpha colors - banded printing works with ZGC. * @key headful printer * @requires (os.family == "windows") - * @requires vm.gc.ZSinglegen - * @run main/manual/othervm -XX:+UseZGC -XX:-ZGenerational -Dsun.java2d.d3d=false AlphaPrintTest - */ - -/* - * @test id=ZGenerational - * @bug 8240654 - * @summary Test printing alpha colors - banded printing works with ZGC. - * @key headful printer - * @requires (os.family == "windows") - * @requires vm.gc.ZGenerational - * @run main/manual/othervm -XX:+UseZGC -XX:+ZGenerational -Dsun.java2d.d3d=false AlphaPrintTest + * @requires vm.gc.Z + * @run main/manual/othervm -XX:+UseZGC -Dsun.java2d.d3d=false AlphaPrintTest */ import java.awt.Color; diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 45cd191ae39db..41c5fdf8ccdbf 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -24,6 +24,7 @@ import java.awt.AWTException; import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Font; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; @@ -44,6 +45,7 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -69,6 +71,7 @@ import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.Timer; +import javax.swing.border.Border; import javax.swing.text.JTextComponent; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; @@ -79,15 +82,77 @@ import static javax.swing.SwingUtilities.isEventDispatchThread; /** - * Provides a framework for manual tests to display test instructions and - * Pass/Fail buttons. + * A framework for manual tests to display test instructions and + * Pass / Fail buttons. The framework automatically + * creates a frame to display the instructions, provides buttons + * to select the test result, and handles test timeout. + * + *

              + * The instruction UI frame displays a timer at the top which indicates + * how much time is left. The timer can be paused using the Pause + * button to the right of the time; the title of the button changes to + * Resume. To resume the timer, use the Resume button. + * + *

              + * In the center, the instruction UI frame displays instructions for the + * tester. The instructions can be either plain text or HTML. If the + * text of the instructions starts with {@code ""}, the + * instructions are displayed as HTML, as supported by Swing, which + * provides richer formatting options. + *

              + * The instructions are displayed in a text component with word-wrapping + * so that there's no horizontal scroll bar. If the text doesn't fit, a + * vertical scroll bar is shown. Use {@code rows} and {@code columns} + * parameters to change the size of this text component. + * If possible, choose the number of rows and columns so that + * the instructions fit and no scroll bars are shown. + * + *

              + * At the bottom, the instruction UI frame displays the + * Pass and Fail buttons. The tester clicks either Pass + * or Fail button to finish the test. When the tester clicks the + * Fail button, the framework displays a dialog box prompting for + * a reason why the test fails. The tester enters the reason and clicks + * OK to close the dialog and fail the test, + * or simply closes the dialog to fail the test without providing any reason. + * + *

              + * If you enable the screenshot feature, a Screenshot button is + * added to the right of the Fail button. The tester can choose either + * Capture Full Screen (default) or Capture Frames and click the + * Screenshot button to take a screenshot. + * If there are multiple screens, screenshots of each screen are created. + * If the tester selects the Capture Frames mode, screenshots of all + * the windows or frames registered in the {@code PassFailJFrame} framework + * are created. + * + *

              + * If you enable a log area, the instruction UI frame adds a text component + * to display log messages below the buttons. + * Use {@link #log(String) log}, {@link #logSet(String) logSet} + * and {@link #logClear() logClear} static methods of {@code PassFailJFrame} + * to add or clear messages from the log area. + * + *

              + * After you create an instance of {@code PassFailJFrame}, call the + * {@link #awaitAndCheck() awaitAndCheck} method to stop the current thread + * (usually the main thread) and wait until the tester clicks + * either Pass or Fail button, + * or until the test times out. *

              - * Instructions for the user can be either plain text or HTML as supported - * by Swing. If the instructions start with {@code }, the - * instructions are displayed as HTML. + * The call to the {@code awaitAndCheck} method is usually the last + * statement in the {@code main} method of your test. + * If the test fails, an exception is thrown to signal the failure to jtreg. + * The test fails if the tester clicks the Fail button, + * if the timeout occurs, + * or if any window or frame is closed. *

              + * Before returning from {@code awaitAndCheck}, the framework disposes of + * all the windows and frames. + * + *

              Sample Manual Test

              * A simple test would look like this: - *
              {@code
              + * {@snippet id='sampleManualTestCode' lang='java':
                * public class SampleManualTest {
                *     private static final String INSTRUCTIONS =
                *             "Click Pass, or click Fail if the test failed.";
              @@ -95,7 +160,7 @@
                *     public static void main(String[] args) throws Exception {
                *         PassFailJFrame.builder()
                *                       .instructions(INSTRUCTIONS)
              - *                       .testUI(() -> createTestUI())
              + *                       .testUI(SampleManualTest::createTestUI)
                *                       .build()
                *                       .awaitAndCheck();
                *     }
              @@ -106,39 +171,87 @@
                *         return testUI;
                *     }
                * }
              - * }
              + * } *

              - * The above example uses the {@link Builder Builder} to set the parameters of - * the instruction frame. It is the recommended way. + * The above example uses the {@link Builder Builder} class to set + * the parameters of the instruction frame. + * It is the recommended way. + * *

              - * The framework will create instruction UI, it will call - * the provided {@code createTestUI} on the Event Dispatch Thread (EDT), - * and it will automatically position the test UI and make it visible. + * The framework will create an instruction UI frame, it will call + * the provided {@code createTestUI} on the Event Dispatch Thread (EDT), + * and it will automatically position the test UI frame and make it visible. + * + *

              + * Add the following jtreg tags before the test class declaration + * {@snippet : + * /* + * * @test + * * @summary Sample manual test + * * @library /java/awt/regtesthelpers + * * @build PassFailJFrame + * * @run main/manual SampleManualTest + * } + * and the closing comment tag */. *

              + * The {@code @library} tag points to the location of the + * {@code PassFailJFrame} class in the source code; + * the {@code @build} tag makes jtreg compile the {@code PassFailJFrame} class, + * and finally the {@code @run} tag specifies it is a manual + * test and the class to run. + * + *

              Using {@code Builder}

              + * Use methods of the {@link Builder Builder} class to set or change + * parameters of {@code PassFailJFrame} and its instruction UI: + *
                + *
              • {@link Builder#title(String) title} sets + * the title of the instruction UI + * (the default is {@value #TITLE});
              • + *
              • {@link Builder#testTimeOut(long) testTimeOut} sets + * the timeout of the test + * (the default is {@value #TEST_TIMEOUT});
              • + *
              • {@link Builder#rows(int) rows} and + * {@link Builder#columns(int) columns} control the size + * the text component which displays the instructions + * (the default number of rows is the number of lines in the text + * of the instructions, + * the default number of columns is {@value #COLUMNS});
              • + *
              • {@link Builder#logArea() logArea} adds a log area;
              • + *
              • {@link Builder#screenCapture() screenCapture} + * enables screenshots.
              • + *
              + * + *

              Using {@code testUI} and {@code splitUI}

              * The {@code Builder.testUI} methods accept interfaces which create one window * 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 + * For simple test UI, use {@link Builder#splitUI(PanelCreator) splitUI}, + * or explicitly + * {@link Builder#splitUIRight(PanelCreator) splitUIRight} or + * {@link Builder#splitUIBottom(PanelCreator) splitUIBottom} with + * a {@link PanelCreator PanelCreator}. + * The framework will call the provided + * {@code createUIPanel} method 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. *

              + * Note: support for multiple windows is incomplete. + * + *

              Obsolete Sample Test

              * 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. * The following sample demonstrates it: - *
              {@code
              - * public class SampleOldManualTest {
              + * {@snippet id='obsoleteSampleTestCode' lang='java':
              + * public class ObsoleteManualTest {
                *     private static final String INSTRUCTIONS =
                *             "Click Pass, or click Fail if the test failed.";
                *
                *     public static void main(String[] args) throws Exception {
                *         PassFailJFrame passFail = new PassFailJFrame(INSTRUCTIONS);
                *
              - *         SwingUtilities.invokeAndWait(() -> createTestUI());
              + *         SwingUtilities.invokeAndWait(ObsoleteManualTest::createTestUI);
                *
                *         passFail.awaitAndCheck();
                *     }
              @@ -151,31 +264,54 @@
                *         testUI.setVisible(true);
                *     }
                * }
              - * }
              + * } *

              - * Use methods of the {@code Builder} class or constructors of the - * {@code PassFailJFrame} class to control other parameters: - *

                - *
              • the title of the instruction UI,
              • - *
              • the timeout of the test,
              • - *
              • the size of the instruction UI via rows and columns, and
              • - *
              • to add a log area,
              • - *
              • to enable screenshots.
              • - *
              + * This sample uses {@link #PassFailJFrame(String) a constructor} of + * {@code PassFailJFrame} to create its instance, + * there are several overloads provided which allow changing other parameters. + *

              + * When you use the constructors, you have to explicitly create + * your test UI window on EDT. After you create the window, + * you need to register it with the framework using + * {@link #addTestWindow(Window) addTestWindow} + * to ensure the window is disposed of when the test completes. + * Before showing the window, you have to call + * {@link #positionTestWindow(Window, Position) positionTestWindow} + * to position the test window near the instruction UI frame provided + * by the framework. And finally you have to explicitly show the test UI + * window by calling {@code setVisible(true)}. + *

              + * To avoid the complexity, use the {@link Builder Builder} class + * which provides a streamlined way to configure and create an + * instance of {@code PassFailJFrame}. + *

              + * Consider updating tests which use {@code PassFailJFrame} constructors to + * use the builder pattern. */ public final class PassFailJFrame { - private static final String TITLE = "Test Instruction Frame"; + /** A default title for the instruction frame. */ + private static final String TITLE = "Test Instructions"; + + /** A default test timeout. */ private static final long TEST_TIMEOUT = 5; + + /** A default number of rows for displaying the test instructions. */ private static final int ROWS = 10; + /** A default number of columns for displaying the test instructions. */ private static final int COLUMNS = 40; + /** + * A gap between windows. + */ + public static final int WINDOW_GAP = 8; + /** * Prefix for the user-provided failure reason. */ private static final String FAILURE_REASON = "Failure Reason:\n"; /** - * The failure reason message when the user didn't provide one. + * The failure reason message when the user doesn't provide one. */ private static final String EMPTY_REASON = "(no reason provided)"; @@ -528,6 +664,8 @@ private static JComponent createInstructionUIPanel(String instructions, boolean addLogArea, int logAreaRows) { JPanel main = new JPanel(new BorderLayout()); + main.setBorder(createFrameBorder()); + timeoutHandlerPanel = new TimeoutHandlerPanel(testTimeOut); main.add(timeoutHandlerPanel, BorderLayout.NORTH); @@ -536,7 +674,11 @@ private static JComponent createInstructionUIPanel(String instructions, : configurePlainText(instructions, rows, columns); text.setEditable(false); - main.add(new JScrollPane(text), BorderLayout.CENTER); + JPanel textPanel = new JPanel(new BorderLayout()); + textPanel.setBorder(createEmptyBorder(GAP, 0, GAP, 0)); + textPanel.add(new JScrollPane(text), BorderLayout.CENTER); + + main.add(textPanel, BorderLayout.CENTER); JButton btnPass = new JButton("Pass"); btnPass.addActionListener((e) -> { @@ -550,7 +692,8 @@ private static JComponent createInstructionUIPanel(String instructions, timeoutHandlerPanel.stop(); }); - JPanel buttonsPanel = new JPanel(); + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, + GAP, 0)); buttonsPanel.add(btnPass); buttonsPanel.add(btnFail); @@ -561,10 +704,12 @@ private static JComponent createInstructionUIPanel(String instructions, if (addLogArea) { logArea = new JTextArea(logAreaRows, columns); logArea.setEditable(false); + logArea.setBorder(createTextBorder()); Box buttonsLogPanel = Box.createVerticalBox(); buttonsLogPanel.add(buttonsPanel); + buttonsLogPanel.add(Box.createVerticalStrut(GAP)); buttonsLogPanel.add(new JScrollPane(logArea)); main.add(buttonsLogPanel, BorderLayout.SOUTH); @@ -582,7 +727,7 @@ private static JTextComponent configurePlainText(String instructions, JTextArea text = new JTextArea(instructions, rows, columns); text.setLineWrap(true); text.setWrapStyleWord(true); - text.setBorder(createEmptyBorder(4, 4, 4, 4)); + text.setBorder(createTextBorder()); return text; } @@ -604,6 +749,29 @@ private static JTextComponent configureHTML(String instructions, return text; } + /** A default gap between components. */ + private static final int GAP = 4; + + /** + * Creates a default border for frames or dialogs. + * It uses the default gap of {@value GAP}. + * + * @return the border for frames and dialogs + */ + private static Border createFrameBorder() { + return createEmptyBorder(GAP, GAP, GAP, GAP); + } + + /** + * Creates a border set to text area. + * It uses the default gap of {@value GAP}. + * + * @return the border for text area + */ + private static Border createTextBorder() { + return createEmptyBorder(GAP, GAP, GAP, GAP); + } + /** * Creates a test UI window. @@ -817,7 +985,7 @@ public void windowClosing(WindowEvent e) { private static JComponent createCapturePanel() { JComboBox screenShortType = new JComboBox<>(CaptureType.values()); - JButton capture = new JButton("ScreenShot"); + JButton capture = new JButton("Screenshot"); capture.addActionListener((e) -> captureScreen((CaptureType) screenShortType.getSelectedItem())); @@ -829,7 +997,7 @@ private static JComponent createCapturePanel() { private enum CaptureType { FULL_SCREEN("Capture Full Screen"), - WINDOWS("Capture Individual Frame"); + WINDOWS("Capture Frames"); private final String type; CaptureType(String type) { @@ -955,26 +1123,30 @@ public void awaitAndCheck() throws InterruptedException, InvocationTargetExcepti * Requests the description of the test failure reason from the tester. */ private static void requestFailureReason() { - final JDialog dialog = new JDialog(frame, "Test Failure ", true); - dialog.setTitle("Failure reason"); - JPanel jPanel = new JPanel(new BorderLayout()); - JTextArea jTextArea = new JTextArea(5, 20); + final JDialog dialog = new JDialog(frame, "Failure reason", true); + + JTextArea reason = new JTextArea(5, 20); + reason.setBorder(createTextBorder()); JButton okButton = new JButton("OK"); okButton.addActionListener((ae) -> { - String text = jTextArea.getText(); + String text = reason.getText(); setFailureReason(FAILURE_REASON + (!text.isEmpty() ? text : EMPTY_REASON)); dialog.setVisible(false); }); - jPanel.add(new JScrollPane(jTextArea), BorderLayout.CENTER); - - JPanel okayBtnPanel = new JPanel(); + JPanel okayBtnPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, + GAP, 0)); + okayBtnPanel.setBorder(createEmptyBorder(GAP, 0, 0, 0)); okayBtnPanel.add(okButton); - jPanel.add(okayBtnPanel, BorderLayout.SOUTH); - dialog.add(jPanel); + JPanel main = new JPanel(new BorderLayout()); + main.setBorder(createFrameBorder()); + main.add(new JScrollPane(reason), BorderLayout.CENTER); + main.add(okayBtnPanel, BorderLayout.SOUTH); + + dialog.add(main); dialog.setLocationRelativeTo(frame); dialog.pack(); dialog.setVisible(true); @@ -1007,13 +1179,13 @@ private static void positionInstructionFrame(final Position position) { switch (position) { case HORIZONTAL: - int newX = ((screenSize.width / 2) - frame.getWidth()); + int newX = (((screenSize.width + WINDOW_GAP) / 2) - frame.getWidth()); frame.setLocation((newX + screenInsets.left), (frame.getY() + screenInsets.top)); break; case VERTICAL: - int newY = ((screenSize.height / 2) - frame.getHeight()); + int newY = (((screenSize.height + WINDOW_GAP) / 2) - frame.getHeight()); frame.setLocation((frame.getX() + screenInsets.left), (newY + screenInsets.top)); break; @@ -1061,13 +1233,13 @@ public static void positionTestWindow(Window testWindow, Position position) { switch (position) { case HORIZONTAL: case TOP_LEFT_CORNER: - testWindow.setLocation((frame.getX() + frame.getWidth() + 5), + testWindow.setLocation((frame.getX() + frame.getWidth() + WINDOW_GAP), frame.getY()); break; case VERTICAL: testWindow.setLocation(frame.getX(), - (frame.getY() + frame.getHeight() + 5)); + (frame.getY() + frame.getHeight() + WINDOW_GAP)); break; } } @@ -1370,6 +1542,7 @@ public Builder testUI(WindowCreator windowCreator) { return this; } + /** * Adds an implementation of {@link PositionWindows PositionWindows} * which the framework will use to position multiple test UI windows. @@ -1393,6 +1566,77 @@ public Builder positionTestUI(PositionWindows positionWindows) { return this; } + /** + * Positions the test UI windows in a row to the right of + * the instruction frame. The top of the windows is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIRightRow() { + return position(Position.HORIZONTAL) + .positionTestUI(WindowLayouts::rightOneRow); + } + + /** + * Positions the test UI windows in a column to the right of + * the instruction frame. The top of the first window is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIRightColumn() { + return position(Position.HORIZONTAL) + .positionTestUI(WindowLayouts::rightOneColumn); + } + + /** + * Positions the test UI windows in a column to the right of + * the instruction frame centering the stack of the windows. + * + * @return this builder + */ + public Builder positionTestUIRightColumnCentered() { + return position(Position.HORIZONTAL) + .positionTestUI(WindowLayouts::rightOneColumnCentered); + } + + /** + * Positions the test UI windows in a row to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIBottomRow() { + return position(Position.VERTICAL) + .positionTestUI(WindowLayouts::bottomOneRow); + } + + /** + * Positions the test UI windows in a row to the bottom of + * the instruction frame centering the row of the windows. + * + * @return this builder + */ + public Builder positionTestUIBottomRowCentered() { + return position(Position.VERTICAL) + .positionTestUI(WindowLayouts::bottomOneRowCentered); + } + + /** + * Positions the test UI windows in a column to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIBottomColumn() { + return position(Position.VERTICAL) + .positionTestUI(WindowLayouts::bottomOneColumn); + } + + /** * Adds a {@code WindowListCreator} which the framework will use * to create a list of test UI windows. @@ -1495,6 +1739,7 @@ public Builder testUI(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. @@ -1586,9 +1831,41 @@ public PassFailJFrame build() throws InterruptedException, return new PassFailJFrame(this); } + /** + * Returns the file name of the test, if the {@code test.file} property + * is defined, concatenated with {@code " - "} which serves as a prefix + * to the default instruction frame title; + * or an empty string if the {@code test.file} property is not defined. + * + * @return the prefix to the default title: + * either the file name of the test or an empty string + * + * @see jtreg + * test-specific system properties and environment variables + */ + private static String getTestFileNamePrefix() { + String testFile = System.getProperty("test.file"); + if (testFile == null) { + return ""; + } + + return Paths.get(testFile).getFileName().toString() + + " - "; + } + + /** + * Validates the state of the builder and + * expands parameters that have no assigned values + * to their default values. + * + * @throws IllegalStateException if no instructions are provided, + * or if {@code PositionWindows} implementation is + * provided but neither window creator nor + * test window list are set + */ private void validate() { if (title == null) { - title = TITLE; + title = getTestFileNamePrefix() + TITLE; } if (instructions == null || instructions.isEmpty()) { diff --git a/test/jdk/java/awt/regtesthelpers/WindowLayouts.java b/test/jdk/java/awt/regtesthelpers/WindowLayouts.java new file mode 100644 index 0000000000000..4368e3a59432f --- /dev/null +++ b/test/jdk/java/awt/regtesthelpers/WindowLayouts.java @@ -0,0 +1,237 @@ +/* + * 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. + */ + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GraphicsConfiguration; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Window; +import java.util.List; + +import static java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment; +import static java.awt.Toolkit.getDefaultToolkit; + +/** + * A utility class which provides standard window layouts for multi-window + * manual tests using the {@link PassFailJFrame} framework. + * The layout methods {@code right-} and {@code bottom-} implement the + * {@link PassFailJFrame.PositionWindows PositionWindows} interface and + * can be used directly or via builder methods. + *

              + * There are several helper methods, such as + * {@link #getScreenCenter() getScreenCenter}, which could help you + * implement customized windows layouts. + */ +public final class WindowLayouts { + + /** Private constructor to prevent instantiating the utility class. */ + private WindowLayouts() { + } + + /** A gap between windows. (Local copy makes expressions shorter.) */ + private static final int WINDOW_GAP = PassFailJFrame.WINDOW_GAP; + + /** + * Lays out the window list in one row to the right of + * the instruction frame. The top of the windows is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void rightOneRow(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutRow(instructionUI.getLocation().x + + instructionUI.getSize().width + + WINDOW_GAP, + instructionUI.getLocation().y, + windows); + } + + /** + * Lays out the window list in one column to the right of + * the instruction frame. The top of the first window is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void rightOneColumn(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutColumn(instructionUI.getLocation().x + + instructionUI.getSize().width + + WINDOW_GAP, + instructionUI.getLocation().y, + windows); + } + + /** + * Lays out the window list in one column to the right of + * the instruction frame centering the stack of the windows. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void rightOneColumnCentered(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutColumn(instructionUI.getLocation().x + + instructionUI.getSize().width + + WINDOW_GAP, + getScreenCenter().y + - getWindowListHeight(windows) / 2, + windows); + } + + + /** + * Lays out the window list in one row to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void bottomOneRow(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutRow(instructionUI.getLocation().x, + instructionUI.getLocation().y + + instructionUI.getSize().height + + WINDOW_GAP, + windows); + } + + /** + * Lays out the window list in one row to the bottom of + * the instruction frame centering the row of the windows. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void bottomOneRowCentered(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutRow(getScreenCenter().x + - getWindowListWidth(windows) / 2, + instructionUI.getLocation().y + + instructionUI.getSize().height + + WINDOW_GAP, + windows); + } + + /** + * Lays out the window list in one column to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void bottomOneColumn(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutColumn(instructionUI.getLocation().x, + instructionUI.getLocation().y + + instructionUI.getSize().height + + WINDOW_GAP, + windows); + } + + + /** + * Lays out the window list in one row starting at + * ({@code x0}, {@code y}). + * + * @param x0 the starting x coordinate of the windows + * @param y the y coordinate of the windows + * @param windows the list of windows to lay out + */ + public static void layoutRow(final int x0, + final int y, + final List windows) { + int x = x0; + for (Window w : windows) { + w.setLocation(x, y); + x += w.getWidth() + WINDOW_GAP; + } + } + + /** + * Lays out the window list in one column starting at + * ({@code x}, {@code y0}). + * + * @param x the x coordinate of the windows + * @param y0 the starting y coordinate of the windows + * @param windows the list of windows to lay out + */ + public static void layoutColumn(final int x, + final int y0, + final List windows) { + int y = y0; + for (Window w : windows) { + w.setLocation(x, y); + y += w.getHeight() + WINDOW_GAP; + } + } + + + /** + * {@return the center point of the main screen} + */ + public static Point getScreenCenter() { + GraphicsConfiguration gc = getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .getDefaultConfiguration(); + Dimension size = gc.getBounds() + .getSize(); + Insets insets = getDefaultToolkit() + .getScreenInsets(gc); + + return new Point((size.width - insets.left - insets.right) / 2, + (size.height - insets.top - insets.bottom) / 2); + } + + /** + * {@return width of the windows in the list, taking into account + * the gap between windows} + * + * @param windows the list of windows to get the width of + */ + public static int getWindowListWidth(final List windows) { + return windows.stream() + .mapToInt(Component::getWidth) + .sum() + + WINDOW_GAP * (windows.size() - 1); + } + + /** + * {@return height of the windows in the list, taking into account + * the gap between windows} + * + * @param windows the list of windows to get the height of + */ + public static int getWindowListHeight(final List windows) { + return windows.stream() + .mapToInt(Component::getHeight) + .sum() + + WINDOW_GAP * (windows.size() - 1); + } +} diff --git a/test/jdk/java/foreign/TestUpcallStress.java b/test/jdk/java/foreign/TestUpcallStress.java new file mode 100644 index 0000000000000..b7a53dd6c01d0 --- /dev/null +++ b/test/jdk/java/foreign/TestUpcallStress.java @@ -0,0 +1,98 @@ +/* + * 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 + * @requires jdk.foreign.linker != "FALLBACK" + * @requires (os.arch == "aarch64" | os.arch=="riscv64") & os.name == "Linux" + * @requires os.maxMemory > 4G + * @requires vm.compMode != "Xcomp" + * @modules java.base/jdk.internal.foreign + * @build NativeTestHelper CallGeneratorHelper TestUpcallBase + * @bug 8337753 + * + * @run testng/othervm/timeout=3200 + * -Xcheck:jni + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:-VerifyDependencies + * --enable-native-access=ALL-UNNAMED + * -Dgenerator.sample.factor=17 + * TestUpcallStress + */ + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; + +import org.testng.annotations.Test; + +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.*; +import java.util.function.Consumer; + +public class TestUpcallStress extends TestUpcallBase { + + static { + System.loadLibrary("TestUpcall"); + } + + @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) + public void testUpcallsStress(int count, String fName, Ret ret, List paramTypes, + List fields) throws Throwable { + ExecutorService executor = Executors.newFixedThreadPool(16); + for (int threadIdx = 0; threadIdx < 16; threadIdx++) { + executor.submit(() -> { + for (int iter = 0; iter < 10000; iter++) { + List> returnChecks = new ArrayList<>(); + List> argChecks = new ArrayList<>(); + MemorySegment addr = findNativeOrThrow(fName); + try (Arena arena = Arena.ofConfined()) { + FunctionDescriptor descriptor = function(ret, paramTypes, fields); + MethodHandle mh = downcallHandle(LINKER, addr, arena, descriptor); + AtomicReference capturedArgs = new AtomicReference<>(); + Object[] args = makeArgs(capturedArgs, arena, descriptor, returnChecks, argChecks, 0); + + Object res = mh.invokeWithArguments(args); + + if (ret == Ret.NON_VOID) { + returnChecks.forEach(c -> c.accept(res)); + } + + Object[] capturedArgsArr = capturedArgs.get(); + for (int i = 0; i < capturedArgsArr.length; i++) { + argChecks.get(i).accept(capturedArgsArr[i]); + } + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + }); + } + // This shutdownNow is 'wrong', since it doesn't wait for tasks to terminate, + // but it seems to be the only way to reproduce the race of JDK-8337753 + executor.shutdownNow(); + } +} diff --git a/test/jdk/java/foreign/stackwalk/TestAsyncStackWalk.java b/test/jdk/java/foreign/stackwalk/TestAsyncStackWalk.java index c21225575f9e9..1c234a9c3c658 100644 --- a/test/jdk/java/foreign/stackwalk/TestAsyncStackWalk.java +++ b/test/jdk/java/foreign/stackwalk/TestAsyncStackWalk.java @@ -39,8 +39,8 @@ */ /* - * @test id=ZSinglegen - * @requires vm.gc.ZSinglegen + * @test id=Z + * @requires vm.gc.Z * @library /test/lib * @library ../ * @build jdk.test.whitebox.WhiteBox @@ -52,25 +52,7 @@ * -XX:+WhiteBoxAPI * --enable-native-access=ALL-UNNAMED * -Xbatch - * -XX:+UseZGC -XX:-ZGenerational - * TestAsyncStackWalk - */ - -/* - * @test id=ZGenerational - * @requires vm.gc.ZGenerational - * @library /test/lib - * @library ../ - * @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 - * --enable-native-access=ALL-UNNAMED - * -Xbatch - * -XX:+UseZGC -XX:+ZGenerational + * -XX:+UseZGC * TestAsyncStackWalk */ diff --git a/test/jdk/java/foreign/stackwalk/TestStackWalk.java b/test/jdk/java/foreign/stackwalk/TestStackWalk.java index 5218792658f0c..193a71affdd93 100644 --- a/test/jdk/java/foreign/stackwalk/TestStackWalk.java +++ b/test/jdk/java/foreign/stackwalk/TestStackWalk.java @@ -39,8 +39,8 @@ */ /* - * @test id=ZSinglegen - * @requires vm.gc.ZSinglegen + * @test id=Z + * @requires vm.gc.Z * @library /test/lib * @library ../ * @build jdk.test.whitebox.WhiteBox @@ -52,25 +52,7 @@ * -XX:+WhiteBoxAPI * --enable-native-access=ALL-UNNAMED * -Xbatch - * -XX:+UseZGC -XX:-ZGenerational - * TestStackWalk - */ - -/* - * @test id=ZGenerational - * @requires vm.gc.ZGenerational - * @library /test/lib - * @library ../ - * @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 - * --enable-native-access=ALL-UNNAMED - * -Xbatch - * -XX:+UseZGC -XX:+ZGenerational + * -XX:+UseZGC * TestStackWalk */ diff --git a/test/jdk/java/io/Console/DefaultCharsetTest.java b/test/jdk/java/io/Console/DefaultCharsetTest.java new file mode 100644 index 0000000000000..0b17217e10974 --- /dev/null +++ b/test/jdk/java/io/Console/DefaultCharsetTest.java @@ -0,0 +1,53 @@ +/* + * 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 org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * @test + * @bug 8341975 + * @summary Tests the default charset. It should honor `stdout.encoding` + * which should be the same as System.out.charset() + * @modules jdk.internal.le + * @run junit/othervm -Dstdout.encoding=UTF-8 DefaultCharsetTest + * @run junit/othervm -Dstdout.encoding=ISO-8859-1 DefaultCharsetTest + * @run junit/othervm -Dstdout.encoding=US-ASCII DefaultCharsetTest + * @run junit/othervm -Dstdout.encoding=foo DefaultCharsetTest + * @run junit/othervm DefaultCharsetTest + */ +public class DefaultCharsetTest { + @Test + public void testDefaultCharset() { + var stdoutEncoding = System.getProperty("stdout.encoding"); + var sysoutCharset = System.out.charset(); + var consoleCharset = System.console().charset(); + System.out.println(""" + stdout.encoding = %s + System.out.charset() = %s + System.console().charset() = %s + """.formatted(stdoutEncoding, sysoutCharset.name(), consoleCharset.name())); + assertEquals(consoleCharset, sysoutCharset, + "Charsets for System.out and Console differ for stdout.encoding: %s".formatted(stdoutEncoding)); + } +} diff --git a/test/jdk/java/io/FileInputStream/PseudoDevice.java b/test/jdk/java/io/FileInputStream/PseudoDevice.java new file mode 100644 index 0000000000000..9f581c3ff81d8 --- /dev/null +++ b/test/jdk/java/io/FileInputStream/PseudoDevice.java @@ -0,0 +1,210 @@ +/* + * 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 8341666 + * @summary Test of FileInputStream reading from stdin and a named pipe + * @requires os.family != "windows" + * @library .. /test/lib + * @build jdk.test.lib.Platform + * @run junit/othervm --enable-native-access=ALL-UNNAMED PseudoDevice + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import jdk.test.lib.Platform; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; +import static org.junit.jupiter.api.Assertions.*; + +public class PseudoDevice { + + private static final String PIPE = "pipe"; + private static final File PIPE_FILE = new File(PIPE); + private static final String SENTENCE = + "Rien n'est permis mais tout est possible"; + + private static class mkfifo { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + ValueLayout.JAVA_INT, + ValueLayout.ADDRESS, + ValueLayout.JAVA_SHORT + ); + + public static final MemorySegment ADDR; + static { + Linker linker = Linker.nativeLinker(); + SymbolLookup stdlib = linker.defaultLookup(); + ADDR = stdlib.find("mkfifo").orElseThrow(); + } + + public static final MethodHandle HANDLE = + Linker.nativeLinker().downcallHandle(ADDR, DESC); + } + + public static int mkfifo(MemorySegment x0, short x1) { + var mh$ = mkfifo.HANDLE; + try { + return (int)mh$.invokeExact(x0, x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static Thread createWriteThread() { + Thread t = new Thread( + new Runnable() { + public void run() { + try (FileOutputStream fos = new FileOutputStream(PIPE);) { + fos.write(SENTENCE.getBytes()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + ); + t.start(); + return t; + } + + @BeforeAll + static void before() throws InterruptedException, IOException { + if (Platform.isWindows()) + return; + + PIPE_FILE.delete(); + try (var newArena = Arena.ofConfined()) { + var addr = newArena.allocateFrom(PIPE); + short mode = 0666; + assertEquals(0, mkfifo(addr, mode)); + } + if (!PIPE_FILE.exists()) + throw new RuntimeException("Failed to create " + PIPE); + } + + @AfterAll + static void after() throws IOException { + if (Platform.isWindows()) + return; + + PIPE_FILE.delete(); + } + + /** + * Tests that new FileInputStream(File).available() does not throw + */ + @Test + @DisabledOnOs(OS.WINDOWS) + void availableStdin() throws IOException { + File stdin = new File("/dev", "stdin"); + if (stdin.exists()) { + try (InputStream s = new FileInputStream(stdin);) { + s.available(); + } + } + } + + /** + * Tests that new FileInputStream(File).skip(0) does not throw + */ + @Test + @DisabledOnOs(OS.WINDOWS) + void skipStdin() throws IOException { + File stdin = new File("/dev", "stdin"); + if (stdin.exists()) { + try (InputStream s = new FileInputStream(stdin);) { + s.skip(0); + } + } + } + + /** + * Tests new FileInputStream(File).readAllBytes(). + */ + @Test + @DisabledOnOs(OS.WINDOWS) + void readAllBytes() throws InterruptedException, IOException { + Thread t = createWriteThread(); + try (InputStream in = new FileInputStream(PIPE)) { + String s = new String(in.readAllBytes()); + System.out.println(s); + assertEquals(SENTENCE, s); + } finally { + t.join(); + } + } + + /** + * Tests new FileInputStream(File).readNBytes(byte[],int,int). + */ + @Test + @DisabledOnOs(OS.WINDOWS) + void readNBytesNoOverride() throws InterruptedException, IOException { + Thread t = createWriteThread(); + try (InputStream in = new FileInputStream(PIPE)) { + final int offset = 11; + final int length = 17; + assert length <= SENTENCE.length(); + byte[] b = new byte[offset + length]; + int n = in.readNBytes(b, offset, length); + String s = new String(b, offset, length); + System.out.println(s); + assertEquals(SENTENCE.substring(0, length), s); + } finally { + t.join(); + } + } + + /** + * Tests new FileInputStream(File).readNBytes(int). + */ + @Test + @DisabledOnOs(OS.WINDOWS) + void readNBytesOverride() throws InterruptedException, IOException { + Thread t = createWriteThread(); + try (InputStream in = new FileInputStream(PIPE)) { + final int length = 17; + assert length <= SENTENCE.length(); + byte[] b = in.readNBytes(length); + String s = new String(b); + System.out.println(s); + assertEquals(SENTENCE.substring(0, length), s); + } finally { + t.join(); + } + } +} diff --git a/test/jdk/java/io/FileInputStream/ReadXBytes.java b/test/jdk/java/io/FileInputStream/ReadXBytes.java index 3b0fe7d0590de..9a38205cb13e1 100644 --- a/test/jdk/java/io/FileInputStream/ReadXBytes.java +++ b/test/jdk/java/io/FileInputStream/ReadXBytes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ public class ReadXBytes { private static final Random RND = RandomFactory.getRandom(); public static void main(String args[]) throws IOException { - File dir = new File(System.getProperty("test.src", ".")); + File dir = new File("."); dir.deleteOnExit(); File empty = File.createTempFile("foo", "bar", dir); diff --git a/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java b/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java index 115481243f77d..4004cbcf859e9 100644 --- a/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java +++ b/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java @@ -49,12 +49,12 @@ */ /* - * @test id=ZGenerational - * @requires vm.gc.ZGenerational + * @test id=Z + * @requires vm.gc.Z * @bug 8277072 8327180 * @library /test/lib/ * @summary ObjectStreamClass caches keep ClassLoaders alive (ZGC) - * @run testng/othervm -Xmx64m -XX:+UseZGC -XX:+ZGenerational ObjectStreamClassCaching + * @run testng/othervm -Xmx64m -XX:+UseZGC ObjectStreamClassCaching */ /* diff --git a/test/jdk/java/io/Reader/Of.java b/test/jdk/java/io/Reader/Of.java new file mode 100644 index 0000000000000..491c0499e6b1d --- /dev/null +++ b/test/jdk/java/io/Reader/Of.java @@ -0,0 +1,217 @@ +/* + * 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.Reader; +import java.io.StringReader; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.ReadOnlyBufferException; + +import org.testng.annotations.*; + +import static org.testng.Assert.*; + +/* + * @test + * @bug 8341566 + * @summary Check for expected behavior of Reader.of(). + * @run testng Of + */ +public class Of { + final static String CONTENT = "Some Reader Test"; + + /* + * Readers to be tested. + */ + @DataProvider + public static Reader[] readers() { + return new Reader[] { + new StringReader(CONTENT), + Reader.of(CONTENT), + Reader.of(new StringBuffer(CONTENT)), + Reader.of(new StringBuilder(CONTENT)), + Reader.of(ByteBuffer.allocateDirect(CONTENT.length() * 2) + .asCharBuffer().put(CONTENT).flip()), + Reader.of(CharBuffer.wrap(CONTENT.toCharArray())), + Reader.of(new CharSequence() { + @Override + public char charAt(int index) { + return CONTENT.charAt(index); + } + + @Override + public int length() { + return CONTENT.length(); + } + + @Override + public CharSequence subSequence(int start, int end) { + // unused by Reader.Of's result + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + // Reader.Of's result SHALL NOT convert to String + throw new UnsupportedOperationException(); + } + }) + }; + } + + @Test(dataProvider = "readers") + public void testRead(Reader reader) throws IOException { + String s = ""; + for (int c; (c = reader.read()) != -1; s += (char) c); + assertEquals(s, CONTENT, "read() returned wrong value"); + } + + @Test(dataProvider = "readers") + public void testReadBII(Reader reader) throws IOException { + char[] c = new char[16]; + assertEquals(reader.read(c, 8, 8), 8, + "read(char[],int,int) does not respect given start or end"); + assertEquals(reader.read(c, 0, 16), 8, + "read(char[],int,int) does not respect end of stream"); + assertEquals(new String(c), + CONTENT.substring(8, 16) + CONTENT.substring(0, 8), + "read(char[],int,int) provides wrong content"); + } + + @Test(dataProvider = "readers") + public void testReadBIILenZero(Reader reader) throws IOException { + assertEquals(reader.read(new char[1], 0, 0), 0, + "read(char[],int,int) != 0"); + } + + @Test(dataProvider = "readers") + public void testReadDirectCharBuffer(Reader reader) throws IOException { + CharBuffer charBuffer = ByteBuffer.allocateDirect(32).asCharBuffer(); + charBuffer.position(8); + assertEquals(reader.read(charBuffer), 8, + "read(CharBuffer) does not respect position or limit"); + charBuffer.rewind(); + assertEquals(reader.read(charBuffer), 8, + "read(CharBuffer) does not respect end of stream"); + charBuffer.rewind(); + assertEquals(charBuffer.toString(), + // last part first proofs that copy loops correctly stopped + CONTENT.substring(8, 16) + CONTENT.substring(0, 8), + "read(CharBuffer) provides wrong content"); + } + + @Test(dataProvider = "readers") + public void testReadNonDirectCharBuffer(Reader reader) throws IOException { + CharBuffer charBuffer = CharBuffer.allocate(16); + charBuffer.position(8); + assertEquals(reader.read(charBuffer), 8, + "read(CharBuffer) does not respect position or limit"); + charBuffer.rewind(); + assertEquals(reader.read(charBuffer), 8, + "read(CharBuffer) does not respect end of stream"); + charBuffer.rewind(); + assertEquals(charBuffer.toString(), + CONTENT.substring(8, 16) + CONTENT.substring(0, 8), + "read(CharBuffer) provides wrong content"); + } + + @Test(dataProvider = "readers") + public void testReadCharBufferZeroRemaining(Reader reader) throws IOException { + CharBuffer charBuffer = CharBuffer.allocate(0); + assertEquals(reader.read(charBuffer), 0, "read(CharBuffer) != 0"); + } + + @Test(dataProvider = "readers") + public void testReady(Reader reader) throws IOException { + assertTrue(reader.ready()); + } + + @Test(dataProvider = "readers") + public void testSkip(Reader reader) throws IOException { + assertEquals(reader.skip(8), 8, "skip() does not respect limit"); + assertEquals(reader.skip(9), 8, "skip() does not respect end of stream"); + assertEquals(reader.skip(1), 0, "skip() does not respect empty stream"); + } + + @Test(dataProvider = "readers") + public void testTransferTo(Reader reader) throws IOException { + StringWriter sw = new StringWriter(16); + assertEquals(reader.transferTo(sw), 16, "transferTo() != 16"); + assertEquals(reader.transferTo(sw), 0, + "transferTo() does not respect empty stream"); + assertEquals(sw.toString(), CONTENT, + "transferTo() provides wrong content"); + } + + @Test(dataProvider = "readers") + public void testReadClosed(Reader reader) throws IOException { + reader.close(); + assertThrows(IOException.class, () -> {reader.read();}); + } + + @Test(dataProvider = "readers") + public void testReadBIIClosed(Reader reader) throws IOException { + reader.close(); + assertThrows(IOException.class, () -> reader.read(new char[1], 0, 1)); + } + + @Test(dataProvider = "readers") + public void testReadCharBufferClosed(Reader reader) throws IOException { + CharBuffer charBuffer = CharBuffer.allocate(1); + reader.close(); + assertThrows(IOException.class, () -> reader.read(charBuffer)); + } + + @Test(dataProvider = "readers") + public void testReadCharBufferZeroRemainingClosed(Reader reader) throws IOException { + CharBuffer charBuffer = CharBuffer.allocate(0); + reader.close(); + assertThrows(IOException.class, () -> reader.read(charBuffer)); + } + + @Test(dataProvider = "readers") + public void testReadyClosed(Reader reader) throws IOException { + reader.close(); + assertThrows(IOException.class, () -> reader.ready()); + } + + @Test(dataProvider = "readers") + public void testSkipClosed(Reader reader) throws IOException { + reader.close(); + assertThrows(IOException.class, () -> reader.skip(1)); + } + + @Test(dataProvider = "readers") + public void testTransferToClosed(Reader reader) throws IOException { + reader.close(); + assertThrows(IOException.class, () -> reader.transferTo(new StringWriter(1))); + } + + @Test(dataProvider = "readers") + public void testCloseClosed(Reader reader) throws IOException { + reader.close(); + reader.close(); + } +} diff --git a/test/jdk/java/lang/ProcessBuilder/CloseRace.java b/test/jdk/java/lang/ProcessBuilder/CloseRace.java index e7eab128d60cf..b0ca352b8acf6 100644 --- a/test/jdk/java/lang/ProcessBuilder/CloseRace.java +++ b/test/jdk/java/lang/ProcessBuilder/CloseRace.java @@ -22,24 +22,24 @@ */ /** - * @test + * @test id=Default * @bug 8024521 8315721 * @summary Closing ProcessPipeInputStream at the time the process exits is racy * and leads to data corruption. Run this test manually (as * an ordinary java program) with -Xmx8M to repro bug 8024521. - * @requires !vm.opt.final.ZGenerational + * @requires vm.gc != "Z" * @comment Don't allow -Xcomp, it disturbs the timing * @requires (vm.compMode != "Xcomp") * @run main/othervm -Xmx8M -Dtest.duration=2 CloseRace */ /** - * @test + * @test id=Z * @comment Turn up heap size to lower amount of GCs - * @requires vm.gc.Z & vm.opt.final.ZGenerational + * @requires vm.gc.Z * @comment Don't allow -Xcomp, it disturbs the timing * @requires (vm.compMode != "Xcomp") - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xmx32M -Dtest.duration=2 CloseRace + * @run main/othervm -XX:+UseZGC -Xmx32M -Dtest.duration=2 CloseRace */ import java.io.*; diff --git a/test/jdk/java/lang/Thread/virtual/ParkWithFixedThreadPool.java b/test/jdk/java/lang/Thread/virtual/ParkWithFixedThreadPool.java index 28a32fc504ab4..70b73884d9295 100644 --- a/test/jdk/java/lang/Thread/virtual/ParkWithFixedThreadPool.java +++ b/test/jdk/java/lang/Thread/virtual/ParkWithFixedThreadPool.java @@ -30,14 +30,16 @@ * @run main ParkWithFixedThreadPool */ -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.locks.LockSupport; import jdk.test.lib.thread.VThreadScheduler; public class ParkWithFixedThreadPool { public static void main(String[] args) throws Exception { - try (ExecutorService scheduler = Executors.newFixedThreadPool(8)) { + try (var scheduler = new Scheduler(8)) { int vthreadCount = 300; Thread[] vthreads = new Thread[vthreadCount]; Runnable target = new Runnable() { @@ -74,4 +76,27 @@ public void run() { } } } + + static class Scheduler implements Executor, AutoCloseable { + private final ExecutorService pool; + + Scheduler(int poolSize) { + pool = Executors.newFixedThreadPool(poolSize); + } + + @Override + public void execute(Runnable task) { + try { + pool.execute(task); + } finally { + // ExecutorService::execute may consume parking permit + LockSupport.unpark(Thread.currentThread()); + } + } + + @Override + public void close() { + pool.close(); + } + } } diff --git a/test/jdk/java/lang/Thread/virtual/stress/Skynet.java b/test/jdk/java/lang/Thread/virtual/stress/Skynet.java index 5b63fe84b1d89..562a8dbd5e1bf 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/Skynet.java +++ b/test/jdk/java/lang/Thread/virtual/stress/Skynet.java @@ -28,22 +28,12 @@ * @requires !vm.debug | vm.gc != "Z" * @run main/othervm/timeout=300 -Xmx1500m Skynet */ - -/* - * @test id=ZSinglegen - * @requires vm.debug == true & vm.continuations - * @requires vm.gc.ZSinglegen - * @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions - * -XX:+UseZGC -XX:-ZGenerational - * -XX:+ZVerifyOops -XX:ZCollectionInterval=0.01 -Xmx1500m Skynet - */ - /* - * @test id=ZGenerational + * @test id=Z * @requires vm.debug == true & vm.continuations - * @requires vm.gc.ZGenerational + * @requires vm.gc.Z * @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions - * -XX:+UseZGC -XX:+ZGenerational + * -XX:+UseZGC * -XX:+ZVerifyOops -XX:ZCollectionInterval=0.01 -Xmx1500m Skynet */ diff --git a/test/jdk/java/lang/constant/ClassDescTest.java b/test/jdk/java/lang/constant/ClassDescTest.java index 4d98e1283f0f1..839de27b1780a 100644 --- a/test/jdk/java/lang/constant/ClassDescTest.java +++ b/test/jdk/java/lang/constant/ClassDescTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,9 +40,9 @@ import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -/** +/* * @test - * @bug 8215510 8283075 + * @bug 8215510 8283075 8338544 * @compile ClassDescTest.java * @run testng ClassDescTest * @summary unit tests for java.lang.constant.ClassDesc @@ -68,7 +68,30 @@ private void testClassDesc(ClassDesc r) throws ReflectiveOperationException { assertEquals(r, r.componentType().arrayType()); assertEquals(r, r.resolveConstantDesc(LOOKUP).getComponentType().describeConstable().orElseThrow().arrayType()); assertEquals(r, Array.newInstance(r.componentType().resolveConstantDesc(LOOKUP), 0).getClass().describeConstable().orElseThrow()); + } else { + assertNull(r.componentType()); + } + + if (!r.isClassOrInterface()) { + assertEquals(r.packageName(), ""); + } + } + + private static String classDisplayName(Class c) { + int arrayLevel = 0; + while (c.isArray()) { + arrayLevel++; + c = c.componentType(); + } + String name = c.getName(); + String simpleClassName; + if (c.isPrimitive()) { + simpleClassName = name; + } else { + int lastDot = name.lastIndexOf('.'); + simpleClassName = lastDot == -1 ? name : name.substring(lastDot + 1); } + return simpleClassName + "[]".repeat(arrayLevel); } private void testClassDesc(ClassDesc r, Class c) throws ReflectiveOperationException { @@ -77,6 +100,13 @@ private void testClassDesc(ClassDesc r, Class c) throws ReflectiveOperationEx assertEquals(r.resolveConstantDesc(LOOKUP), c); assertEquals(c.describeConstable().orElseThrow(), r); assertEquals(ClassDesc.ofDescriptor(c.descriptorString()), r); + if (r.isArray()) { + testClassDesc(r.componentType(), c.componentType()); + } + if (r.isClassOrInterface()) { + assertEquals(r.packageName(), c.getPackageName()); + } + assertEquals(r.displayName(), classDisplayName(c)); } public void testSymbolicDescsConstants() throws ReflectiveOperationException { @@ -143,7 +173,8 @@ public void testSimpleClassDesc() throws ReflectiveOperationException { assertFalse(r.isPrimitive()); assertEquals("Ljava/lang/String;", r.descriptorString()); assertEquals("String", r.displayName()); - assertEquals(r.arrayType().resolveConstantDesc(LOOKUP), String[].class); + testClassDesc(r.arrayType(), String[].class); + testClassDesc(r.arrayType(3), String[][][].class); stringClassDescs.forEach(rr -> assertEquals(r, rr)); } diff --git a/test/jdk/java/lang/invoke/BigArityTest.java b/test/jdk/java/lang/invoke/BigArityTest.java index 338903f31630d..2dba056a183ab 100644 --- a/test/jdk/java/lang/invoke/BigArityTest.java +++ b/test/jdk/java/lang/invoke/BigArityTest.java @@ -24,7 +24,7 @@ /* @test * @summary High arity invocations * @compile BigArityTest.java - * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -esa -DBigArityTest.ITERATION_COUNT=1 test.java.lang.invoke.BigArityTest + * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -XX:CompileCommand=memlimit,*.*,0 -esa -DBigArityTest.ITERATION_COUNT=1 test.java.lang.invoke.BigArityTest */ package test.java.lang.invoke; diff --git a/test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java b/test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java index 68a6671e77a03..f8abba4398399 100644 --- a/test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java +++ b/test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java @@ -34,27 +34,15 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @bug 4530538 * @summary Basic unit test of MemoryMXBean.getMemoryPools() and * MemoryMXBean.getMemoryManager(). - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @author Mandy Chung * * @modules jdk.management - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational MemoryTest 2 1 - */ - -/* - * @test id=ZGenerational - * @bug 4530538 - * @summary Basic unit test of MemoryMXBean.getMemoryPools() and - * MemoryMXBean.getMemoryManager(). - * @requires vm.gc.ZGenerational - * @author Mandy Chung - * - * @modules jdk.management - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational MemoryTest 4 2 + * @run main/othervm -XX:+UseZGC MemoryTest 4 2 */ /* diff --git a/test/jdk/java/lang/management/MemoryMXBean/MemoryUtil.java b/test/jdk/java/lang/management/MemoryMXBean/MemoryUtil.java index 55605c6c1c445..5fae7468b79df 100644 --- a/test/jdk/java/lang/management/MemoryMXBean/MemoryUtil.java +++ b/test/jdk/java/lang/management/MemoryMXBean/MemoryUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 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 @@ -56,6 +56,8 @@ public static void printMemoryPool(MemoryPoolMXBean pool) { (pool.isUsageThresholdSupported() ? pool.getUsageThreshold() : -1)); System.out.println(INDENT + "ThresholdCount: " + (pool.isUsageThresholdSupported() ? pool.getUsageThresholdCount() : -1)); + System.out.println(INDENT + "CollectionThresholdCount: " + + (pool.isCollectionUsageThresholdSupported() ? pool.getCollectionUsageThresholdCount() : -1)); System.out.print(INDENT + "Manager = ["); String[] mgrs = pool.getMemoryManagerNames(); for (int i = 0; i < mgrs.length; i++) { diff --git a/test/jdk/java/lang/management/MemoryMXBean/RunUtil.java b/test/jdk/java/lang/management/MemoryMXBean/RunUtil.java index e94bc6c3c2c78..314aab44c4b9b 100644 --- a/test/jdk/java/lang/management/MemoryMXBean/RunUtil.java +++ b/test/jdk/java/lang/management/MemoryMXBean/RunUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, 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 @@ -73,6 +73,7 @@ private static void runTest(String main, boolean clearGcOpts, String... testOpts } opts.addAll(Arrays.asList(testOpts)); opts.add(main); + opts.add("trace"); OutputAnalyzer output = ProcessTools.executeProcess(opts.toArray(new String[0])); output.shouldHaveExitValue(0); diff --git a/test/jdk/java/net/Socket/SocketImplTest.java b/test/jdk/java/net/Socket/SocketImplTest.java deleted file mode 100644 index 28f49b2618363..0000000000000 --- a/test/jdk/java/net/Socket/SocketImplTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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.applet.Applet; -import java.io.*; -import java.net.*; - -/** - * Simple Applet for exposing the Socket constructor - * bug. - */ -public class SocketImplTest extends Applet { - - static public void main(String[] args) { - System.setSecurityManager(new SecurityManager()); - SocketImplTest s = new SocketImplTest(); - s.init(); - s.start(); - } - - - /** - * A no-op SocketImpl descendant. - */ - class MySocketImpl extends SocketImpl { - protected void accept(SocketImpl impl) throws IOException { - } - - protected int available(){ - return 0; - } - - protected void bind(InetAddress host, int port){ - } - - protected void close(){ - } - - protected void connect(InetAddress address, int port){ - } - - protected void connect(String host, int port){ - } - - protected void connect(SocketAddress a, int t) throws IOException { - } - - - protected void create(boolean stream){ - } - - protected InputStream getInputStream(){ - return null; - } - - protected OutputStream getOutputStream(){ - return null; - } - - protected void listen(int backlog){ - } - - public Object getOption(int optID){ - return null; - } - - public void setOption(int optID, Object value){ - } - - protected void sendUrgentData(int i){ - } - } - - class MyDatagramSocketImpl extends DatagramSocketImpl { - protected void create() throws SocketException { - } - - protected void bind(int lport, InetAddress laddr) throws SocketException { - } - - protected void send(DatagramPacket p) throws IOException { - } - - protected int peek(InetAddress i) throws IOException { - return 0; - } - - protected int peekData(DatagramPacket p) throws IOException { - return 0; - } - - protected void receive(DatagramPacket p) throws IOException { - } - - protected void setTTL(byte ttl) throws IOException { - } - - protected byte getTTL() throws IOException { - return 0; - } - - protected void setTimeToLive(int ttl) throws IOException { - } - - protected int getTimeToLive() throws IOException { - return 0; - } - - protected void join(InetAddress inetaddr) throws IOException { - } - - protected void leave(InetAddress inetaddr) throws IOException { - } - - protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) - throws IOException { - } - - protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) - throws IOException { - } - - protected void close() { - } - - public Object getOption(int optID){ - return null; - } - - public void setOption(int optID, Object value){ - } - - } - - /** - * A no-op Socket descendant. - */ - class MySocket extends Socket { - public MySocket(SocketImpl impl) throws IOException { - super(impl); - } - } - - class MyDatagramSocket extends DatagramSocket { - public MyDatagramSocket(DatagramSocketImpl impl) { - super(impl); - } - } - - /** - * Our test case entrypoint. Generates - * a SecurityException. - */ - public void init(){ - MySocketImpl socketImpl = new MySocketImpl(); - MyDatagramSocketImpl dgramSocketImpl = new MyDatagramSocketImpl(); - - try{ - MySocket socko = new MySocket(socketImpl); - MyDatagramSocket dsock = new MyDatagramSocket(dgramSocketImpl); - } catch(IOException ioex){ - System.err.println(ioex); - } catch(SecurityException sec) { - throw new RuntimeException("Failed. Creation of socket throwing SecurityException: "); - } - } -} diff --git a/test/jdk/java/net/Socket/UdpSocket.java b/test/jdk/java/net/Socket/UdpSocket.java index a15f9255b450a..5d13c1f916a60 100644 --- a/test/jdk/java/net/Socket/UdpSocket.java +++ b/test/jdk/java/net/Socket/UdpSocket.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 @@ -47,6 +47,8 @@ @Test public class UdpSocket { + private static final int MAX_RETRIES = 3; + /** * Test using the Socket API to send/receive datagrams */ @@ -133,16 +135,21 @@ public void testMaxSockets() throws Exception { } - private Socket newUdpSocket() throws IOException { - Socket s = null; - - try { - s = new Socket(InetAddress.getLoopbackAddress(), 8000, false); - } catch (BindException unexpected) { - System.out.println("BindException caught retry Socket creation"); - s = new Socket(InetAddress.getLoopbackAddress(), 8000, false); + private Socket newUdpSocket() throws IOException, InterruptedException { + BindException unexpected = null; + for (int i=0; i < MAX_RETRIES; i++) { + try { + return new Socket(InetAddress.getLoopbackAddress(), 8000, false); + } catch (BindException be) { + unexpected = be; + if (i != MAX_RETRIES - 1) { + System.out.printf("BindException caught: retry Socket creation [%s/%s]%n", + i + 1, MAX_RETRIES); + Thread.sleep(10 + 10 * i); + } + } } - return s; + throw unexpected; } private void closeAll(Deque sockets) throws IOException { diff --git a/test/jdk/java/net/httpclient/AuthFilter.java b/test/jdk/java/net/httpclient/AuthFilter.java deleted file mode 100644 index 28474bfd8303a..0000000000000 --- a/test/jdk/java/net/httpclient/AuthFilter.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 com.sun.net.httpserver.Headers; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; - -import java.io.*; -import java.net.Authenticator; -import java.net.InetSocketAddress; -import java.net.ProxySelector; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.channels.*; -import java.nio.charset.StandardCharsets; - -import jdk.test.lib.net.IPSupport; - -/** - * @test - * @bug 8263442 - * @summary Potential bug in jdk.internal.net.http.common.Utils.CONTEXT_RESTRICTED - * @library /test/lib - * @run main/othervm AuthFilter - */ - -public class AuthFilter { - static class Auth extends Authenticator { - } - - static HttpServer createServer() throws IOException { - HttpServer server = HttpServer.create(new InetSocketAddress(0), 5); - HttpHandler handler = (HttpExchange e) -> { - InputStream is = e.getRequestBody(); - is.readAllBytes(); - is.close(); - Headers reqh = e.getRequestHeaders(); - if (reqh.containsKey("authorization")) { - e.sendResponseHeaders(500, -1); - } else { - e.sendResponseHeaders(200, -1); - } - }; - server.createContext("/", handler); - return server; - } - - public static void main(String[] args) throws Exception { - test(false); - test(true); - } - - /** - * Fake proxy. Just looks for Proxy-Authorization header - * and returns error if seen. Returns 200 OK if not. - * Does not actually forward the request - */ - static class ProxyServer extends Thread { - - final ServerSocketChannel server; - final int port; - volatile SocketChannel c; - - ProxyServer() throws IOException { - server = ServerSocketChannel.open(); - server.bind(new InetSocketAddress(0)); - if (server.getLocalAddress() instanceof InetSocketAddress isa) { - port = isa.getPort(); - } else { - port = -1; - } - } - - int getPort() { - return port; - } - - static String ok = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"; - static String notok1 = "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n"; - static String notok2 = "HTTP/1.1 501 Not Implemented\r\nContent-Length: 0\r\n\r\n"; - - static void reply(String msg, Writer writer) throws IOException { - writer.write(msg); - writer.flush(); - } - - public void run() { - try { - c = server.accept(); - var cs = StandardCharsets.US_ASCII; - LineNumberReader reader = new LineNumberReader(Channels.newReader(c, cs)); - Writer writer = Channels.newWriter(c, cs); - - String line; - while ((line=reader.readLine()) != null) { - if (line.indexOf("Proxy-Authorization") != -1) { - reply(notok1, writer); - return; - } - if (line.equals("")) { - // end of headers - reply(ok, writer); - return; - } - } - reply(notok2, writer); - } catch (IOException e) { - } - try { - server.close(); - c.close(); - } catch (IOException ee) {} - } - } - - private static InetSocketAddress getLoopback(int port) throws IOException { - if (IPSupport.hasIPv4()) { - return new InetSocketAddress("127.0.0.1", port); - } else { - return new InetSocketAddress("::1", port); - } - } - - public static void test(boolean useProxy) throws Exception { - HttpServer server = createServer(); - int port = server.getAddress().getPort(); - ProxyServer proxy; - - InetSocketAddress proxyAddr; - String authHdr; - if (useProxy) { - proxy = new ProxyServer(); - proxyAddr = getLoopback(proxy.getPort()); - proxy.start(); - authHdr = "Proxy-Authorization"; - } else { - authHdr = "Authorization"; - proxyAddr = null; - } - - server.start(); - - // proxyAddr == null => proxying disabled - HttpClient client = HttpClient - .newBuilder() - .authenticator(new Auth()) - .proxy(ProxySelector.of(proxyAddr)) - .build(); - - - URI uri = new URI("http://127.0.0.1:" + Integer.toString(port)); - - HttpRequest request = HttpRequest.newBuilder(uri) - .header(authHdr, "nonsense") - .GET() - .build(); - - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - int r = response.statusCode(); - System.out.println(r); - server.stop(0); - if (r != 200) - throw new RuntimeException("Test failed : " + r); - } -} diff --git a/test/jdk/java/net/httpclient/ExpectContinueTest.java b/test/jdk/java/net/httpclient/ExpectContinueTest.java index 3d28ae8c8b49c..50e43099255ac 100644 --- a/test/jdk/java/net/httpclient/ExpectContinueTest.java +++ b/test/jdk/java/net/httpclient/ExpectContinueTest.java @@ -59,6 +59,7 @@ import java.io.Writer; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.ProtocolException; import java.net.ServerSocket; import java.net.Socket; import java.net.URI; @@ -361,7 +362,7 @@ private void verifyRequest(String path, int expectedStatusCode, HttpResponse resp = client.send(req, HttpResponse.BodyHandlers.ofString()); + if (!useHeader) { + assertTrue(resp.statusCode() == 200, "Expected 200 response"); + assertTrue(!h.authValue().equals(encoded), "Expected user set header to not be set"); + assertTrue(h.authValue().equals(sa.authValue()), "Expected auth value from Authenticator"); + assertTrue(sa.wasCalled(), "Expected authenticator to be called"); + System.out.println("h2Test: using authenticator OK"); + } else if (rightPassword) { + assertTrue(resp.statusCode() == 200, "Expected 200 response"); + assertTrue(h.authValue().equals(encoded), "Expected user set header to be set"); + assertTrue(!sa.wasCalled(), "Expected authenticator not to be called"); + System.out.println("h2Test: using user set header OK"); + } else { + assertTrue(resp.statusCode() == 401, "Expected 401 response"); + assertTrue(!sa.wasCalled(), "Expected authenticator not to be called"); + System.out.println("h2Test: using user set header with wrong password OK"); + } + } finally { + if (h2s != null) + h2s.stop(); + if (client != null) + client.close(); + if (ex != null) + ex.shutdown(); + } + } + + static final String data = "0123456789"; + + static final String data1 = "ABCDEFGHIJKL"; + + static final String[] proxyResponses = { + "HTTP/1.1 407 Proxy Authentication Required\r\n"+ + "Content-Length: 0\r\n" + + "Proxy-Authenticate: Basic realm=\"Access to the proxy\"\r\n\r\n" + , + "HTTP/1.1 200 OK\r\n"+ + "Date: Mon, 15 Jan 2001 12:18:21 GMT\r\n" + + "Server: Apache/1.3.14 (Unix)\r\n" + + "Content-Length: " + data.length() + "\r\n\r\n" + data + }; + + static final String[] proxyWithErrorResponses = { + "HTTP/1.1 407 Proxy Authentication Required\r\n"+ + "Content-Length: 0\r\n" + + "Proxy-Authenticate: Basic realm=\"Access to the proxy\"\r\n\r\n" + , + "HTTP/1.1 407 Proxy Authentication Required\r\n"+ + "Content-Length: 0\r\n" + + "Proxy-Authenticate: Basic realm=\"Access to the proxy\"\r\n\r\n" + }; + + static final String[] serverResponses = { + "HTTP/1.1 200 OK\r\n"+ + "Date: Mon, 15 Jan 2001 12:18:21 GMT\r\n" + + "Server: Apache/1.3.14 (Unix)\r\n" + + "Content-Length: " + data1.length() + "\r\n\r\n" + data1 + }; + + static final String[] authenticatorResponses = { + "HTTP/1.1 401 Authentication Required\r\n"+ + "Content-Length: 0\r\n" + + "WWW-Authenticate: Basic realm=\"Access to the server\"\r\n\r\n" + , + "HTTP/1.1 200 OK\r\n"+ + "Date: Mon, 15 Jan 2001 12:18:21 GMT\r\n" + + "Server: Apache/1.3.14 (Unix)\r\n" + + "Content-Length: " + data1.length() + "\r\n\r\n" + data1 + }; + + public static void main(String[] args) throws Exception { + testServerOnly(); + testServerWithProxy(); + testServerWithProxyError(); + testServerOnlyAuthenticator(); + h2Test(true, true); + h2Test(false, true); + h2Test(true, false); + } + + static void testServerWithProxy() throws IOException, InterruptedException { + Mocker proxyMock = new Mocker(proxyResponses); + proxyMock.start(); + ProxyAuth p = new ProxyAuth(); + try (var client = HttpClient.newBuilder() + .version(java.net.http.HttpClient.Version.HTTP_1_1) + .proxy(new ProxySel(proxyMock.getPort())) + .authenticator(p) + .build()) { + + var plainCreds = "user:pwd"; + var encoded = java.util.Base64.getEncoder().encodeToString(plainCreds.getBytes(US_ASCII)); + var request = HttpRequest.newBuilder().uri(URI.create("http://127.0.0.1/some_url")) + .setHeader("User-Agent", "myUserAgent") + .setHeader("Authorization", AUTH_PREFIX + encoded) + .build(); + + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + assertEquals(200, response.statusCode()); + assertTrue(p.wasCalled(), "Proxy authenticator was not called"); + assertEquals(data, response.body()); + var proxyStr = proxyMock.getRequest(1); + + assertContains(proxyStr, "/some_url"); + assertPattern(".*^Proxy-Authorization:.*Basic " + encoded + ".*", proxyStr); + assertPattern(".*^User-Agent:.*myUserAgent.*", proxyStr); + assertPattern(".*^Authorization:.*Basic.*", proxyStr); + System.out.println("testServerWithProxy: OK"); + } finally { + proxyMock.stopMocker(); + } + } + + static void testServerWithProxyError() throws IOException, InterruptedException { + Mocker proxyMock = new Mocker(proxyWithErrorResponses); + proxyMock.start(); + ProxyAuth p = new ProxyAuth(); + try (var client = HttpClient.newBuilder() + .version(java.net.http.HttpClient.Version.HTTP_1_1) + .proxy(new ProxySel(proxyMock.getPort())) + .authenticator(p) + .build()) { + + var badCreds = "user:wrong"; + var encoded1 = java.util.Base64.getEncoder().encodeToString(badCreds.getBytes(US_ASCII)); + var request = HttpRequest.newBuilder().uri(URI.create("http://127.0.0.1/some_url")) + .setHeader("User-Agent", "myUserAgent") + .setHeader("Proxy-Authorization", AUTH_PREFIX + encoded1) + .build(); + + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + var proxyStr = proxyMock.getRequest(0); + assertEquals(407, response.statusCode()); + assertPattern(".*^Proxy-Authorization:.*Basic " + encoded1 + ".*", proxyStr); + assertTrue(!p.wasCalled(), "Proxy Auth should not have been called"); + System.out.println("testServerWithProxyError: OK"); + } finally { + proxyMock.stopMocker(); + } + } + + static void testServerOnly() throws IOException, InterruptedException { + Mocker serverMock = new Mocker(serverResponses); + serverMock.start(); + try (var client = HttpClient.newBuilder() + .version(java.net.http.HttpClient.Version.HTTP_1_1) + .build()) { + + var plainCreds = "user:pwd"; + var encoded = java.util.Base64.getEncoder().encodeToString(plainCreds.getBytes(US_ASCII)); + var request = HttpRequest.newBuilder().uri(URI.create(serverMock.baseURL() + "/some_serv_url")) + .setHeader("User-Agent", "myUserAgent") + .setHeader("Authorization", AUTH_PREFIX + encoded) + .build(); + + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + assertEquals(data1, response.body()); + + var serverStr = serverMock.getRequest(0); + assertContains(serverStr, "/some_serv_url"); + assertPattern(".*^User-Agent:.*myUserAgent.*", serverStr); + assertPattern(".*^Authorization:.*Basic " + encoded + ".*", serverStr); + System.out.println("testServerOnly: OK"); + } finally { + serverMock.stopMocker(); + } + } + + // This is effectively a regression test for existing behavior + static void testServerOnlyAuthenticator() throws IOException, InterruptedException { + Mocker serverMock = new Mocker(authenticatorResponses); + serverMock.start(); + try (var client = HttpClient.newBuilder() + .version(java.net.http.HttpClient.Version.HTTP_1_1) + .authenticator(new ServerAuth()) + .build()) { + + // credentials set in the server authenticator + var plainCreds = "serverUser:serverPwd"; + var encoded = java.util.Base64.getEncoder().encodeToString(plainCreds.getBytes(US_ASCII)); + var request = HttpRequest.newBuilder().uri(URI.create(serverMock.baseURL() + "/some_serv_url")) + .setHeader("User-Agent", "myUserAgent") + .build(); + + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + assertEquals(data1, response.body()); + + var serverStr = serverMock.getRequest(1); + assertContains(serverStr, "/some_serv_url"); + assertPattern(".*^User-Agent:.*myUserAgent.*", serverStr); + assertPattern(".*^Authorization:.*Basic " + encoded + ".*", serverStr); + System.out.println("testServerOnlyAuthenticator: OK"); + } finally { + serverMock.stopMocker(); + } + } + + static void close(Closeable... clarray) { + for (Closeable c : clarray) { + try { + c.close(); + } catch (Exception e) {} + } + } + + static class Mocker extends Thread { + final ServerSocket ss; + final String[] responses; + volatile List requests; + volatile InputStream in; + volatile OutputStream out; + volatile Socket s = null; + + public Mocker(String[] responses) throws IOException { + this.ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); + this.responses = responses; + this.requests = new LinkedList<>(); + } + + public void stopMocker() { + close(ss, s, in, out); + } + + public int getPort() { + return ss.getLocalPort(); + } + + public String baseURL() { + try { + return URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(getPort()) + .build() + .toString(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + private String readRequest() throws IOException { + String req = ""; + while (!req.endsWith("\r\n\r\n")) { + int x = in.read(); + if (x == -1) { + s.close(); + s = ss.accept(); + in = s.getInputStream(); + out = s.getOutputStream(); + } + req += (char)x; + } + return req; + } + + public String getRequest(int i) { + return requests.get(i); + } + + public void run() { + try { + int index=0; + s = ss.accept(); + in = s.getInputStream(); + out = s.getOutputStream(); + while (index < responses.length) { + requests.add(readRequest()); + out.write(responses[index++].getBytes(US_ASCII)); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + static class ProxySel extends ProxySelector { + final int port; + + ProxySel(int port) { + this.port = port; + } + @Override + public List select(URI uri) { + return List.of(new Proxy(Proxy.Type.HTTP, new InetSocketAddress( + InetAddress.getLoopbackAddress(), port))); + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {} + + } + + static class ProxyAuth extends Authenticator { + private volatile boolean called = false; + + @Override + protected PasswordAuthentication getPasswordAuthentication() { + called = true; + return new PasswordAuthentication("proxyUser", "proxyPwd".toCharArray()); + } + + boolean wasCalled() { + return called; + } + } + + static class ServerAuth extends Authenticator { + private volatile boolean called = false; + + private static String USER = "serverUser"; + private static String PASS = "serverPwd"; + + @Override + protected PasswordAuthentication getPasswordAuthentication() { + called = true; + if (getRequestorType() != RequestorType.SERVER) { + // We only want to handle server authentication here + return null; + } + return new PasswordAuthentication(USER, PASS.toCharArray()); + } + + String authValue() { + var plainCreds = USER + ":" + PASS; + return java.util.Base64.getEncoder().encodeToString(plainCreds.getBytes(US_ASCII)); + } + + boolean wasCalled() { + return called; + } + } + + static void assertTrue(boolean assertion, String failMsg) { + if (!assertion) { + throw new RuntimeException(failMsg); + } + } + + static void assertEquals(int a, int b) { + if (a != b) { + String msg = String.format("Error: expected %d Got %d", a, b); + throw new RuntimeException(msg); + } + } + + static void assertEquals(String s1, String s2) { + if (!s1.equals(s2)) { + String msg = String.format("Error: expected %s Got %s", s1, s2); + throw new RuntimeException(msg); + } + } + + static void assertContains(String container, String containee) { + if (!container.contains(containee)) { + String msg = String.format("Error: expected %s Got %s", container, containee); + throw new RuntimeException(msg); + } + } + + static void assertPattern(String pattern, String candidate) { + Pattern pat = Pattern.compile(pattern, Pattern.DOTALL | Pattern.MULTILINE); + Matcher matcher = pat.matcher(candidate); + if (!matcher.matches()) { + String msg = String.format("Error: expected %s Got %s", pattern, candidate); + throw new RuntimeException(msg); + } + } +} diff --git a/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java b/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java new file mode 100644 index 0000000000000..6b0b3727ee25c --- /dev/null +++ b/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java @@ -0,0 +1,365 @@ +/* + * 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 8342075 + * @summary checks connection flow control + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext + * @run testng/othervm -Djdk.internal.httpclient.debug=true + * -Djdk.httpclient.connectionWindowSize=65535 + * -Djdk.httpclient.windowsize=16384 + * ConnectionFlowControlTest + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ProtocolException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandler; +import java.net.http.HttpResponse.BodyHandlers; +import java.net.http.HttpResponse.BodySubscriber; +import java.net.http.HttpResponse.ResponseInfo; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Flow.Subscription; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; + +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.httpclient.test.lib.http2.BodyOutputStream; +import jdk.httpclient.test.lib.http2.Http2Handler; +import jdk.httpclient.test.lib.http2.Http2TestExchange; +import jdk.httpclient.test.lib.http2.Http2TestExchangeImpl; +import jdk.httpclient.test.lib.http2.Http2TestServer; +import jdk.httpclient.test.lib.http2.Http2TestServerConnection; +import jdk.internal.net.http.common.HttpHeadersBuilder; +import jdk.internal.net.http.frame.ContinuationFrame; +import jdk.internal.net.http.frame.HeaderFrame; +import jdk.internal.net.http.frame.HeadersFrame; +import jdk.internal.net.http.frame.Http2Frame; +import jdk.internal.net.http.frame.SettingsFrame; +import jdk.test.lib.Utils; +import jdk.test.lib.net.SimpleSSLContext; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static java.util.List.of; +import static java.util.Map.entry; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +public class ConnectionFlowControlTest { + + SSLContext sslContext; + HttpTestServer http2TestServer; // HTTP/2 ( h2c ) + HttpTestServer https2TestServer; // HTTP/2 ( h2 ) + String http2URI; + String https2URI; + final AtomicInteger reqid = new AtomicInteger(); + + + @DataProvider(name = "variants") + public Object[][] variants() { + return new Object[][] { + { http2URI }, + { https2URI }, + }; + } + + @Test(dataProvider = "variants") + void test(String uri) throws Exception { + System.out.printf("%ntesting %s%n", uri); + ConcurrentHashMap> responseSent = new ConcurrentHashMap<>(); + ConcurrentHashMap> responses = new ConcurrentHashMap<>(); + FCHttp2TestExchange.setResponseSentCB((s) -> responseSent.get(s).complete(s)); + int connectionWindowSize = Math.max(Integer.getInteger( + "jdk.httpclient.connectionWindowSize", 65535), 65535); + int windowSize = Math.max(Integer.getInteger( + "jdk.httpclient.windowsize", 65535), 16384); + int max = connectionWindowSize / windowSize + 2; + System.out.printf("connection window: %s, stream window: %s, will make %s requests%n", + connectionWindowSize, windowSize, max); + + try (HttpClient client = HttpClient.newBuilder().sslContext(sslContext).build()) { + String label = null; + + Throwable t = null; + try { + String[] keys = new String[max]; + for (int i = 0; i < max; i++) { + String query = "reqId=" + reqid.incrementAndGet(); + keys[i] = query; + URI uriWithQuery = URI.create(uri + "?" + query); + CompletableFuture sent = new CompletableFuture<>(); + responseSent.put(query, sent); + HttpRequest request = HttpRequest.newBuilder(uriWithQuery) + .POST(BodyPublishers.ofString("Hello there!")) + .build(); + System.out.println("\nSending request:" + uriWithQuery); + final HttpClient cc = client; + var response = cc.send(request, BodyHandlers.ofInputStream()); + responses.put(query, response); + String ckey = response.headers().firstValue("X-Connection-Key").get(); + if (label == null) label = ckey; + try { + if (i < max - 1) { + // the connection window might be exceeded at i == max - 2, which + // means that the last request could go on a new connection. + assertEquals(ckey, label, "Unexpected key for " + query); + } + } catch (AssertionError ass) { + // since we won't pull all responses, the client + // will not exit unless we ask it to shutdown now. + client.shutdownNow(); + throw ass; + } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + // ignore + } + CompletableFuture allsent = CompletableFuture.allOf(responseSent.values().stream() + .toArray(CompletableFuture[]::new)); + allsent.get(); + for (int i = 0; i < max; i++) { + try { + String query = keys[i]; + var response = responses.get(keys[i]); + String ckey = response.headers().firstValue("X-Connection-Key").get(); + if (label == null) label = ckey; + assertEquals(ckey, label, "Unexpected key for " + query); + int wait = uri.startsWith("https://") ? 500 : 250; + try (InputStream is = response.body()) { + Thread.sleep(Utils.adjustTimeout(wait)); + is.readAllBytes(); + } + System.out.printf("%s did not fail: %s%n", query, response.statusCode()); + } catch (AssertionError t1) { + // since we won't pull all responses, the client + // will not exit unless we ask it to shutdown now. + client.shutdownNow(); + throw t1; + } catch (Throwable t0) { + System.out.println("Got EXPECTED: " + t0); + if (t0 instanceof ExecutionException) { + t0 = t0.getCause(); + } + t = t0; + try { + assertDetailMessage(t0, i); + } catch (AssertionError e) { + // since we won't pull all responses, the client + // will not exit unless we ask it to shutdown now. + client.shutdownNow(); + throw e; + } + } + } + } catch (Throwable t0) { + System.out.println("Got EXPECTED: " + t0); + if (t0 instanceof ExecutionException) { + t0 = t0.getCause(); + } + t = t0; + } + if (t == null) { + // we could fail here if we haven't waited long enough + fail("Expected exception, got all responses, should sleep time be raised?"); + } else { + assertDetailMessage(t, max); + } + String query = "reqId=" + reqid.incrementAndGet(); + URI uriWithQuery = URI.create(uri + "?" + query); + CompletableFuture sent = new CompletableFuture<>(); + responseSent.put(query, sent); + HttpRequest request = HttpRequest.newBuilder(uriWithQuery) + .POST(BodyPublishers.ofString("Hello there!")) + .build(); + System.out.println("\nSending last request:" + uriWithQuery); + var response = client.send(request, BodyHandlers.ofString()); + if (label != null) { + String ckey = response.headers().firstValue("X-Connection-Key").get(); + assertNotEquals(ckey, label); + System.out.printf("last request %s sent on different connection as expected:" + + "\n\tlast: %s\n\tprevious: %s%n", query, ckey, label); + } + } + } + + // Assertions based on implementation specific detail messages. Keep in + // sync with implementation. + static void assertDetailMessage(Throwable throwable, int iterationIndex) { + try { + Throwable cause = throwable; + while (cause != null) { + if (cause instanceof ProtocolException) { + if (cause.getMessage().contains("connection window exceeded")) { + System.out.println("Found expected exception: " + cause); + return; + } + } + cause = cause.getCause(); + } + throw new AssertionError( + "ProtocolException(\"protocol error: connection window exceeded\") not found", + throwable); + } catch (AssertionError e) { + System.out.println("Exception does not match expectation: " + throwable); + throwable.printStackTrace(System.out); + throw e; + } + } + + @BeforeTest + public void setup() throws Exception { + sslContext = new SimpleSSLContext().get(); + if (sslContext == null) + throw new AssertionError("Unexpected null sslContext"); + + var http2TestServer = new Http2TestServer("localhost", false, 0); + http2TestServer.addHandler(new Http2TestHandler(), "/http2/"); + this.http2TestServer = HttpTestServer.of(http2TestServer); + http2URI = "http://" + this.http2TestServer.serverAuthority() + "/http2/x"; + + var https2TestServer = new Http2TestServer("localhost", true, sslContext); + https2TestServer.addHandler(new Http2TestHandler(), "/https2/"); + this.https2TestServer = HttpTestServer.of(https2TestServer); + https2URI = "https://" + this.https2TestServer.serverAuthority() + "/https2/x"; + + // Override the default exchange supplier with a custom one to enable + // particular test scenarios + http2TestServer.setExchangeSupplier(FCHttp2TestExchange::new); + https2TestServer.setExchangeSupplier(FCHttp2TestExchange::new); + + this.http2TestServer.start(); + this.https2TestServer.start(); + } + + @AfterTest + public void teardown() throws Exception { + http2TestServer.stop(); + https2TestServer.stop(); + } + + static class Http2TestHandler implements Http2Handler { + + @Override + public void handle(Http2TestExchange t) throws IOException { + String query = t.getRequestURI().getRawQuery(); + + try (InputStream is = t.getRequestBody(); + OutputStream os = t.getResponseBody()) { + + byte[] bytes = is.readAllBytes(); + System.out.println("Server " + t.getLocalAddress() + " received:\n" + + t.getRequestURI() + ": " + new String(bytes, StandardCharsets.UTF_8)); + t.getResponseHeaders().setHeader("X-Connection-Key", t.getConnectionKey()); + + if (bytes.length == 0) bytes = "no request body!".getBytes(StandardCharsets.UTF_8); + int window = Math.max(16384, Integer.getInteger("jdk.httpclient.windowsize", 2*16*1024)); + final int maxChunkSize; + if (t instanceof FCHttp2TestExchange fct) { + maxChunkSize = Math.min(window, fct.conn.getMaxFrameSize()); + } else { + maxChunkSize = Math.min(window, SettingsFrame.MAX_FRAME_SIZE); + } + byte[] resp = bytes.length < maxChunkSize + ? bytes + : Arrays.copyOfRange(bytes, 0, maxChunkSize); + int max = (window / resp.length); + // send in chunks + t.sendResponseHeaders(200, 0); + int sent = 0; + for (int i=0; i<=max; i++) { + int len = Math.min(resp.length, window - sent); + if (len <= 0) break; + if (os instanceof BodyOutputStream bos) { + try { + // we don't wait for the stream window, but we want + // to wait for the connection window + bos.waitForStreamWindow(len); + } catch (InterruptedException ie) { + // ignore and continue... + } + } + ((BodyOutputStream) os).writeUncontrolled(resp, 0, len); + sent += len; + } + if (sent != window) fail("should have sent %s, sent %s".formatted(window, sent)); + } + if (t instanceof FCHttp2TestExchange fct) { + fct.responseSent(query); + } else { + fail("Exchange is not %s but %s" + .formatted(FCHttp2TestExchange.class.getName(), t.getClass().getName())); + } + } + } + + // A custom Http2TestExchangeImpl that overrides sendResponseHeaders to + // allow headers to be sent with a number of CONTINUATION frames. + static class FCHttp2TestExchange extends Http2TestExchangeImpl { + static volatile Consumer responseSentCB; + static void setResponseSentCB(Consumer responseSentCB) { + FCHttp2TestExchange.responseSentCB = responseSentCB; + } + + final Http2TestServerConnection conn; + FCHttp2TestExchange(int streamid, String method, HttpHeaders reqheaders, + HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is, + SSLSession sslSession, BodyOutputStream os, + Http2TestServerConnection conn, boolean pushAllowed) { + super(streamid, method, reqheaders, rspheadersBuilder, uri, is, sslSession, os, conn, pushAllowed); + this.conn = conn; + } + public void responseSent(String query) { + System.out.println("Server: response sent for " + query); + responseSentCB.accept(query); + } + + } +} diff --git a/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java b/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java index 6395cc839a2e8..c0021e7e4ea72 100644 --- a/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java +++ b/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java @@ -40,6 +40,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.ProtocolException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpHeaders; @@ -195,7 +196,8 @@ public void testSendHeadersOnPushPromiseStream() throws Exception { client.sendAsync(hreq, HttpResponse.BodyHandlers.ofString(UTF_8), pph); CompletionException t = expectThrows(CompletionException.class, () -> cf.join()); - assertEquals(t.getCause().getClass(), IOException.class, "Expected an IOException but got " + t.getCause()); + assertEquals(t.getCause().getClass(), ProtocolException.class, + "Expected a ProtocolException but got " + t.getCause()); System.err.println("Client received the following expected exception: " + t.getCause()); faultyServer.stop(); } @@ -222,7 +224,10 @@ private void verify(HttpResponse resp) { static class Http2PushPromiseHeadersExchangeImpl extends Http2TestExchangeImpl { - Http2PushPromiseHeadersExchangeImpl(int streamid, String method, HttpHeaders reqheaders, HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is, SSLSession sslSession, BodyOutputStream os, Http2TestServerConnection conn, boolean pushAllowed) { + Http2PushPromiseHeadersExchangeImpl(int streamid, String method, HttpHeaders reqheaders, + HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is, + SSLSession sslSession, BodyOutputStream os, + Http2TestServerConnection conn, boolean pushAllowed) { super(streamid, method, reqheaders, rspheadersBuilder, uri, is, sslSession, os, conn, pushAllowed); } diff --git a/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java b/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java new file mode 100644 index 0000000000000..36b727e3a22d3 --- /dev/null +++ b/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java @@ -0,0 +1,342 @@ +/* + * 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 8342075 + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext + * @run testng/othervm -Djdk.internal.httpclient.debug=true + * -Djdk.httpclient.connectionWindowSize=65535 + * -Djdk.httpclient.windowsize=16384 + * StreamFlowControlTest + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ProtocolException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; + +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.httpclient.test.lib.http2.BodyOutputStream; +import jdk.httpclient.test.lib.http2.Http2Handler; +import jdk.httpclient.test.lib.http2.Http2TestExchange; +import jdk.httpclient.test.lib.http2.Http2TestExchangeImpl; +import jdk.httpclient.test.lib.http2.Http2TestServer; +import jdk.httpclient.test.lib.http2.Http2TestServerConnection; +import jdk.internal.net.http.common.HttpHeadersBuilder; +import jdk.internal.net.http.frame.SettingsFrame; +import jdk.test.lib.Utils; +import jdk.test.lib.net.SimpleSSLContext; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +public class StreamFlowControlTest { + + SSLContext sslContext; + HttpTestServer http2TestServer; // HTTP/2 ( h2c ) + HttpTestServer https2TestServer; // HTTP/2 ( h2 ) + String http2URI; + String https2URI; + final AtomicInteger reqid = new AtomicInteger(); + + + @DataProvider(name = "variants") + public Object[][] variants() { + return new Object[][] { + { http2URI, false }, + { https2URI, false }, + { http2URI, true }, + { https2URI, true }, + }; + } + + + @Test(dataProvider = "variants") + void test(String uri, + boolean sameClient) + throws Exception + { + System.out.printf("%ntesting test(%s, %s)%n", uri, sameClient); + ConcurrentHashMap> responseSent = new ConcurrentHashMap<>(); + FCHttp2TestExchange.setResponseSentCB((s) -> responseSent.get(s).complete(s)); + + HttpClient client = null; + try { + int max = sameClient ? 10 : 3; + String label = null; + for (int i = 0; i < max; i++) { + if (!sameClient || client == null) + client = HttpClient.newBuilder().sslContext(sslContext).build(); + + String query = "reqId=" + reqid.incrementAndGet(); + URI uriWithQuery = URI.create(uri + "?" + query); + CompletableFuture sent = new CompletableFuture<>(); + responseSent.put(query, sent); + HttpRequest request = HttpRequest.newBuilder(uriWithQuery) + .POST(BodyPublishers.ofString("Hello there!")) + .build(); + System.out.println("\nSending request:" + uriWithQuery); + final HttpClient cc = client; + try { + HttpResponse response = cc.send(request, BodyHandlers.ofInputStream()); + if (sameClient) { + String key = response.headers().firstValue("X-Connection-Key").get(); + if (label == null) label = key; + assertEquals(key, label, "Unexpected key for " + query); + } + sent.join(); + // we have to pull to get the exception, but slow enough + // so that DataFrames are buffered up to the point that + // the window is exceeded... + int wait = uri.startsWith("https://") ? 500 : 350; + try (InputStream is = response.body()) { + Thread.sleep(Utils.adjustTimeout(wait)); + is.readAllBytes(); + } + // we could fail here if we haven't waited long enough + fail("Expected exception, got :" + response + ", should sleep time be raised?"); + } catch (IOException ioe) { + System.out.println("Got EXPECTED: " + ioe); + assertDetailMessage(ioe, i); + } finally { + if (!sameClient && client != null) { + client.close(); + client = null; + } + } + } + } finally { + if (sameClient && client != null) client.close(); + } + + } + + @Test(dataProvider = "variants") + void testAsync(String uri, + boolean sameClient) + { + System.out.printf("%ntesting testAsync(%s, %s)%n", uri, sameClient); + ConcurrentHashMap> responseSent = new ConcurrentHashMap<>(); + FCHttp2TestExchange.setResponseSentCB((s) -> responseSent.get(s).complete(s)); + + HttpClient client = null; + try { + int max = sameClient ? 5 : 3; + String label = null; + for (int i = 0; i < max; i++) { + if (!sameClient || client == null) + client = HttpClient.newBuilder().sslContext(sslContext).build(); + + String query = "reqId=" + reqid.incrementAndGet(); + URI uriWithQuery = URI.create(uri + "?" + query); + CompletableFuture sent = new CompletableFuture<>(); + responseSent.put(query, sent); + HttpRequest request = HttpRequest.newBuilder(uriWithQuery) + .POST(BodyPublishers.ofString("Hello there!")) + .build(); + System.out.println("\nSending request:" + uriWithQuery); + final HttpClient cc = client; + + Throwable t = null; + try { + HttpResponse response = cc.sendAsync(request, BodyHandlers.ofInputStream()).get(); + if (sameClient) { + String key = response.headers().firstValue("X-Connection-Key").get(); + if (label == null) label = key; + assertEquals(key, label, "Unexpected key for " + query); + } + sent.join(); + int wait = uri.startsWith("https://") ? 600 : 300; + try (InputStream is = response.body()) { + Thread.sleep(Utils.adjustTimeout(wait)); + is.readAllBytes(); + } + // we could fail here if we haven't waited long enough + fail("Expected exception, got :" + response + ", should sleep time be raised?"); + } catch (Throwable t0) { + System.out.println("Got EXPECTED: " + t0); + if (t0 instanceof ExecutionException) { + t0 = t0.getCause(); + } + t = t0; + } finally { + if (!sameClient && client != null) { + client.close(); + client = null; + } + } + assertDetailMessage(t, i); + } + } finally { + if (sameClient && client != null) client.close(); + } + } + + // Assertions based on implementation specific detail messages. Keep in + // sync with implementation. + static void assertDetailMessage(Throwable throwable, int iterationIndex) { + try { + Throwable cause = throwable; + while (cause != null) { + if (cause instanceof ProtocolException) { + if (cause.getMessage().matches("stream [0-9]+ flow control window exceeded")) { + System.out.println("Found expected exception: " + cause); + return; + } + } + cause = cause.getCause(); + } + throw new AssertionError( + "ProtocolException(\"stream X flow control window exceeded\") not found", + throwable); + } catch (AssertionError e) { + System.out.println("Exception does not match expectation: " + throwable); + throwable.printStackTrace(System.out); + throw e; + } + } + + @BeforeTest + public void setup() throws Exception { + sslContext = new SimpleSSLContext().get(); + if (sslContext == null) + throw new AssertionError("Unexpected null sslContext"); + + var http2TestServer = new Http2TestServer("localhost", false, 0); + http2TestServer.addHandler(new Http2TestHandler(), "/http2/"); + this.http2TestServer = HttpTestServer.of(http2TestServer); + http2URI = "http://" + this.http2TestServer.serverAuthority() + "/http2/x"; + + var https2TestServer = new Http2TestServer("localhost", true, sslContext); + https2TestServer.addHandler(new Http2TestHandler(), "/https2/"); + this.https2TestServer = HttpTestServer.of(https2TestServer); + https2URI = "https://" + this.https2TestServer.serverAuthority() + "/https2/x"; + + // Override the default exchange supplier with a custom one to enable + // particular test scenarios + http2TestServer.setExchangeSupplier(FCHttp2TestExchange::new); + https2TestServer.setExchangeSupplier(FCHttp2TestExchange::new); + + this.http2TestServer.start(); + this.https2TestServer.start(); + } + + @AfterTest + public void teardown() throws Exception { + http2TestServer.stop(); + https2TestServer.stop(); + } + + static class Http2TestHandler implements Http2Handler { + + @Override + public void handle(Http2TestExchange t) throws IOException { + String query = t.getRequestURI().getRawQuery(); + + try (InputStream is = t.getRequestBody(); + OutputStream os = t.getResponseBody()) { + + byte[] bytes = is.readAllBytes(); + System.out.println("Server " + t.getLocalAddress() + " received:\n" + + t.getRequestURI() + ": " + new String(bytes, StandardCharsets.UTF_8)); + t.getResponseHeaders().setHeader("X-Connection-Key", t.getConnectionKey()); + + if (bytes.length == 0) bytes = "no request body!".getBytes(StandardCharsets.UTF_8); + int window = Integer.getInteger("jdk.httpclient.windowsize", 2 * 16 * 1024); + final int maxChunkSize; + if (t instanceof FCHttp2TestExchange fct) { + maxChunkSize = Math.min(window, fct.conn.getMaxFrameSize()); + } else { + maxChunkSize = Math.min(window, SettingsFrame.MAX_FRAME_SIZE); + } + byte[] resp = bytes.length <= maxChunkSize + ? bytes + : Arrays.copyOfRange(bytes, 0, maxChunkSize); + int max = (window / resp.length) + 2; + // send in chunks + t.sendResponseHeaders(200, 0); + for (int i = 0; i <= max; i++) { + if (t instanceof FCHttp2TestExchange fct) { + try { + // we don't wait for the stream window, but we want + // to wait for the connection window + fct.conn.obtainConnectionWindow(resp.length); + } catch (InterruptedException ie) { + // ignore and continue... + } + } + ((BodyOutputStream) os).writeUncontrolled(resp, 0, resp.length); + } + } + if (t instanceof FCHttp2TestExchange fct) { + fct.responseSent(query); + } else fail("Exchange is not %s but %s" + .formatted(FCHttp2TestExchange.class.getName(), t.getClass().getName())); + } + } + + // A custom Http2TestExchangeImpl that overrides sendResponseHeaders to + // allow headers to be sent with a number of CONTINUATION frames. + static class FCHttp2TestExchange extends Http2TestExchangeImpl { + static volatile Consumer responseSentCB; + static void setResponseSentCB(Consumer responseSentCB) { + FCHttp2TestExchange.responseSentCB = responseSentCB; + } + + final Http2TestServerConnection conn; + FCHttp2TestExchange(int streamid, String method, HttpHeaders reqheaders, + HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is, + SSLSession sslSession, BodyOutputStream os, + Http2TestServerConnection conn, boolean pushAllowed) { + super(streamid, method, reqheaders, rspheadersBuilder, uri, is, sslSession, os, conn, pushAllowed); + this.conn = conn; + } + public void responseSent(String query) { + System.out.println("Server: response sent for " + query); + responseSentCB.accept(query); + } + + } +} diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java index 36498684a9a95..27dbe637b94ef 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,6 +241,7 @@ public static abstract class HttpTestExchange implements AutoCloseable { public abstract void close(); public abstract InetSocketAddress getRemoteAddress(); public abstract String getConnectionKey(); + public abstract InetSocketAddress getLocalAddress(); public void serverPush(URI uri, HttpHeaders headers, byte[] body) { ByteArrayInputStream bais = new ByteArrayInputStream(body); serverPush(uri, headers, bais); @@ -303,7 +304,10 @@ void doFilter(Filter.Chain chain) throws IOException { public InetSocketAddress getRemoteAddress() { return exchange.getRemoteAddress(); } - + @Override + public InetSocketAddress getLocalAddress() { + return exchange.getLocalAddress(); + } @Override public URI getRequestURI() { return exchange.getRequestURI(); } @Override @@ -370,6 +374,10 @@ void doFilter(Filter.Chain filter) throws IOException { public InetSocketAddress getRemoteAddress() { return exchange.getRemoteAddress(); } + @Override + public InetSocketAddress getLocalAddress() { + return exchange.getLocalAddress(); + } @Override public String getConnectionKey() { diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/BodyOutputStream.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/BodyOutputStream.java index c091b7ecf9b8f..db5778ec3d9f2 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/BodyOutputStream.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/BodyOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ import java.io.*; import java.nio.ByteBuffer; +import java.util.Objects; import jdk.internal.net.http.frame.DataFrame; import jdk.internal.net.http.frame.ResetFrame; @@ -65,6 +66,10 @@ void waitForWindow(int demand) throws InterruptedException { // first wait for the connection window conn.obtainConnectionWindow(demand); // now wait for the stream window + waitForStreamWindow(demand); + } + + public void waitForStreamWindow(int demand) throws InterruptedException { synchronized (this) { while (demand > 0) { int n = Math.min(demand, window); @@ -83,6 +88,7 @@ public void goodToGo() { @Override public void write(byte[] buf, int offset, int len) throws IOException { + Objects.checkFromIndexSize(offset, len, buf.length); if (closed) { throw new IOException("closed"); } @@ -104,6 +110,34 @@ public void write(byte[] buf, int offset, int len) throws IOException { } } + /** + * This method pushes frames onto the stack without checking + * for flow control, allowing the sender to bypass flow + * control for testing purposes + * @param buf data to send + * @param offset offset at which the data starts + * @param len length of the data to send + * @throws IOException if an I/O error occurs + */ + public void writeUncontrolled(byte[] buf, int offset, int len) + throws IOException { + Objects.checkFromIndexSize(offset, len, buf.length); + if (closed) { + throw new IOException("closed"); + } + + if (!goodToGo) { + throw new IllegalStateException("sendResponseHeaders must be called first"); + } + int max = conn.getMaxFrameSize(); + while (len > 0) { + int n = len > max ? max : len; + send(buf, offset, n, 0); + offset += n; + len -= n; + } + } + private void send(byte[] buf, int offset, int len, int flags) throws IOException { ByteBuffer buffer = ByteBuffer.allocate(len); buffer.put(buf, offset, len); diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/HpackTestEncoder.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/HpackTestEncoder.java new file mode 100644 index 0000000000000..f54a4a766b86e --- /dev/null +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/HpackTestEncoder.java @@ -0,0 +1,174 @@ +/* + * 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 + * 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.httpclient.test.lib.http2; + +import java.util.function.*; + +import jdk.internal.net.http.hpack.Encoder; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; +import static jdk.internal.net.http.hpack.HPACK.Logger.Level.EXTRA; +import static jdk.internal.net.http.hpack.HPACK.Logger.Level.NORMAL; + +public class HpackTestEncoder extends Encoder { + + public HpackTestEncoder(int maxCapacity) { + super(maxCapacity); + } + + /** + * Sets up the given header {@code (name, value)} with possibly sensitive + * value. + * + *

              If the {@code value} is sensitive (think security, secrecy, etc.) + * this encoder will compress it using a special representation + * (see 6.2.3. Literal Header Field Never Indexed). + * + *

              Fixates {@code name} and {@code value} for the duration of encoding. + * + * @param name + * the name + * @param value + * the value + * @param sensitive + * whether or not the value is sensitive + * + * @throws NullPointerException + * if any of the arguments are {@code null} + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + * @see #header(CharSequence, CharSequence) + * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean) + */ + public void header(CharSequence name, + CharSequence value, + boolean sensitive) throws IllegalStateException { + if (sensitive || getMaxCapacity() == 0) { + super.header(name, value, true); + } else { + header(name, value, false, (n,v) -> false); + } + } + /** + * Sets up the given header {@code (name, value)} with possibly sensitive + * value. + * + *

              If the {@code value} is sensitive (think security, secrecy, etc.) + * this encoder will compress it using a special representation + * (see 6.2.3. Literal Header Field Never Indexed). + * + *

              Fixates {@code name} and {@code value} for the duration of encoding. + * + * @param name + * the name + * @param value + * the value + * @param insertionPolicy + * a bipredicate to indicate whether a name value pair + * should be added to the dynamic table + * + * @throws NullPointerException + * if any of the arguments are {@code null} + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + * @see #header(CharSequence, CharSequence) + * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean) + */ + public void header(CharSequence name, + CharSequence value, + BiPredicate insertionPolicy) + throws IllegalStateException { + header(name, value, false, insertionPolicy); + } + + /** + * Sets up the given header {@code (name, value)} with possibly sensitive + * value. + * + *

              If the {@code value} is sensitive (think security, secrecy, etc.) + * this encoder will compress it using a special representation + * (see + * 6.2.3. Literal Header Field Never Indexed). + * + *

              Fixates {@code name} and {@code value} for the duration of encoding. + * + * @param name + * the name + * @param value + * the value + * @param sensitive + * whether or not the value is sensitive + * @param insertionPolicy + * a bipredicate to indicate whether a name value pair + * should be added to the dynamic table + * + * @throws NullPointerException + * if any of the arguments are {@code null} + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + * @see #header(CharSequence, CharSequence) + * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean) + */ + public void header(CharSequence name, + CharSequence value, + boolean sensitive, + BiPredicate insertionPolicy) + throws IllegalStateException { + if (sensitive == true || getMaxCapacity() == 0 || !insertionPolicy.test(name, value)) { + super.header(name, value, sensitive); + return; + } + var logger = logger(); + // Arguably a good balance between complexity of implementation and + // efficiency of encoding + requireNonNull(name, "name"); + requireNonNull(value, "value"); + var t = getHeaderTable(); + int index = tableIndexOf(name, value); + if (logger.isLoggable(NORMAL)) { + logger.log(NORMAL, () -> format("encoding with indexing ('%s', '%s'): index:%s", + name, value, index)); + } + if (index > 0) { + indexed(index); + } else { + boolean huffmanValue = isHuffmanBetterFor(value); + if (index < 0) { + literalWithIndexing(-index, value, huffmanValue); + } else { + boolean huffmanName = isHuffmanBetterFor(name); + literalWithIndexing(name, huffmanName, value, huffmanValue); + } + } + } + + protected int calculateCapacity(int maxCapacity) { + return maxCapacity; + } + +} diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java index d982349dac500..828c939f53f20 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java @@ -29,9 +29,12 @@ import java.net.URI; import java.net.InetSocketAddress; import java.net.http.HttpHeaders; +import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.BiPredicate; import javax.net.ssl.SSLSession; import jdk.internal.net.http.common.HttpHeadersBuilder; +import jdk.internal.net.http.frame.Http2Frame; public interface Http2TestExchange { @@ -53,6 +56,12 @@ public interface Http2TestExchange { void sendResponseHeaders(int rCode, long responseLength) throws IOException; + default void sendResponseHeaders(int rCode, long responseLength, + BiPredicate insertionPolicy) + throws IOException { + sendResponseHeaders(rCode, responseLength); + } + InetSocketAddress getRemoteAddress(); int getResponseCode(); @@ -65,6 +74,10 @@ public interface Http2TestExchange { void serverPush(URI uri, HttpHeaders headers, InputStream content); + default void sendFrames(List frames) throws IOException { + throw new UnsupportedOperationException("not implemented"); + } + /** * Send a PING on this exchanges connection, and completes the returned CF * with the number of milliseconds it took to get a valid response. diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java index d25019f9094c0..fa7589c023249 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java @@ -27,6 +27,7 @@ import jdk.internal.net.http.common.HttpHeadersBuilder; import jdk.internal.net.http.frame.HeaderFrame; import jdk.internal.net.http.frame.HeadersFrame; +import jdk.internal.net.http.frame.Http2Frame; import jdk.internal.net.http.frame.ResetFrame; import javax.net.ssl.SSLSession; @@ -39,6 +40,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.function.BiPredicate; public class Http2TestExchangeImpl implements Http2TestExchange { @@ -132,8 +134,13 @@ public OutputStream getResponseBody() { return os; } - @Override public void sendResponseHeaders(int rCode, long responseLength) throws IOException { + sendResponseHeaders(rCode, responseLength, (n,v) -> false); + } + @Override + public void sendResponseHeaders(int rCode, long responseLength, + BiPredicate insertionPolicy) + throws IOException { // Do not set Content-Length for 100, and do not set END_STREAM if (rCode == 100) responseLength = 0; @@ -147,7 +154,7 @@ public void sendResponseHeaders(int rCode, long responseLength) throws IOExcepti HttpHeaders headers = rspheadersBuilder.build(); ResponseHeaders response - = new ResponseHeaders(headers); + = new ResponseHeaders(headers, insertionPolicy); response.streamid(streamid); response.setFlag(HeaderFrame.END_HEADERS); @@ -172,6 +179,11 @@ public void sendResponseHeaders(ResponseHeaders response) throws IOException { conn.outputQ.put(response); } + @Override + public void sendFrames(List frames) throws IOException { + conn.sendFrames(frames); + } + @Override public InetSocketAddress getRemoteAddress() { return (InetSocketAddress) conn.socket.getRemoteSocketAddress(); diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java index 1aeeee60b197e..068d2a49e576b 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java @@ -24,6 +24,8 @@ package jdk.httpclient.test.lib.http2; import jdk.internal.net.http.common.HttpHeadersBuilder; +import jdk.internal.net.http.common.Log; +import jdk.internal.net.http.frame.ContinuationFrame; import jdk.internal.net.http.frame.DataFrame; import jdk.internal.net.http.frame.ErrorFrame; import jdk.internal.net.http.frame.FramesDecoder; @@ -80,6 +82,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiPredicate; import java.util.function.Consumer; import java.util.function.Predicate; @@ -87,6 +90,7 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; import static jdk.internal.net.http.frame.ErrorFrame.REFUSED_STREAM; +import static jdk.internal.net.http.frame.SettingsFrame.DEFAULT_MAX_FRAME_SIZE; import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE; /** @@ -105,7 +109,7 @@ public class Http2TestServerConnection { final Http2TestExchangeSupplier exchangeSupplier; final InputStream is; final OutputStream os; - volatile Encoder hpackOut; + volatile HpackTestEncoder hpackOut; volatile Decoder hpackIn; volatile SettingsFrame clientSettings; final SettingsFrame serverSettings; @@ -421,7 +425,9 @@ private SettingsFrame getSettingsFromString(String s) throws IOException { } public int getMaxFrameSize() { - return clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE); + var max = clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE); + if (max <= 0) max = DEFAULT_MAX_FRAME_SIZE; + return max; } /** Sends a pre-canned HTTP/1.1 response. */ @@ -482,7 +488,7 @@ void run() throws Exception { //System.out.println("ServerSettings: " + serverSettings); //System.out.println("ClientSettings: " + clientSettings); - hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE)); + hpackOut = new HpackTestEncoder(serverSettings.getParameter(HEADER_TABLE_SIZE)); hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE)); if (!secure) { @@ -812,6 +818,14 @@ headers, rspheadersBuilder, uri, bis, getSSLSession(), } } + public void sendFrames(List frames) throws IOException { + synchronized (outputQ) { + for (var frame : frames) { + outputQ.put(frame); + } + } + } + protected HttpHeadersBuilder createNewHeadersBuilder() { return new HttpHeadersBuilder(); } @@ -938,26 +952,38 @@ static boolean isServerStreamId(int streamid) { return (streamid & 0x01) == 0x00; } + final ReentrantLock headersLock = new ReentrantLock(); + /** Encodes an group of headers, without any ordering guarantees. */ public List encodeHeaders(HttpHeaders headers) { + return encodeHeaders(headers, (n,v) -> false); + } + + public List encodeHeaders(HttpHeaders headers, + BiPredicate insertionPolicy) { List buffers = new LinkedList<>(); ByteBuffer buf = getBuffer(); boolean encoded; - for (Map.Entry> entry : headers.map().entrySet()) { - List values = entry.getValue(); - String key = entry.getKey().toLowerCase(); - for (String value : values) { - do { - hpackOut.header(key, value); - encoded = hpackOut.encode(buf); - if (!encoded) { - buf.flip(); - buffers.add(buf); - buf = getBuffer(); - } - } while (!encoded); + headersLock.lock(); + try { + for (Map.Entry> entry : headers.map().entrySet()) { + List values = entry.getValue(); + String key = entry.getKey().toLowerCase(); + for (String value : values) { + hpackOut.header(key, value, insertionPolicy); + do { + encoded = hpackOut.encode(buf); + if (!encoded && !buf.hasRemaining()) { + buf.flip(); + buffers.add(buf); + buf = getBuffer(); + } + } while (!encoded); + } } + } finally { + headersLock.unlock(); } buf.flip(); buffers.add(buf); @@ -970,18 +996,23 @@ public List encodeHeadersOrdered(List> head ByteBuffer buf = getBuffer(); boolean encoded; - for (Map.Entry entry : headers) { - String value = entry.getValue(); - String key = entry.getKey().toLowerCase(); - do { + headersLock.lock(); + try { + for (Map.Entry entry : headers) { + String value = entry.getValue(); + String key = entry.getKey().toLowerCase(); hpackOut.header(key, value); - encoded = hpackOut.encode(buf); - if (!encoded) { - buf.flip(); - buffers.add(buf); - buf = getBuffer(); - } - } while (!encoded); + do { + encoded = hpackOut.encode(buf); + if (!encoded && !buf.hasRemaining()) { + buf.flip(); + buffers.add(buf); + buf = getBuffer(); + } + } while (!encoded); + } + } finally { + headersLock.unlock(); } buf.flip(); buffers.add(buf); @@ -1008,10 +1039,50 @@ void writeLoop() { break; } else throw x; } - if (frame instanceof ResponseHeaders) { - ResponseHeaders rh = (ResponseHeaders)frame; - HeadersFrame hf = new HeadersFrame(rh.streamid(), rh.getFlags(), encodeHeaders(rh.headers)); - writeFrame(hf); + if (frame instanceof ResponseHeaders rh) { + var buffers = encodeHeaders(rh.headers, rh.insertionPolicy); + int maxFrameSize = Math.min(rh.getMaxFrameSize(), getMaxFrameSize() - 64); + int next = 0; + int cont = 0; + do { + // If the total size of headers exceeds the max frame + // size we need to split the headers into one + // HeadersFrame + N x ContinuationFrames + int remaining = maxFrameSize; + var list = new ArrayList(buffers.size()); + for (; next < buffers.size(); next++) { + var b = buffers.get(next); + var len = b.remaining(); + if (!b.hasRemaining()) continue; + if (len <= remaining) { + remaining -= len; + list.add(b); + } else { + if (next == 0) { + list.add(b.slice(b.position(), remaining)); + b.position(b.position() + remaining); + remaining = 0; + } + break; + } + } + int flags = rh.getFlags(); + if (next != buffers.size()) { + flags = flags & ~HeadersFrame.END_HEADERS; + } + if (cont > 0) { + flags = flags & ~HeadersFrame.END_STREAM; + } + HeaderFrame hf = cont == 0 + ? new HeadersFrame(rh.streamid(), flags, list) + : new ContinuationFrame(rh.streamid(), flags, list); + if (Log.headers()) { + // avoid too much chatter: log only if Log.headers() is enabled + System.err.println("TestServer writing " + hf); + } + writeFrame(hf); + cont++; + } while (next < buffers.size()); } else if (frame instanceof OutgoingPushPromise) { handlePush((OutgoingPushPromise)frame); } else @@ -1303,7 +1374,7 @@ void registerStreamWindowUpdater(int streamid, Consumer r) { * * @param amount */ - synchronized void obtainConnectionWindow(int amount) throws InterruptedException { + public synchronized void obtainConnectionWindow(int amount) throws InterruptedException { while (amount > 0) { int n = Math.min(amount, sendWindow); amount -= n; @@ -1313,20 +1384,42 @@ synchronized void obtainConnectionWindow(int amount) throws InterruptedException } } - synchronized void updateConnectionWindow(int amount) { - sendWindow += amount; - notifyAll(); + void updateConnectionWindow(int amount) { + System.out.printf("sendWindow (window=%s, amount=%s) is now: %s%n", + sendWindow, amount, sendWindow + amount); + synchronized (this) { + sendWindow += amount; + notifyAll(); + } } // simplified output headers class. really just a type safe container // for the hashmap. public static class ResponseHeaders extends Http2Frame { - HttpHeaders headers; + final HttpHeaders headers; + final BiPredicate insertionPolicy; + + final int maxFrameSize; public ResponseHeaders(HttpHeaders headers) { + this(headers, (n,v) -> false); + } + public ResponseHeaders(HttpHeaders headers, BiPredicate insertionPolicy) { + this(headers, insertionPolicy, Integer.MAX_VALUE); + } + + public ResponseHeaders(HttpHeaders headers, + BiPredicate insertionPolicy, + int maxFrameSize) { super(0, 0); this.headers = headers; + this.insertionPolicy = insertionPolicy; + this.maxFrameSize = maxFrameSize; + } + + public int getMaxFrameSize() { + return maxFrameSize; } } diff --git a/test/jdk/java/nio/MappedByteBuffer/ForceException.java b/test/jdk/java/nio/MappedByteBuffer/ForceException.java index dea63db42bf9c..c8bd06967d027 100644 --- a/test/jdk/java/nio/MappedByteBuffer/ForceException.java +++ b/test/jdk/java/nio/MappedByteBuffer/ForceException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ public static void main(String[] args) throws IOException { int numberOfBlocks = 200; int fileLength = numberOfBlocks * blockSize; - File file = new File(System.getProperty("test.src", "."), "test.dat"); + File file = new File(".", "test.dat"); file.deleteOnExit(); try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) { raf.setLength(fileLength); diff --git a/test/jdk/java/nio/MappedByteBuffer/ForceViews.java b/test/jdk/java/nio/MappedByteBuffer/ForceViews.java index 83727f8096859..57ddac28cdfa0 100644 --- a/test/jdk/java/nio/MappedByteBuffer/ForceViews.java +++ b/test/jdk/java/nio/MappedByteBuffer/ForceViews.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ static record Segment(int position, int length) {} @BeforeTest(alwaysRun=true) public void openChannel() throws IOException { - Path file = Path.of(System.getProperty("test.src", "."), "junk"); + Path file = Path.of(".", "junk"); fc = FileChannel.open(file, CREATE_NEW, READ, WRITE, DELETE_ON_CLOSE); ByteBuffer buf = ByteBuffer.wrap(new byte[1024]); fc.write(buf); diff --git a/test/jdk/java/nio/channels/Selector/WakeupNow.java b/test/jdk/java/nio/channels/Selector/WakeupNow.java index 23dc0c3090708..a8d1222ba1395 100644 --- a/test/jdk/java/nio/channels/Selector/WakeupNow.java +++ b/test/jdk/java/nio/channels/Selector/WakeupNow.java @@ -26,7 +26,9 @@ * @summary Ensure that the wakeup state is cleared by selectNow() */ -import java.nio.channels.*; +import java.nio.channels.Pipe; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; public class WakeupNow { @@ -47,14 +49,15 @@ private static void test1() throws Exception { // ensure wakeup is consumed by selectNow Thread.sleep(2000); sel.selectNow(); - long startTime = System.currentTimeMillis(); + long startTime = System.nanoTime(); int n = sel.select(2000); - long endTime = System.currentTimeMillis(); + long endTime = System.nanoTime(); p.source().close(); p.sink().close(); sel.close(); - if (endTime - startTime < 1000) - throw new RuntimeException("test failed"); + long delta = endTime - startTime; + if (delta < 1_000_000_000) + throw new RuntimeException("test failed with delta " + delta); } // Test if selectNow clears wakeup with only the wakeup fd @@ -62,18 +65,17 @@ private static void test1() throws Exception { // This fails before the fix on Solaris private static void test2() throws Exception { Selector sel = Selector.open(); - Pipe p = Pipe.open(); - p.source().configureBlocking(false); sel.wakeup(); // ensure wakeup is consumed by selectNow Thread.sleep(2000); sel.selectNow(); - long startTime = System.currentTimeMillis(); + long startTime = System.nanoTime(); int n = sel.select(2000); - long endTime = System.currentTimeMillis(); + long endTime = System.nanoTime(); sel.close(); - if (endTime - startTime < 1000) - throw new RuntimeException("test failed"); + long delta = endTime - startTime; + if (delta < 1_000_000_000) + throw new RuntimeException("test failed with delta " + delta); } } diff --git a/test/jdk/java/nio/file/DirectoryStream/SecureDS.java b/test/jdk/java/nio/file/DirectoryStream/SecureDS.java index d4f197eb09b9a..e058d782c52e7 100644 --- a/test/jdk/java/nio/file/DirectoryStream/SecureDS.java +++ b/test/jdk/java/nio/file/DirectoryStream/SecureDS.java @@ -22,8 +22,9 @@ */ /* @test - * @bug 4313887 6838333 + * @bug 4313887 6838333 8343020 * @summary Unit test for java.nio.file.SecureDirectoryStream + * @requires (os.family == "linux" | os.family == "mac") * @library .. */ @@ -45,11 +46,7 @@ public static void main(String[] args) throws IOException { DirectoryStream stream = newDirectoryStream(dir); stream.close(); if (!(stream instanceof SecureDirectoryStream)) { - if (System.getProperty("os.name").equals("Linux")) - throw new AssertionError( - "SecureDirectoryStream not supported."); - System.out.println("SecureDirectoryStream not supported."); - return; + throw new AssertionError("SecureDirectoryStream not supported."); } supportsSymbolicLinks = TestUtil.supportsSymbolicLinks(dir); diff --git a/test/jdk/java/nio/file/Files/InputStreamTest.java b/test/jdk/java/nio/file/Files/InputStreamTest.java index 8587ee332f255..f6fa7da6ff069 100644 --- a/test/jdk/java/nio/file/Files/InputStreamTest.java +++ b/test/jdk/java/nio/file/Files/InputStreamTest.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 @@ -22,37 +22,123 @@ */ /* @test - * @bug 8227609 + * @bug 8227609 8233451 * @summary Test of InputStream and OutputStream created by java.nio.file.Files - * @library .. + * @library .. /test/lib + * @build jdk.test.lib.Platform + * @run junit/othervm --enable-native-access=ALL-UNNAMED InputStreamTest */ +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.InputStream; +import java.io.IOException; import java.io.OutputStream; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; import java.nio.channels.ClosedChannelException; -import java.nio.file.*; -import static java.nio.file.Files.*; -import static java.nio.file.LinkOption.*; -import java.nio.file.attribute.*; -import java.io.IOException; -import java.util.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import jdk.test.lib.Platform; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; +import static org.junit.jupiter.api.Assertions.*; public class InputStreamTest { - public static void main(String[] args) throws IOException { - Path dir = TestUtil.createTemporaryDirectory(); + private static final String PIPE = "pipe"; + private static final Path PIPE_PATH = Path.of(PIPE); + private static final String SENTENCE = + "Tout est permis mais rien n’est possible"; + + private static Path TMPDIR; + + private static class mkfifo { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + ValueLayout.JAVA_INT, + ValueLayout.ADDRESS, + ValueLayout.JAVA_SHORT + ); + + public static final MemorySegment ADDR; + static { + Linker linker = Linker.nativeLinker(); + SymbolLookup stdlib = linker.defaultLookup(); + ADDR = stdlib.find("mkfifo").orElseThrow(); + } + + public static final MethodHandle HANDLE = + Linker.nativeLinker().downcallHandle(ADDR, DESC); + } + + public static int mkfifo(MemorySegment x0, short x1) { + var mh$ = mkfifo.HANDLE; try { - testSkip(dir); - } finally { - TestUtil.removeAll(dir); + return (int)mh$.invokeExact(x0, x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); } } + private static Thread createWriteThread() { + Thread t = new Thread( + new Runnable() { + public void run() { + try (FileOutputStream fos = new FileOutputStream(PIPE);) { + fos.write(SENTENCE.getBytes()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + ); + t.start(); + return t; + } + + @BeforeAll + static void before() throws InterruptedException, IOException { + TMPDIR = TestUtil.createTemporaryDirectory(); + + if (Platform.isWindows()) + return; + + Files.deleteIfExists(PIPE_PATH); + try (var newArena = Arena.ofConfined()) { + var addr = newArena.allocateFrom(PIPE); + short mode = 0666; + assertEquals(0, mkfifo(addr, mode)); + } + if (Files.notExists(PIPE_PATH)) + throw new RuntimeException("Failed to create " + PIPE); + } + + @AfterAll + static void after() throws IOException { + TestUtil.removeAll(TMPDIR); + + if (Platform.isWindows()) + return; + + Files.deleteIfExists(PIPE_PATH); + } + /** * Tests Files.newInputStream(Path).skip(). */ - static void testSkip(Path tmpdir) throws IOException { - Path file = createFile(tmpdir.resolve("foo")); + @Test + void skip() throws IOException { + Path file = Files.createFile(TMPDIR.resolve("foo")); try (OutputStream out = Files.newOutputStream(file)) { final int size = 512; byte[] blah = new byte[size]; @@ -123,8 +209,87 @@ static void testSkip(Path tmpdir) throws IOException { } } - static void assertTrue(boolean okay) { - if (!okay) - throw new RuntimeException("Assertion Failed"); + /** + * Tests that Files.newInputStream(Path).available() does not throw + */ + @Test + @DisabledOnOs(OS.WINDOWS) + void availableStdin() throws IOException { + Path stdin = Path.of("/dev", "stdin"); + if (Files.exists(stdin)) { + try (InputStream s = Files.newInputStream(stdin);) { + s.available(); + } + } + } + + /** + * Tests that Files.newInputStream(Path).skip(0) does not throw + */ + @Test + @DisabledOnOs(OS.WINDOWS) + void skipStdin() throws IOException { + Path stdin = Path.of("/dev", "stdin"); + if (Files.exists(stdin)) { + try (InputStream s = Files.newInputStream(stdin);) { + s.skip(0); + } + } + } + + /** + * Tests Files.newInputStream(Path).readAllBytes(). + */ + @Test + @DisabledOnOs(OS.WINDOWS) + void readAllBytes() throws InterruptedException, IOException { + Thread t = createWriteThread(); + try (InputStream in = Files.newInputStream(Path.of(PIPE))) { + String s = new String(in.readAllBytes()); + System.out.println(s); + assertEquals(SENTENCE, s); + } finally { + t.join(); + } + } + + /** + * Tests Files.newInputStream(Path).readNBytes(byte[],int,int). + */ + @Test + @DisabledOnOs(OS.WINDOWS) + void readNBytesNoOverride() throws InterruptedException, IOException { + Thread t = createWriteThread(); + try (InputStream in = Files.newInputStream(Path.of(PIPE))) { + final int offset = 11; + final int length = 17; + assert length <= SENTENCE.length(); + byte[] b = new byte[offset + length]; + int n = in.readNBytes(b, offset, length); + String s = new String(b, offset, length); + System.out.println(s); + assertEquals(SENTENCE.substring(0, length), s); + } finally { + t.join(); + } + } + + /** + * Tests Files.newInputStream(Path).readNBytes(int). + */ + @Test + @DisabledOnOs(OS.WINDOWS) + void readNBytesOverride() throws InterruptedException, IOException { + Thread t = createWriteThread(); + try (InputStream in = Files.newInputStream(Path.of(PIPE))) { + final int length = 17; + assert length <= SENTENCE.length(); + byte[] b = in.readNBytes(length); + String s = new String(b); + System.out.println(s); + assertEquals(SENTENCE.substring(0, length), s); + } finally { + t.join(); + } } } diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java index ad85da7ae63b1..65e801b0a9f35 100644 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024 Alibaba Group Holding 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 @@ -25,18 +26,18 @@ * @bug 8011536 8151430 8316304 8334339 * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using /tmp directory. - * @library ../.. /test/lib - * @build jdk.test.lib.Platform - * @run main CreationTime + * @library ../.. /test/lib /java/foreign + * @build jdk.test.lib.Platform NativeTestHelper + * @run main/othervm/native --enable-native-access=ALL-UNNAMED 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 CreationTime . + * @library ../.. /test/lib /java/foreign + * @build jdk.test.lib.Platform NativeTestHelper + * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime . */ import java.lang.foreign.Linker; @@ -51,8 +52,6 @@ public class CreationTime { - private static final java.io.PrintStream err = System.err; - /** * Reads the creationTime attribute */ @@ -78,14 +77,9 @@ static void test(Path top) throws IOException { FileTime creationTime = creationTime(file); Instant now = Instant.now(); if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) { - 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); - } + System.err.println("creationTime.toMillis() == " + creationTime.toMillis()); + System.err.println("File creation time reported as: " + creationTime); + throw new RuntimeException("Expected to be close to: " + now); } /** @@ -107,7 +101,12 @@ static void test(Path top) throws IOException { } } else if (Platform.isLinux()) { // Creation time read depends on statx system call support - supportsCreationTimeRead = Linker.nativeLinker().defaultLookup().find("statx").isPresent(); + try { + supportsCreationTimeRead = CreationTimeHelper. + linuxIsCreationTimeSupported(file.toAbsolutePath().toString()); + } catch (Throwable e) { + supportsCreationTimeRead = false; + } // Creation time updates are not supported on Linux supportsCreationTimeWrite = false; } @@ -122,8 +121,11 @@ static void test(Path top) throws IOException { Instant plusHour = Instant.now().plusSeconds(60L * 60L); Files.setLastModifiedTime(file, FileTime.from(plusHour)); FileTime current = creationTime(file); - if (!current.equals(creationTime)) + if (!current.equals(creationTime)) { + System.err.println("current = " + current); + System.err.println("creationTime = " + creationTime); throw new RuntimeException("Creation time should not have changed"); + } } /** diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java new file mode 100644 index 0000000000000..592aeba322dd0 --- /dev/null +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Alibaba Group Holding 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 + * 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.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; + +public class CreationTimeHelper extends NativeTestHelper { + + static { + System.loadLibrary("CreationTimeHelper"); + } + + final static Linker abi = Linker.nativeLinker(); + static final SymbolLookup lookup = SymbolLookup.loaderLookup(); + final static MethodHandle methodHandle = abi. + downcallHandle(lookup.findOrThrow("linuxIsCreationTimeSupported"), + FunctionDescriptor.of(C_BOOL, C_POINTER)); + + // Helper so as to determine birth time support or not on Linux. + // Support is determined in a two-step process: + // 1. Determine if `statx` system call is available. If available proceed, + // otherwise return false. + // 2. Perform an actual `statx` call on the given file and check for birth + // time support in the mask returned from the call. This is needed, + // since some file systems, like nfs/tmpfs etc., don't support birth + // time even though the `statx` system call is available. + static boolean linuxIsCreationTimeSupported(String file) throws Throwable { + if (!abi.defaultLookup().find("statx").isPresent()) { + return false; + } + try (var arena = Arena.ofConfined()) { + MemorySegment s = arena.allocateFrom(file); + return (boolean)methodHandle.invokeExact(s); + } + } +} diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c new file mode 100644 index 0000000000000..0686cc790da41 --- /dev/null +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2024 Alibaba Group Holding 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include "export.h" +#include +#if defined(__linux__) +#include +#include +#include +#include +#include +#ifndef STATX_BASIC_STATS +#define STATX_BASIC_STATS 0x000007ffU +#endif +#ifndef STATX_BTIME +#define STATX_BTIME 0x00000800U +#endif +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT RTLD_LOCAL +#endif +#ifndef AT_SYMLINK_NOFOLLOW +#define AT_SYMLINK_NOFOLLOW 0x100 +#endif +#ifndef AT_FDCWD +#define AT_FDCWD -100 +#endif + +#ifndef __GLIBC__ +// Alpine doesn't know these types, define them +typedef unsigned int __uint32_t; +typedef unsigned short __uint16_t; +typedef unsigned long int __uint64_t; +#endif + +/* + * Timestamp structure for the timestamps in struct statx. + */ +struct my_statx_timestamp { + int64_t tv_sec; + __uint32_t tv_nsec; + int32_t __reserved; +}; + +/* + * struct statx used by statx system call on >= glibc 2.28 + * systems + */ +struct my_statx +{ + __uint32_t stx_mask; + __uint32_t stx_blksize; + __uint64_t stx_attributes; + __uint32_t stx_nlink; + __uint32_t stx_uid; + __uint32_t stx_gid; + __uint16_t stx_mode; + __uint16_t __statx_pad1[1]; + __uint64_t stx_ino; + __uint64_t stx_size; + __uint64_t stx_blocks; + __uint64_t stx_attributes_mask; + struct my_statx_timestamp stx_atime; + struct my_statx_timestamp stx_btime; + struct my_statx_timestamp stx_ctime; + struct my_statx_timestamp stx_mtime; + __uint32_t stx_rdev_major; + __uint32_t stx_rdev_minor; + __uint32_t stx_dev_major; + __uint32_t stx_dev_minor; + __uint64_t __statx_pad2[14]; +}; + +typedef int statx_func(int dirfd, const char *restrict pathname, int flags, + unsigned int mask, struct my_statx *restrict statxbuf); + +static statx_func* my_statx_func = NULL; +#endif //#defined(__linux__) + +// static boolean linuxIsCreationTimeSupported(char* file) +EXPORT bool linuxIsCreationTimeSupported(char* file) { +#if defined(__linux__) + struct my_statx stx = {0}; + int ret, atflag = AT_SYMLINK_NOFOLLOW; + unsigned int mask = STATX_BASIC_STATS | STATX_BTIME; + + my_statx_func = (statx_func*) dlsym(RTLD_DEFAULT, "statx"); + if (my_statx_func == NULL) { + return false; + } + + if (file == NULL) { + printf("input file error!\n"); + return false; + } + + ret = my_statx_func(AT_FDCWD, file, atflag, mask, &stx); + if (ret != 0) { + return false; + } + // On some systems where statx is available but birth time might still not + // be supported as it's file system specific. The only reliable way to + // check for supported or not is looking at the filled in STATX_BTIME bit + // in the returned statx buffer mask. + if ((stx.stx_mask & STATX_BTIME) != 0) + return true; + return false; +#else + return false; +#endif +} diff --git a/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java b/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java index 1e16c157fed2e..1e5eb9680302e 100644 --- a/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java +++ b/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ public static void main(String[] args) throws Exception { String kaAlgo = args[0]; String kpgAlgo = args[1]; - String provider = args[2]; + String provider = System.getProperty("test.provider.name", args[2]); System.out.println("Testing " + kaAlgo); AlgoSpec aSpec = AlgoSpec.valueOf(AlgoSpec.class, kaAlgo); List specs = aSpec.getAlgorithmParameterSpecs(); diff --git a/test/jdk/java/security/KeyAgreement/KeySizeTest.java b/test/jdk/java/security/KeyAgreement/KeySizeTest.java index 5dfb2dc731521..6ac36a5ee863f 100644 --- a/test/jdk/java/security/KeyAgreement/KeySizeTest.java +++ b/test/jdk/java/security/KeyAgreement/KeySizeTest.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 @@ -64,7 +64,7 @@ public class KeySizeTest { public static void main(String[] args) throws Exception { String kaAlgo = args[0]; - String provider = args[1]; + String provider = System.getProperty("test.provider.name", args[1]); String kpgAlgo = args[2]; int keySize = Integer.parseInt(args[3]); testKeyAgreement(provider, kaAlgo, kpgAlgo, keySize); diff --git a/test/jdk/java/security/KeyAgreement/KeySpecTest.java b/test/jdk/java/security/KeyAgreement/KeySpecTest.java index 1e8742dd7969d..f5974738a1257 100644 --- a/test/jdk/java/security/KeyAgreement/KeySpecTest.java +++ b/test/jdk/java/security/KeyAgreement/KeySpecTest.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 @@ -24,6 +24,7 @@ /* * @test * @bug 8184359 + * @library /test/lib * @summary Standard tests on KeySpec, KeyFactory, KeyPairs and Keys. * Arguments order * @run main KeySpecTest DiffieHellman SunJCE DiffieHellman @@ -55,13 +56,14 @@ import javax.crypto.KeyAgreement; import javax.crypto.spec.DHPrivateKeySpec; import javax.crypto.spec.DHPublicKeySpec; +import jdk.test.lib.security.SecurityUtils; public class KeySpecTest { public static void main(String[] args) throws Exception { String kaAlgo = args[0]; - String provider = args[1]; + String provider = System.getProperty("test.provider.name", args[1]); String kpgAlgo = args[2]; KeyPair kp = genKeyPair(provider, kpgAlgo, (args.length > 3) ? args[3] : kpgAlgo); @@ -78,7 +80,7 @@ private static KeyPair genKeyPair(String provider, String kpgAlgo, KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgo, provider); switch (kpgInit) { case "DiffieHellman": - kpg.initialize(512); + kpg.initialize(SecurityUtils.getTestKeySize(kpgInit)); break; case "EC": kpg.initialize(256); diff --git a/test/jdk/java/security/KeyAgreement/MultiThreadTest.java b/test/jdk/java/security/KeyAgreement/MultiThreadTest.java index f53572a10b5a9..743e874a7dea2 100644 --- a/test/jdk/java/security/KeyAgreement/MultiThreadTest.java +++ b/test/jdk/java/security/KeyAgreement/MultiThreadTest.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 @@ -24,6 +24,7 @@ /* * @test * @bug 8184359 + * @library /test/lib * @summary KeyPairGenerator Test with multiple threads. * Arguments order * @run main MultiThreadTest DiffieHellman SunJCE DiffieHellman @@ -39,6 +40,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import javax.crypto.KeyAgreement; +import jdk.test.lib.security.SecurityUtils; /** * This test targets KeyPairGenerator API related issue in a multi threaded @@ -52,7 +54,7 @@ public class MultiThreadTest { public static void main(String[] args) throws Exception { String kaAlgo = args[0]; - String provider = args[1]; + String provider = System.getProperty("test.provider.name", args[1]); String kpgAlgo = args[2]; KeyPairGenerator kpg = genKeyGenerator(provider, kpgAlgo, (args.length > 3) ? args[3] : kpgAlgo); @@ -68,7 +70,7 @@ private static KeyPairGenerator genKeyGenerator(String provider, KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgo, provider); switch (kpgInit) { case "DiffieHellman": - kpg.initialize(512); + kpg.initialize(SecurityUtils.getTestKeySize(kpgInit)); break; case "EC": kpg.initialize(256); diff --git a/test/jdk/java/security/KeyAgreement/NegativeTest.java b/test/jdk/java/security/KeyAgreement/NegativeTest.java index 864bf09aeebad..3ccb614ffc3a7 100644 --- a/test/jdk/java/security/KeyAgreement/NegativeTest.java +++ b/test/jdk/java/security/KeyAgreement/NegativeTest.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 @@ -35,7 +35,7 @@ * Arguments order * * @library /test/lib - * @run main NegativeTest DiffieHellman SunJCE DiffieHellman 1024 + * @run main NegativeTest DiffieHellman SunJCE DiffieHellman 2048 * @run main NegativeTest ECDH SunEC EC 256 * @run main NegativeTest XDH SunEC XDH 255 X25519 * @run main NegativeTest XDH SunEC XDH 448 X448 @@ -59,13 +59,14 @@ import java.util.Arrays; import java.util.HexFormat; import javax.crypto.KeyAgreement; +import jdk.test.lib.security.SecurityUtils; public class NegativeTest { public static void main(String[] args) throws Exception { String kaAlgo = args[0]; - String provider = args[1]; + String provider = System.getProperty("test.provider.name", args[1]); String kpgAlgo = args[2]; int keySize = Integer.parseInt(args[3]); String kpgInit = (args.length > 4) ? args[4] : args[2]; @@ -93,7 +94,7 @@ private static KeyPair genKeyPair(String provider, String kpgAlgo, Security.getProvider(provider)); switch (kpgInit) { case "DiffieHellman": - kpg.initialize(512); + kpg.initialize(SecurityUtils.getTestKeySize(kpgInit)); break; case "EC": kpg.initialize(256); diff --git a/test/jdk/java/security/KeyFactory/Failover.java b/test/jdk/java/security/KeyFactory/Failover.java index 6242758a9cf89..7107ef1ad0281 100644 --- a/test/jdk/java/security/KeyFactory/Failover.java +++ b/test/jdk/java/security/KeyFactory/Failover.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, 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 @@ -24,7 +24,7 @@ /** * @test * @bug 4894125 7054918 8130181 - * @library ../testlibrary + * @library ../testlibrary /test/lib * @summary test that failover for KeyFactory works * @author Andreas Sterbenz */ @@ -34,6 +34,7 @@ import java.security.*; import java.security.interfaces.*; import java.security.spec.*; +import jdk.test.lib.security.SecurityUtils; public class Failover { @@ -72,8 +73,9 @@ public static void main0(String[] args) throws Exception { // somewhat more real tests using DSA System.out.println("DSA tests..."); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); - kpg.initialize(512); + String kpgAlgorithm = "DSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair kp = kpg.generateKeyPair(); kf = KeyFactory.getInstance("DSA"); diff --git a/test/jdk/java/security/KeyFactory/GenerateRSAPrivateCrtKey.java b/test/jdk/java/security/KeyFactory/GenerateRSAPrivateCrtKey.java index de37778b844c9..1c7cdba2598da 100644 --- a/test/jdk/java/security/KeyFactory/GenerateRSAPrivateCrtKey.java +++ b/test/jdk/java/security/KeyFactory/GenerateRSAPrivateCrtKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 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 @@ -51,7 +51,8 @@ public static void main(String[] args) throws Exception { new BigInteger(1, coeff)); // Create an RSA private key from the CRT specification - KeyFactory kf = KeyFactory.getInstance("RSA", "SunRsaSign"); + KeyFactory kf = KeyFactory.getInstance("RSA", + System.getProperty("test.provider.name", "SunRsaSign")); RSAPrivateCrtKey rsaPriKey = (RSAPrivateCrtKey) kf.generatePrivate(rsaCrtSpec); diff --git a/test/jdk/java/security/KeyFactory/KeyFactoryGetKeySpecForInvalidSpec.java b/test/jdk/java/security/KeyFactory/KeyFactoryGetKeySpecForInvalidSpec.java index e72d5c8decc3f..71b05b0c2252f 100644 --- a/test/jdk/java/security/KeyFactory/KeyFactoryGetKeySpecForInvalidSpec.java +++ b/test/jdk/java/security/KeyFactory/KeyFactoryGetKeySpecForInvalidSpec.java @@ -69,7 +69,8 @@ public BigInteger getModulus() { } public static void main(String[] args) throws Exception { - KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA", "SunRsaSign"); + KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA", + System.getProperty("test.provider.name", "SunRsaSign")); kg.initialize(2048); KeyPair pair = kg.generateKeyPair(); diff --git a/test/jdk/java/security/KeyPairGenerator/GenerateKeypair.java b/test/jdk/java/security/KeyPairGenerator/GenerateKeypair.java index 2c68e5954fa16..b2c87b1c38afc 100644 --- a/test/jdk/java/security/KeyPairGenerator/GenerateKeypair.java +++ b/test/jdk/java/security/KeyPairGenerator/GenerateKeypair.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 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 @@ -24,18 +24,21 @@ /* * @test * @bug 4221800 + * @library /test/lib * @summary Test restored generateKeyPair method */ import java.security.KeyPairGenerator; import java.security.KeyPair; +import jdk.test.lib.security.SecurityUtils; public class GenerateKeypair { public static void main(String[] args) throws Exception { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); - kpg.initialize(512); + String kpgAlgorithm = "DSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); // test generateKeyPair KeyPair kpair = kpg.generateKeyPair(); diff --git a/test/jdk/java/security/KeyPairGenerator/GenerateRSAKeyPair.java b/test/jdk/java/security/KeyPairGenerator/GenerateRSAKeyPair.java index eafd06ee3ec21..1b9ace546dcc5 100644 --- a/test/jdk/java/security/KeyPairGenerator/GenerateRSAKeyPair.java +++ b/test/jdk/java/security/KeyPairGenerator/GenerateRSAKeyPair.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 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,6 +24,7 @@ /* * @test * @bug 4297026 + * @library /test/lib * @summary Make sure that RSA Keypair generation using * java.security.spec.RSAKeyGenParameterSpec passes */ @@ -31,14 +32,18 @@ import java.security.KeyPairGenerator; import java.security.KeyPair; import java.security.spec.RSAKeyGenParameterSpec; +import jdk.test.lib.security.SecurityUtils; public class GenerateRSAKeyPair { public static void main(String[] args) throws Exception { + String kpgAlgorithm = "RSA"; RSAKeyGenParameterSpec rsaSpec = - new RSAKeyGenParameterSpec (1024, RSAKeyGenParameterSpec.F4); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SunRsaSign"); + new RSAKeyGenParameterSpec (SecurityUtils.getTestKeySize(kpgAlgorithm), + RSAKeyGenParameterSpec.F4); + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, + System.getProperty("test.provider.name", "SunRsaSign")); kpg.initialize(rsaSpec); // test generateKeyPair diff --git a/test/jdk/java/security/KeyRep/Serial.java b/test/jdk/java/security/KeyRep/Serial.java index 413aa10661a17..88c91a091e753 100644 --- a/test/jdk/java/security/KeyRep/Serial.java +++ b/test/jdk/java/security/KeyRep/Serial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 4532506 4999599 + * @library /test/lib * @summary Serializing KeyPair on one VM (Sun), * and Deserializing on another (IBM) fails * @run main/othervm/java.security.policy=Serial.policy Serial @@ -34,19 +35,22 @@ import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; +import jdk.test.lib.security.DiffieHellmanGroup; +import jdk.test.lib.security.SecurityUtils; public class Serial { // providers - private static final String SUN = "SUN"; - private static final String RSA = "SunRsaSign"; - private static final String JCE = "SunJCE"; + private static final String SUN = System.getProperty("test.provider.name", "SUN"); + private static final String RSA = System.getProperty("test.provider.name", "SunRsaSign"); + private static final String JCE = System.getProperty("test.provider.name", "SunJCE"); public static void main(String[] args) throws Exception { // generate DSA key pair - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", SUN); - kpg.initialize(512); + String kpgAlgorithmDsa = "DSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithmDsa, SUN); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithmDsa)); KeyPair dsaKp = kpg.genKeyPair(); // serialize DSA key pair @@ -67,8 +71,9 @@ public static void main(String[] args) throws Exception { } // generate RSA key pair - kpg = KeyPairGenerator.getInstance("RSA", RSA); - kpg.initialize(512); + String kpgAlgorithmRsa = "RSA"; + kpg = KeyPairGenerator.getInstance(kpgAlgorithmRsa, RSA); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithmRsa)); KeyPair rsaKp = kpg.genKeyPair(); // serialize RSA key pair @@ -89,8 +94,9 @@ public static void main(String[] args) throws Exception { } // generate DH key pair + DiffieHellmanGroup dhGroup = SecurityUtils.getTestDHGroup(); kpg = KeyPairGenerator.getInstance("DiffieHellman", JCE); - kpg.initialize(new DHParameterSpec(skip1024Modulus, skip1024Base)); + kpg.initialize(new DHParameterSpec(dhGroup.getPrime(), dhGroup.getBase())); KeyPair dhKp = kpg.genKeyPair(); // serialize DH key pair @@ -197,47 +203,4 @@ private static void checkKey(String algorithm, int size) throws Exception { throw new SecurityException(algorithm + " test failed"); } } - - // The 1024 bit Diffie-Hellman modulus values used by SKIP - private static final byte skip1024ModulusBytes[] = { - (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58, - (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD, - (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4, - (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B, - (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D, - (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C, - (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C, - (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6, - (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0, - (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B, - (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB, - (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D, - (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD, - (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43, - (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C, - (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C, - (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C, - (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40, - (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C, - (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72, - (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03, - (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29, - (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C, - (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB, - (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B, - (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08, - (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D, - (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C, - (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22, - (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB, - (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55, - (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7 - }; - - // The SKIP 1024 bit modulus - private static final BigInteger skip1024Modulus - = new BigInteger(1, skip1024ModulusBytes); - - // The base used with the SKIP 1024 bit modulus - private static final BigInteger skip1024Base = BigInteger.valueOf(2); } diff --git a/test/jdk/java/security/KeyRep/Serial.policy b/test/jdk/java/security/KeyRep/Serial.policy index 0c2c1d0868d6c..3c529c87a13f8 100644 --- a/test/jdk/java/security/KeyRep/Serial.policy +++ b/test/jdk/java/security/KeyRep/Serial.policy @@ -1,3 +1,4 @@ grant { + permission java.util.PropertyPermission "test.provider.name", "read"; // XXX note package access is *not* granted to the 'sun' package }; diff --git a/test/jdk/java/security/KeyStore/TestKeyStoreEntry.java b/test/jdk/java/security/KeyStore/TestKeyStoreEntry.java index d0aa21f8144d7..fde58a1cf3392 100644 --- a/test/jdk/java/security/KeyStore/TestKeyStoreEntry.java +++ b/test/jdk/java/security/KeyStore/TestKeyStoreEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ public class TestKeyStoreEntry { private static final char[] PASSWDF = new String("guardian Angel") .toCharArray(); private static final String[] KS_ALGOS = { - "DES", "DESede", "Blowfish" + "DES", "DESede", "Blowfish", "AES" }; private static final int NUM_ALGOS = KS_ALGOS.length; diff --git a/test/jdk/java/security/MessageDigest/ByteBuffers.java b/test/jdk/java/security/MessageDigest/ByteBuffers.java index dd3467d0e67bb..fc25b596d8691 100644 --- a/test/jdk/java/security/MessageDigest/ByteBuffers.java +++ b/test/jdk/java/security/MessageDigest/ByteBuffers.java @@ -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 @@ -27,6 +27,8 @@ * @summary Test the MessageDigest.update(ByteBuffer) method * @author Andreas Sterbenz * @key randomness + * @run main ByteBuffers MD5 + * @run main ByteBuffers SHA-1 */ import java.util.*; @@ -37,13 +39,14 @@ public class ByteBuffers { public static void main(String[] args) throws Exception { - Provider p = Security.getProvider("SUN"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SUN")); Random random = new Random(); int n = 10 * 1024; byte[] t = new byte[n]; random.nextBytes(t); - MessageDigest md = MessageDigest.getInstance("MD5", p); + String digestAlgo = args[0]; + MessageDigest md = MessageDigest.getInstance(digestAlgo, p); byte[] d1 = md.digest(t); // test 1: ByteBuffer with an accessible backing array diff --git a/test/jdk/java/security/MessageDigest/TestCloneable.java b/test/jdk/java/security/MessageDigest/TestCloneable.java index 3a4feb82ff6da..48236dbd447da 100644 --- a/test/jdk/java/security/MessageDigest/TestCloneable.java +++ b/test/jdk/java/security/MessageDigest/TestCloneable.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 @@ -43,14 +43,16 @@ public class TestCloneable { private static final Class CNSE = CloneNotSupportedException.class; + private static String providerName = System.getProperty("test.provider.name", "SUN"); + @DataProvider public Object[][] testData() { return new Object[][] { - { "MD2", "SUN" }, { "MD5", "SUN" }, { "SHA-1", "SUN" }, - { "SHA-224", "SUN" }, { "SHA-256", "SUN" }, - { "SHA-384", "SUN" }, { "SHA-512", "SUN" }, - { "SHA3-224", "SUN" }, { "SHA3-256", "SUN" }, - { "SHA3-384", "SUN" }, { "SHA3-512", "SUN" } + { "MD2", providerName }, { "MD5", providerName }, { "SHA-1", providerName }, + { "SHA-224", providerName }, { "SHA-256", providerName }, + { "SHA-384", providerName }, { "SHA-512", providerName }, + { "SHA3-224", providerName }, { "SHA3-256", providerName }, + { "SHA3-384", providerName }, { "SHA3-512", providerName } }; } diff --git a/test/jdk/java/security/Provider/SupportsParameter.java b/test/jdk/java/security/Provider/SupportsParameter.java index bc3cb031791ed..039fb3d079757 100644 --- a/test/jdk/java/security/Provider/SupportsParameter.java +++ b/test/jdk/java/security/Provider/SupportsParameter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, 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 @@ -24,6 +24,7 @@ /** * @test * @bug 4911081 8130181 + * @library /test/lib * @summary verify that Provider.Service.supportsParameter() works * @author Andreas Sterbenz */ @@ -33,12 +34,14 @@ import javax.crypto.*; import javax.crypto.spec.SecretKeySpec; +import jdk.test.lib.security.SecurityUtils; public class SupportsParameter { public static void main(String[] args) throws Exception { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); - kpg.initialize(512); + String kpgAlgorithm = "DSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair kp = kpg.generateKeyPair(); PublicKey dsaPublicKey = kp.getPublic(); PrivateKey dsaPrivateKey = kp.getPrivate(); diff --git a/test/jdk/java/security/SecureRandom/DefaultAlgo.java b/test/jdk/java/security/SecureRandom/DefaultAlgo.java index 06027f7162e7d..8f9e776f24653 100644 --- a/test/jdk/java/security/SecureRandom/DefaultAlgo.java +++ b/test/jdk/java/security/SecureRandom/DefaultAlgo.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 @@ -87,8 +87,9 @@ private static void checkDefault(Provider p, String ... algos) { p.remove("SecureRandom." + s); out.println("removed " + s); } - validate(new SecureRandom(), "SUN", - SunEntries.DEF_SECURE_RANDOM_ALGO); + validate(new SecureRandom(), System.getProperty("test.provider.name", "SUN"), + System.getProperty("test.default.secure.random.algorithm.name", + SunEntries.DEF_SECURE_RANDOM_ALGO)); } else { validate(new SecureRandom(), pName, algos[0]); } diff --git a/test/jdk/java/security/SecureRandom/DefaultProvider.java b/test/jdk/java/security/SecureRandom/DefaultProvider.java index c80700b78c9d2..b9a393bd34606 100644 --- a/test/jdk/java/security/SecureRandom/DefaultProvider.java +++ b/test/jdk/java/security/SecureRandom/DefaultProvider.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 @@ -42,7 +42,7 @@ public static void main(String[] args) throws NoSuchAlgorithmException { out.println("TEST: Default provider with constructor"); SecureRandom secureRandom = new SecureRandom(); String provider = secureRandom.getProvider().getName(); - if (!provider.equals("SUN")) { + if (!provider.equals(System.getProperty("test.provider.name", "SUN"))) { throw new RuntimeException("Unexpected provider name: " + provider); } @@ -51,7 +51,7 @@ public static void main(String[] args) throws NoSuchAlgorithmException { /* Test default provider with getInstance(String algorithm) */ out.println("TEST: SHA1PRNG supported on all platforms by SUN provider"); String algorithm = "SHA1PRNG"; - provider = "SUN"; + provider = System.getProperty("test.provider.name", "SUN"); SecureRandom instance = SecureRandom.getInstance(algorithm); assertInstance(instance, algorithm, provider); @@ -61,7 +61,7 @@ public static void main(String[] args) throws NoSuchAlgorithmException { out.println("TEST: NativePRNG supported on all platforms" + "(except Windows), by SUN provider"); algorithm = "NativePRNG"; - provider = "SUN"; + provider = System.getProperty("test.provider.name", "SUN"); } else { out.println( "TEST: Windows-PRNG supported on windows by SunMSCAPI provider"); diff --git a/test/jdk/java/security/SecureRandom/GetInstanceTest.java b/test/jdk/java/security/SecureRandom/GetInstanceTest.java index c1fdf1333057a..e95557a7bcbce 100644 --- a/test/jdk/java/security/SecureRandom/GetInstanceTest.java +++ b/test/jdk/java/security/SecureRandom/GetInstanceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,8 @@ public static void main(String[] args) throws Exception { + "'securerandom.strongAlgorithms'."); } try { - Security.setProperty(STRONG_ALG_SEC_PROP, "DRBG:SUN"); + Security.setProperty(STRONG_ALG_SEC_PROP, "DRBG:" + + System.getProperty("test.provider.name", SUN_PROVIDER)); sr = matchExc(() -> SecureRandom.getInstanceStrong(), PASS, NoSuchAlgorithmException.class, "PASS - Undefined security Property " @@ -123,7 +124,8 @@ private static void verifyInstance(String mech) throws Exception { // Test for getInstance(algorithm, provider) method. checkAttributes( matchExc(() -> SecureRandom.getInstance(srAlgo, - Security.getProvider(SUN_PROVIDER)), + Security.getProvider( + System.getProperty("test.provider.name", SUN_PROVIDER))), !(nsa(mech)), NoSuchAlgorithmException.class, String.format("PASS - It is expected to fail for" @@ -132,7 +134,8 @@ private static void verifyInstance(String mech) throws Exception { mech); // Test for getInstance(algorithm, providerName) method. checkAttributes( - matchExc(() -> SecureRandom.getInstance(srAlgo, SUN_PROVIDER), + matchExc(() -> SecureRandom.getInstance(srAlgo, + System.getProperty("test.provider.name", SUN_PROVIDER)), !(nsa(mech)), NoSuchAlgorithmException.class, String.format("PASS - It is expected to fail for " + "getInstance(algorithm, providerName) when " @@ -175,7 +178,8 @@ private static void verifyInstance(String mech) throws Exception { // Test for getInstance(algorithm, params, provider) method. checkAttributes( matchExc(() -> SecureRandom.getInstance(srAlgo, param, - Security.getProvider(SUN_PROVIDER)), + Security.getProvider(System.getProperty( + "test.provider.name", SUN_PROVIDER))), (isDRBG(mech)) && (isValidDRBGParam(param)), getExcType(mech, param), String.format("PASS - It is expected to fail " @@ -186,7 +190,7 @@ private static void verifyInstance(String mech) throws Exception { // Test for getInstance(algorithm, params, providerName) method. checkAttributes( matchExc(() -> SecureRandom.getInstance(srAlgo, param, - SUN_PROVIDER), + System.getProperty("test.provider.name", SUN_PROVIDER)), (isDRBG(mech)) && (isValidDRBGParam(param)), getExcType(mech, param), String.format("PASS - It is expected to fail " @@ -306,7 +310,8 @@ private static void checkAttributes(SecureRandom sr, String mech) { return; } Asserts.assertEquals(sr.getAlgorithm(), (isDRBG(mech) ? "DRBG" : mech)); - Asserts.assertEquals(sr.getProvider().getName(), SUN_PROVIDER); + String expectedProviderName = System.getProperty("test.provider.name", SUN_PROVIDER); + Asserts.assertEquals(sr.getProvider().getName(), expectedProviderName); } } diff --git a/test/jdk/java/security/Security/CaseInsensitiveAlgNames.java b/test/jdk/java/security/Security/CaseInsensitiveAlgNames.java index 2267c461e55c2..f29d368d6d10f 100644 --- a/test/jdk/java/security/Security/CaseInsensitiveAlgNames.java +++ b/test/jdk/java/security/Security/CaseInsensitiveAlgNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 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 @@ -41,10 +41,14 @@ public static void main(String[] args) md = MessageDigest.getInstance("shA1"); // MessageDigest with provider - md = MessageDigest.getInstance("SHA", "SUN"); - md = MessageDigest.getInstance("sha", "SUN"); - md = MessageDigest.getInstance("Sha-1", "SUN"); - md = MessageDigest.getInstance("shA1", "SUN"); + md = MessageDigest.getInstance("SHA", + System.getProperty("test.provider.name", "SUN")); + md = MessageDigest.getInstance("sha", + System.getProperty("test.provider.name", "SUN")); + md = MessageDigest.getInstance("Sha-1", + System.getProperty("test.provider.name", "SUN")); + md = MessageDigest.getInstance("shA1", + System.getProperty("test.provider.name", "SUN")); // KeyPairGenerator without provider KeyPairGenerator kGen = KeyPairGenerator.getInstance("DSA"); @@ -54,11 +58,15 @@ public static void main(String[] args) kGen = KeyPairGenerator.getInstance("1.2.840.10040.4.1"); // KeyPairGenerator with provider - kGen = KeyPairGenerator.getInstance("DSA", "SUN"); - kGen = KeyPairGenerator.getInstance("dsa", "SUN"); - kGen = KeyPairGenerator.getInstance("dSA", "SUN"); + kGen = KeyPairGenerator.getInstance("DSA", + System.getProperty("test.provider.name", "SUN")); + kGen = KeyPairGenerator.getInstance("dsa", + System.getProperty("test.provider.name", "SUN")); + kGen = KeyPairGenerator.getInstance("dSA", + System.getProperty("test.provider.name", "SUN")); kGen = KeyPairGenerator.getInstance("OId.1.2.840.10040.4.1", - "SUN"); - kGen = KeyPairGenerator.getInstance("1.2.840.10040.4.1", "SUN"); + System.getProperty("test.provider.name", "SUN")); + kGen = KeyPairGenerator.getInstance("1.2.840.10040.4.1", + System.getProperty("test.provider.name", "SUN")); } } diff --git a/test/jdk/java/security/Signature/ByteBuffers.java b/test/jdk/java/security/Signature/ByteBuffers.java index 937c9842c3b41..9f03a9923ecf1 100644 --- a/test/jdk/java/security/Signature/ByteBuffers.java +++ b/test/jdk/java/security/Signature/ByteBuffers.java @@ -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 @@ -27,6 +27,8 @@ * @summary Test the Signature.update(ByteBuffer) method * @author Andreas Sterbenz * @key randomness + * @run main ByteBuffers DSA 512 + * @run main ByteBuffers SHA256withDSA 2048 */ import java.util.*; @@ -37,17 +39,21 @@ public class ByteBuffers { public static void main(String[] args) throws Exception { - Provider p = Security.getProvider("SUN"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SUN")); Random random = new Random(); int n = 10 * 1024; byte[] t = new byte[n]; random.nextBytes(t); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", p); - kpg.initialize(512); + String kpgAlgorithm = "DSA"; + int keySize = Integer.parseInt(args[1]); + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, p); + kpg.initialize(keySize); KeyPair kp = kpg.generateKeyPair(); - Signature sig = Signature.getInstance("DSA", p); + String signAlgo = args[0]; + Signature sig = Signature.getInstance(signAlgo, p); sig.initSign(kp.getPrivate()); sig.update(t); byte[] signature = sig.sign(); diff --git a/test/jdk/java/security/Signature/NONEwithRSA.java b/test/jdk/java/security/Signature/NONEwithRSA.java index 6d18c7ac96f1c..c7b08528e7efc 100644 --- a/test/jdk/java/security/Signature/NONEwithRSA.java +++ b/test/jdk/java/security/Signature/NONEwithRSA.java @@ -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 @@ -24,6 +24,7 @@ /** * @test * @bug 4955844 + * @library /test/lib * @summary ensure that the NONEwithRSA adapter works correctly * @author Andreas Sterbenz * @key randomness @@ -34,17 +35,19 @@ import java.security.*; import javax.crypto.*; +import jdk.test.lib.security.SecurityUtils; public class NONEwithRSA { public static void main(String[] args) throws Exception { -// showProvider(Security.getProvider("SUN")); +// showProvider(Security.getProvider(System.getProperty("test.provider.name", "SUN"))); Random random = new Random(); byte[] b = new byte[16]; random.nextBytes(b); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); - kpg.initialize(512); + String kpgAlgorithm = "RSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair kp = kpg.generateKeyPair(); Signature sig = Signature.getInstance("NONEwithRSA"); @@ -66,9 +69,11 @@ public static void main(String[] args) throws Exception { throw new Exception("decryption failed"); } - sig = Signature.getInstance("NONEwithRSA", "SunJCE"); + sig = Signature.getInstance("NONEwithRSA", + System.getProperty("test.provider.name", "SunJCE")); sig.initSign(kp.getPrivate()); - sig = Signature.getInstance("NONEwithRSA", Security.getProvider("SunJCE")); + sig = Signature.getInstance("NONEwithRSA", Security.getProvider( + System.getProperty("test.provider.name", "SunJCE"))); sig.initSign(kp.getPrivate()); try { diff --git a/test/jdk/java/security/Signature/ResetAfterException.java b/test/jdk/java/security/Signature/ResetAfterException.java index 62d5c190becc7..39c766ac63df5 100644 --- a/test/jdk/java/security/Signature/ResetAfterException.java +++ b/test/jdk/java/security/Signature/ResetAfterException.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 @@ -24,10 +24,12 @@ /** * @test * @bug 8149802 + * @library /test/lib * @summary Ensure that Signature objects are reset after verification errored out. */ import java.util.Arrays; import java.security.*; +import jdk.test.lib.security.SecurityUtils; public class ResetAfterException { @@ -51,18 +53,19 @@ public static void main(String[] args) throws Exception { boolean res = true; System.out.println("Testing Provider: " + p.getName()); KeyPairGenerator keyGen = null; + String kpgAlgorithm = "RSA"; try { // It's possible that some provider, e.g. SunMSCAPI, // doesn't work well with keys from other providers // so we use the same provider to generate key first - keyGen = KeyPairGenerator.getInstance("RSA", p); + keyGen = KeyPairGenerator.getInstance(kpgAlgorithm, p); } catch (NoSuchAlgorithmException nsae) { - keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen = KeyPairGenerator.getInstance(kpgAlgorithm); } if (keyGen == null) { throw new RuntimeException("Error: No support for RSA KeyPairGenerator"); } - keyGen.initialize(1024); + keyGen.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair keyPair = keyGen.generateKeyPair(); sig.initSign(keyPair.getPrivate()); diff --git a/test/jdk/java/security/Signature/SignWithOutputBuffer.java b/test/jdk/java/security/Signature/SignWithOutputBuffer.java index 5f4716391a7a7..0fcc0405f7c0a 100644 --- a/test/jdk/java/security/Signature/SignWithOutputBuffer.java +++ b/test/jdk/java/security/Signature/SignWithOutputBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 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 @@ -26,6 +26,8 @@ * @bug 4114896 * @summary Signature should support a sign() method that places the signature * in an already existing array. + * @run main SignWithOutputBuffer DSS 512 + * @run main SignWithOutputBuffer SHA256withDSA 2048 */ import java.security.*; @@ -36,11 +38,14 @@ public static void main(String[] args) throws Exception { int numBytes; - KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DSA"); - kpGen.initialize(512); + String kpgAlgorithm = "DSA"; + int keySize = Integer.parseInt(args[1]); + KeyPairGenerator kpGen = KeyPairGenerator.getInstance(kpgAlgorithm); + kpGen.initialize(keySize); KeyPair kp = kpGen.genKeyPair(); - Signature sig = Signature.getInstance("DSS"); + String signAlgo = args[0]; + Signature sig = Signature.getInstance(signAlgo); sig.initSign(kp.getPrivate()); sig.update((byte)0xff); @@ -55,10 +60,10 @@ public static void main(String[] args) throws Exception { } // Now repeat the same with a buffer that's big enough - sig = Signature.getInstance("DSS"); + sig = Signature.getInstance(signAlgo); sig.initSign(kp.getPrivate()); sig.update((byte)0xff); - out = new byte[48]; + out = new byte[64]; numBytes = sig.sign(out, 0, out.length); System.out.println("Signature len="+numBytes); diff --git a/test/jdk/java/security/Signature/SignatureGetInstance.java b/test/jdk/java/security/Signature/SignatureGetInstance.java index c246773f83ace..821c20602a7c2 100644 --- a/test/jdk/java/security/Signature/SignatureGetInstance.java +++ b/test/jdk/java/security/Signature/SignatureGetInstance.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 @@ -27,7 +27,8 @@ * @summary Ensure the BC provider-reselection workaround in Signature class * functions correctly * @modules java.base/sun.security.util - * @run main/othervm SignatureGetInstance + * @run main/othervm SignatureGetInstance default + * @run main/othervm SignatureGetInstance SHA-256 */ import java.security.*; import java.security.interfaces.*; @@ -37,8 +38,12 @@ public class SignatureGetInstance { private static final String SIGALG = "RSASSA-PSS"; + private static PSSParameterSpec pssParamSpec; public static void main(String[] args) throws Exception { + String mdName = args[0]; + pssParamSpec = "default".equals(mdName) ? PSSParameterSpec.DEFAULT : + new PSSParameterSpec(mdName, "MGF1", new MGF1ParameterSpec(mdName), 20, 1); Provider testProvider = new TestProvider(); // put test provider before SunRsaSign provider Security.insertProviderAt(testProvider, 1); @@ -50,7 +55,8 @@ public static void main(String[] args) throws Exception { MyPubKey testPub = new MyPubKey(); testDblInit(testPriv, testPub, true, "TestProvider"); - testDblInit(kp.getPrivate(), kp.getPublic(), true, "SunRsaSign"); + testDblInit(kp.getPrivate(), kp.getPublic(), true, + System.getProperty("test.provider.name", "SunRsaSign")); testDblInit(testPriv, kp.getPublic(), false, null); testDblInit(kp.getPrivate(), testPub, false, null); @@ -59,7 +65,7 @@ public static void main(String[] args) throws Exception { testSetAndInit(null, kp.getPrivate(), true); testSetAndInit(null, kp.getPublic(), true); - String provName = "SunRsaSign"; + String provName = System.getProperty("test.provider.name", "SunRsaSign"); testSetAndInit(provName, testPriv, false); testSetAndInit(provName, testPub, false); testSetAndInit(provName, kp.getPrivate(), true); @@ -84,7 +90,7 @@ private static void checkName(Signature s, String name) { private static void testDblInit(PrivateKey key1, PublicKey key2, boolean shouldPass, String expectedProvName) throws Exception { Signature sig = Signature.getInstance(SIGALG); - SignatureUtil.initSignWithParam(sig, key1, PSSParameterSpec.DEFAULT, null); + SignatureUtil.initSignWithParam(sig, key1, pssParamSpec, null); try { sig.initVerify(key2); if (!shouldPass) { @@ -107,7 +113,7 @@ private static void testSetAndInit(String provName, Key key, } else { sig = Signature.getInstance(SIGALG, provName); } - AlgorithmParameterSpec params = PSSParameterSpec.DEFAULT; + AlgorithmParameterSpec params = pssParamSpec; boolean doSign = (key instanceof PrivateKey); try { if (doSign) { diff --git a/test/jdk/java/security/Signature/TestCloneable.java b/test/jdk/java/security/Signature/TestCloneable.java index 33e2383cfa40e..97f69a8725b12 100644 --- a/test/jdk/java/security/Signature/TestCloneable.java +++ b/test/jdk/java/security/Signature/TestCloneable.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 @@ -42,21 +42,25 @@ public class TestCloneable { @DataProvider public Object[][] testData() { + String dsaProviderName = System.getProperty("test.provider.name", "SUN"); + String ecProviderName = System.getProperty("test.provider.name", "SunEC"); + String rsaProviderName = System.getProperty("test.provider.name", "SunRsaSign"); + return new Object[][] { - { "SHA1withDSA", "SUN" }, { "NONEwithDSA", "SUN" }, - { "SHA224withDSA", "SUN" }, { "SHA256withDSA", "SUN" }, - { "EdDSA", "SunEC" }, { "Ed25519", "SunEC" }, { "Ed448", "SunEC" }, - { "SHA1withECDSA", "SunEC" }, { "SHA224withECDSA", "SunEC" }, - { "SHA256withECDSA", "SunEC" }, { "SHA384withECDSA", "SunEC" }, - { "SHA512withECDSA", "SunEC" }, { "NONEwithECDSA", "SunEC" }, - { "MD2withRSA", "SunRsaSign" }, { "MD5withRSA", "SunRsaSign" }, - { "SHA1withRSA", "SunRsaSign" }, { "SHA224withRSA", "SunRsaSign" }, - { "SHA256withRSA", "SunRsaSign" }, - { "SHA384withRSA", "SunRsaSign" }, - { "SHA512withRSA", "SunRsaSign" }, - { "SHA512/224withRSA", "SunRsaSign" }, - { "SHA512/256withRSA", "SunRsaSign" }, - { "RSASSA-PSS", "SunRsaSign" }, + { "SHA1withDSA", dsaProviderName }, { "NONEwithDSA", dsaProviderName }, + { "SHA224withDSA", dsaProviderName }, { "SHA256withDSA", dsaProviderName }, + { "EdDSA", ecProviderName }, { "Ed25519", ecProviderName }, { "Ed448", ecProviderName }, + { "SHA1withECDSA", ecProviderName }, { "SHA224withECDSA", ecProviderName }, + { "SHA256withECDSA", ecProviderName }, { "SHA384withECDSA", ecProviderName }, + { "SHA512withECDSA", ecProviderName }, { "NONEwithECDSA", ecProviderName }, + { "MD2withRSA", rsaProviderName }, { "MD5withRSA", rsaProviderName }, + { "SHA1withRSA", rsaProviderName }, { "SHA224withRSA", rsaProviderName }, + { "SHA256withRSA", rsaProviderName }, + { "SHA384withRSA", rsaProviderName }, + { "SHA512withRSA", rsaProviderName }, + { "SHA512/224withRSA", rsaProviderName }, + { "SHA512/256withRSA", rsaProviderName }, + { "RSASSA-PSS", rsaProviderName }, { "NONEwithRSA", "SunMSCAPI" }, { "SHA1withRSA", "SunMSCAPI" }, { "SHA256withRSA", "SunMSCAPI" }, { "SHA384withRSA", "SunMSCAPI" }, { "SHA512withRSA", "SunMSCAPI" }, diff --git a/test/jdk/java/security/Signature/TestInitSignWithMyOwnRandom.java b/test/jdk/java/security/Signature/TestInitSignWithMyOwnRandom.java index 0d2d7fd35a4e0..ac4199ec771cc 100644 --- a/test/jdk/java/security/Signature/TestInitSignWithMyOwnRandom.java +++ b/test/jdk/java/security/Signature/TestInitSignWithMyOwnRandom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,22 +24,30 @@ /** * @test * @bug 4716321 + * @library /test/lib * @summary Ensure the random source supplied in * Signature.initSign(PrivateKey, SecureRandom) is used. + * @run main TestInitSignWithMyOwnRandom DSA 512 + * @run main TestInitSignWithMyOwnRandom SHA256withDSA 2048 */ import java.security.*; +import jdk.test.lib.security.SecurityUtils; public class TestInitSignWithMyOwnRandom { - public static void main(String[] argv) throws Exception { + public static void main(String[] args) throws Exception { // any signature implementation will do as long as // it needs a random source - Provider p = Security.getProvider("SUN"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", p); - kpg.initialize(512); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SUN")); + String kpgAlgorithm = "DSA"; + int keySize = Integer.parseInt(args[1]); + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, p); + kpg.initialize(keySize); KeyPair kp = kpg.generateKeyPair(); TestRandomSource rand = new TestRandomSource(); - Signature sig = Signature.getInstance("DSA", p); + String signAlgo = args[0]; + Signature sig = Signature.getInstance(signAlgo, p); sig.initSign(kp.getPrivate(), rand); sig.update(new byte[20]); sig.sign(); diff --git a/test/jdk/java/security/Signature/VerifyRangeCheckOverflow.java b/test/jdk/java/security/Signature/VerifyRangeCheckOverflow.java index b68d8ca9be739..397d793327447 100644 --- a/test/jdk/java/security/Signature/VerifyRangeCheckOverflow.java +++ b/test/jdk/java/security/Signature/VerifyRangeCheckOverflow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 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,6 +27,7 @@ /* @test * @bug 7172149 + * @library /test/lib * @summary AIOOBE from Signature.verify after integer overflow * @author Jonathan Lu */ @@ -35,17 +36,19 @@ import java.security.KeyPairGenerator; import java.security.PublicKey; import java.security.Signature; +import jdk.test.lib.security.SecurityUtils; public class VerifyRangeCheckOverflow { public static void main(String[] args) throws Exception { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA"); - keyPairGenerator.initialize(1024); + String kpgAlgorithm = "DSA"; + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(kpgAlgorithm); + keyPairGenerator.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair keys = keyPairGenerator.generateKeyPair(); PublicKey publicKey = keys.getPublic(); byte[] sigBytes = new byte[100]; - Signature signature = Signature.getInstance("SHA1withDSA"); + Signature signature = Signature.getInstance("SHA256withDSA"); signature.initVerify(publicKey); try { signature.verify(sigBytes, Integer.MAX_VALUE, 1); diff --git a/test/jdk/java/security/SignedObject/Chain.java b/test/jdk/java/security/SignedObject/Chain.java index b4a5ea794e6bc..883ac13890d2e 100644 --- a/test/jdk/java/security/SignedObject/Chain.java +++ b/test/jdk/java/security/SignedObject/Chain.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 @@ -55,7 +55,10 @@ static enum Provider { Sun("SUN"), SunEC("SunEC"), SunJSSE("SunJSSE"), - SunMSCAPI("SunMSCAPI"); + SunMSCAPI("SunMSCAPI"), + TestProvider_or_SunRsaSign(System.getProperty("test.provider.name", "SunRsaSign")), + TestProvider_or_Sun(System.getProperty("test.provider.name", "SUN")), + TestProvider_or_SunEC(System.getProperty("test.provider.name", "SunEC")); final String name; @@ -162,13 +165,15 @@ public String toString() { new Test(SigAlg.SHA1withDSA, KeyAlg.DSA, Provider.Default, 1024), new Test(SigAlg.MD2withRSA, KeyAlg.RSA, Provider.Default), new Test(SigAlg.MD5withRSA, KeyAlg.RSA, Provider.Default), + new Test(SigAlg.SHA224withRSA, KeyAlg.RSA, Provider.Default), + new Test(SigAlg.SHA256withRSA, KeyAlg.RSA, Provider.Default), new Test(SigAlg.SHA3_224withRSA, KeyAlg.RSA, Provider.Default), new Test(SigAlg.SHA3_256withRSA, KeyAlg.RSA, Provider.Default), new Test(SigAlg.SHA3_384withRSA, KeyAlg.RSA, Provider.Default), new Test(SigAlg.SHA3_512withRSA, KeyAlg.RSA, Provider.Default), - new Test(SigAlg.SHA1withDSA, KeyAlg.DSA, Provider.Sun, 1024), - new Test(SigAlg.SHA224withDSA, KeyAlg.DSA, Provider.Sun, 2048), - new Test(SigAlg.SHA256withDSA, KeyAlg.DSA, Provider.Sun, 2048), + new Test(SigAlg.SHA1withDSA, KeyAlg.DSA, Provider.TestProvider_or_Sun, 1024), + new Test(SigAlg.SHA224withDSA, KeyAlg.DSA, Provider.TestProvider_or_Sun, 2048), + new Test(SigAlg.SHA256withDSA, KeyAlg.DSA, Provider.TestProvider_or_Sun, 2048), }; private static final String str = "to-be-signed"; @@ -190,7 +195,7 @@ private static boolean runTestPSS(int keysize) { Iterator mdAlgs = SigTestUtil.getDigestAlgorithms (SignatureType.RSASSA_PSS, keysize).iterator(); while (mdAlgs.hasNext()) { - result &= runTest(new Test(pss, KeyAlg.RSA, Provider.SunRsaSign, + result &= runTest(new Test(pss, KeyAlg.RSA, Provider.TestProvider_or_SunRsaSign, keysize, SigTestUtil.generateDefaultParameter (SignatureType.RSASSA_PSS, mdAlgs.next()))); } diff --git a/test/jdk/java/security/SignedObject/Copy.java b/test/jdk/java/security/SignedObject/Copy.java index b6edfc031fc7d..3e36891173a11 100644 --- a/test/jdk/java/security/SignedObject/Copy.java +++ b/test/jdk/java/security/SignedObject/Copy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,31 +31,35 @@ * @test * @bug 8050374 * @summary Checks if a signed object is a copy of an original object + * @run main Copy DSA 512 + * @run main Copy SHA256withDSA 2048 */ public class Copy { private static final String DSA = "DSA"; - private static final int KEY_SIZE = 512; private static final int MAGIC = 123; public static void main(String args[]) throws Exception { + int keySize = Integer.parseInt(args[1]); KeyPairGenerator kg = KeyPairGenerator.getInstance(DSA); - kg.initialize(KEY_SIZE); + kg.initialize(keySize); KeyPair kp = kg.genKeyPair(); - Signature signature = Signature.getInstance(DSA); + String signAlgo = args[0]; + Signature signature = Signature.getInstance(signAlgo); Test original = new Test(); SignedObject so = new SignedObject(original, kp.getPrivate(), signature); System.out.println("Signature algorithm: " + so.getAlgorithm()); - signature = Signature.getInstance(DSA, "SUN"); + signature = Signature.getInstance(signAlgo, + System.getProperty("test.provider.name", "SUN")); if (!so.verify(kp.getPublic(), signature)) { throw new RuntimeException("Verification failed"); } kg = KeyPairGenerator.getInstance(DSA); - kg.initialize(KEY_SIZE); + kg.initialize(keySize); kp = kg.genKeyPair(); if (so.verify(kp.getPublic(), signature)) { diff --git a/test/jdk/java/security/cert/X509Certificate/GetSigAlgParams.java b/test/jdk/java/security/cert/X509Certificate/GetSigAlgParams.java index 6d7a834561748..4867058c4c289 100644 --- a/test/jdk/java/security/cert/X509Certificate/GetSigAlgParams.java +++ b/test/jdk/java/security/cert/X509Certificate/GetSigAlgParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,12 +24,14 @@ /* * @test * @bug 8259428 + * @library /test/lib * @summary Verify X509Certificate.getSigAlgParams() returns new array each * time it is called * @modules java.base/sun.security.tools.keytool java.base/sun.security.x509 */ import java.security.cert.X509Certificate; +import jdk.test.lib.security.SecurityUtils; import sun.security.tools.keytool.CertAndKeyGen; import sun.security.x509.X500Name; @@ -38,7 +40,7 @@ public class GetSigAlgParams { public static void main(String[] args) throws Exception { CertAndKeyGen cakg = new CertAndKeyGen("RSASSA-PSS", "RSASSA-PSS"); - cakg.generate(1024); + cakg.generate(SecurityUtils.getTestKeySize("RSA")); X509Certificate c = cakg.getSelfCertificate(new X500Name("CN=Me"), 100); if (c.getSigAlgParams() == c.getSigAlgParams()) { throw new Exception("Encoded params are the same byte array"); diff --git a/test/jdk/java/security/misc/GetInstanceNullsEmpties.java b/test/jdk/java/security/misc/GetInstanceNullsEmpties.java index 75089208fa80d..9fb1d43e6edd0 100644 --- a/test/jdk/java/security/misc/GetInstanceNullsEmpties.java +++ b/test/jdk/java/security/misc/GetInstanceNullsEmpties.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 @@ -44,7 +44,8 @@ */ public class GetInstanceNullsEmpties { - private static final Provider SUN = Security.getProvider("SUN"); + private static final String providerName = System.getProperty("test.provider.name", "SUN"); + private static final Provider provider = Security.getProvider(providerName); /* * See if there are more than "expected" number of getInstance() methods, @@ -168,14 +169,14 @@ private static void testAlgorithmParameterGenerator() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -190,14 +191,14 @@ private static void testAlgorithmParameters() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -212,14 +213,14 @@ private static void testCertPathBuilder() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -234,14 +235,14 @@ private static void testCertPathValidator() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -257,14 +258,14 @@ private static void testCertStore() throws Exception { run(m, NoSuchAlgorithmException.class, "", csp); m = getInstance(clazz, STRING, CertStoreParameters.class, STRING); - run(m, NullPointerException.class, null, csp, "SUN"); - run(m, NoSuchAlgorithmException.class, "", csp, "SUN"); + run(m, NullPointerException.class, null, csp, providerName); + run(m, NoSuchAlgorithmException.class, "", csp, providerName); run(m, IllegalArgumentException.class, "FOO", csp, null); run(m, IllegalArgumentException.class, "FOO", csp, ""); m = getInstance(clazz, STRING, CertStoreParameters.class, PROVIDER); - run(m, NullPointerException.class, null, csp, SUN); - run(m, NoSuchAlgorithmException.class, "", csp, SUN); + run(m, NullPointerException.class, null, csp, provider); + run(m, NoSuchAlgorithmException.class, "", csp, provider); run(m, IllegalArgumentException.class, "FOO", csp, null); } @@ -279,14 +280,14 @@ private static void testCertificateFactory() throws Exception { run(m, CertificateException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, CertificateException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, CertificateException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, CertificateException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, CertificateException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -305,14 +306,14 @@ private static void testCipher() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NoSuchAlgorithmException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NoSuchAlgorithmException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NoSuchAlgorithmException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NoSuchAlgorithmException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -329,15 +330,15 @@ private static void testConfiguration() throws Exception { run(m, NoSuchAlgorithmException.class, "", cp); m = getInstance(clazz, STRING, Configuration.Parameters.class, STRING); - run(m, NullPointerException.class, null, cp, "SUN"); - run(m, NoSuchAlgorithmException.class, "", cp, "SUN"); + run(m, NullPointerException.class, null, cp, providerName); + run(m, NoSuchAlgorithmException.class, "", cp, providerName); run(m, IllegalArgumentException.class, "FOO", cp, null); run(m, IllegalArgumentException.class, "FOO", cp, ""); m = getInstance(clazz, STRING, Configuration.Parameters.class, PROVIDER); - run(m, NullPointerException.class, null, cp, SUN); - run(m, NoSuchAlgorithmException.class, "", cp, SUN); + run(m, NullPointerException.class, null, cp, provider); + run(m, NoSuchAlgorithmException.class, "", cp, provider); run(m, IllegalArgumentException.class, "FOO", cp, null); } @@ -352,14 +353,14 @@ private static void testExemptionMechanism() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -374,14 +375,14 @@ private static void testKeyAgreement() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -396,14 +397,14 @@ private static void testKeyFactory() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -418,14 +419,14 @@ private static void testKeyGenerator() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -440,14 +441,14 @@ private static void testKeyManagerFactory() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -462,14 +463,14 @@ private static void testKeyPairGenerator() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -488,14 +489,14 @@ private static void testKeyStore() throws Exception { run(m, KeyStoreException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, KeyStoreException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, KeyStoreException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, KeyStoreException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, KeyStoreException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -510,14 +511,14 @@ private static void testMac() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -532,14 +533,14 @@ private static void testMessageDigest() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -556,14 +557,14 @@ private static void testPolicy() throws Exception { run(m, NoSuchAlgorithmException.class, "", pp); m = getInstance(clazz, STRING, Policy.Parameters.class, STRING); - run(m, NullPointerException.class, null, pp, "SUN"); - run(m, NoSuchAlgorithmException.class, "", pp, "SUN"); + run(m, NullPointerException.class, null, pp, providerName); + run(m, NoSuchAlgorithmException.class, "", pp, providerName); run(m, IllegalArgumentException.class, "FOO", pp, null); run(m, IllegalArgumentException.class, "FOO", pp, ""); m = getInstance(clazz, STRING, Policy.Parameters.class, PROVIDER); - run(m, NullPointerException.class, null, pp, SUN); - run(m, NoSuchAlgorithmException.class, "", pp, SUN); + run(m, NullPointerException.class, null, pp, provider); + run(m, NoSuchAlgorithmException.class, "", pp, provider); run(m, IllegalArgumentException.class, "FOO", pp, null); } @@ -578,14 +579,14 @@ private static void testSSLContext() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -600,14 +601,14 @@ private static void testSecretKeyFactory() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -624,14 +625,14 @@ private static void testSecureRandom() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); m = getInstance(clazz, STRING, SecureRandomParameters.class); @@ -639,14 +640,14 @@ private static void testSecureRandom() throws Exception { run(m, NoSuchAlgorithmException.class, "", srp); m = getInstance(clazz, STRING, SecureRandomParameters.class, STRING); - run(m, NullPointerException.class, null, srp, "SUN"); - run(m, NoSuchAlgorithmException.class, "", srp, "SUN"); + run(m, NullPointerException.class, null, srp, providerName); + run(m, NoSuchAlgorithmException.class, "", srp, providerName); run(m, IllegalArgumentException.class, "FOO", srp, null); run(m, IllegalArgumentException.class, "FOO", srp, ""); m = getInstance(clazz, STRING, SecureRandomParameters.class, PROVIDER); - run(m, NullPointerException.class, null, srp, SUN); - run(m, NoSuchAlgorithmException.class, "", srp, SUN); + run(m, NullPointerException.class, null, srp, provider); + run(m, NoSuchAlgorithmException.class, "", srp, provider); run(m, IllegalArgumentException.class, "FOO", srp, null); } @@ -661,14 +662,14 @@ private static void testSignature() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } @@ -683,14 +684,14 @@ private static void testTrustManagerFactory() throws Exception { run(m, NoSuchAlgorithmException.class, ""); m = getInstance(clazz, STRING, STRING); - run(m, NullPointerException.class, null, "SUN"); - run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, NullPointerException.class, null, providerName); + run(m, NoSuchAlgorithmException.class, "", providerName); run(m, IllegalArgumentException.class, "FOO", null); run(m, IllegalArgumentException.class, "FOO", ""); m = getInstance(clazz, STRING, PROVIDER); - run(m, NullPointerException.class, null, SUN); - run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, NullPointerException.class, null, provider); + run(m, NoSuchAlgorithmException.class, "", provider); run(m, IllegalArgumentException.class, "FOO", null); } } diff --git a/test/jdk/java/text/Format/DateFormat/TimeZoneNameTest.java b/test/jdk/java/text/Format/DateFormat/TimeZoneNameTest.java index 8ce11445ca0e0..e74bd41ddf9f6 100644 --- a/test/jdk/java/text/Format/DateFormat/TimeZoneNameTest.java +++ b/test/jdk/java/text/Format/DateFormat/TimeZoneNameTest.java @@ -75,7 +75,7 @@ static void initAll() { "N", "GMT", "GMT", "Greenwich Mean Time", "GMT", "Greenwich Mean Time", "N", "Europe/London", "GMT", "Greenwich Mean Time", "BST", "British Summer Time", "N", "Europe/Paris", "CET", "Central European Standard Time", "CEST", "Central European Summer Time", - "N", "WET", "WET", "GMT", "WEST", "GMT+01:00", + "N", "WET", "WET", "Western European Standard Time", "WEST", "Western European Summer Time", "N", "Europe/Berlin", "CET", "Central European Standard Time", "CEST", "Central European Summer Time", "N", "Asia/Jerusalem", "IST", "Israel Standard Time", "IDT", "Israel Daylight Time", "N", "Europe/Helsinki", "EET", "Eastern European Standard Time", "EEST", "Eastern European Summer Time", diff --git a/test/jdk/java/text/Format/DecimalFormat/SettersShouldThrowNPETest.java b/test/jdk/java/text/Format/DecimalFormat/SettersShouldThrowNPETest.java new file mode 100644 index 0000000000000..b09c9102833b3 --- /dev/null +++ b/test/jdk/java/text/Format/DecimalFormat/SettersShouldThrowNPETest.java @@ -0,0 +1,109 @@ +/* + * 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 8341445 + * @summary DFS setters should throw NPE. This ensures that NPE is not thrown + * by equals(). + * @run junit SettersShouldThrowNPETest + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.text.DecimalFormatSymbols; +import java.util.Arrays; +import java.util.Currency; +import java.util.List; +import java.util.Locale; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class SettersShouldThrowNPETest { + + // The public setter methods that should throw NPE + private static final List NPE_SETTERS = + Arrays.stream(DecimalFormatSymbols.class.getDeclaredMethods()) + .filter(m -> Modifier.isPublic(m.getModifiers()) + && m.getName().startsWith("set") + && Stream.of(m.getParameterTypes()).noneMatch(Class::isPrimitive)) + .toList(); + + // Non-primitive setters should throw NPE + @ParameterizedTest + @MethodSource("setters") + public void settersThrowNPETest(Method m) { + var dfs = new DecimalFormatSymbols(); + InvocationTargetException e = + assertThrows(InvocationTargetException.class, () -> m.invoke(dfs, (Object) null)); + if (!(e.getCause() instanceof NullPointerException)) { + throw new RuntimeException(e.getCause() + " was thrown instead of NPE by : " + m); + } + } + + // Currency fields are lazy and can be null + // Ensure when exposed to users, they are never null + @ParameterizedTest + @MethodSource("locales") + public void lazyCurrencyFieldsTest(Locale locale) { + var dfs = new DecimalFormatSymbols(locale); + assertDoesNotThrow(() -> dfs.equals(new DecimalFormatSymbols())); + assertNotNull(dfs.getCurrency()); + assertNotNull(dfs.getInternationalCurrencySymbol()); + assertNotNull(dfs.getCurrencySymbol()); + } + + // Prior to 8341445, if the international currency symbol was invalid, + // the currency attribute was set to null. However, we should not have null + // currency fields post initializeCurrency() call. Ensure invalid code + // does not update the other fields. + @Test + public void setInternationalCurrencySymbolFallbackTest() { + var code = "fooBarBazQux"; + // initialize() should provide null for all currency related fields + var dfs = new DecimalFormatSymbols(Locale.ROOT); + // Load the fallbacks via initCurrency() since the loc is Locale.ROOT + dfs.setInternationalCurrencySymbol(code); // set invalid code + // Ensure our values are the expected fallbacks, minus the updated intl code + assertEquals(Currency.getInstance("XXX"), dfs.getCurrency()); + assertEquals("\u00A4", dfs.getCurrencySymbol()); + assertEquals("fooBarBazQux", dfs.getInternationalCurrencySymbol()); + } + + private static List setters() { + return NPE_SETTERS; + } + + private static List locales() { + return List.of(Locale.ROOT, Locale.US, Locale.forLanguageTag("XXX")); + } +} diff --git a/test/jdk/java/text/Format/MessageFormat/MaxArgumentIndexTest.java b/test/jdk/java/text/Format/MessageFormat/MaxArgumentIndexTest.java new file mode 100644 index 0000000000000..e12dabb638388 --- /dev/null +++ b/test/jdk/java/text/Format/MessageFormat/MaxArgumentIndexTest.java @@ -0,0 +1,97 @@ +/* + * 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 8331446 + * @summary Enforce the MAX_ARGUMENT_INDEX(10,000) implementation limit for the + * ArgumentIndex element in the MessageFormat pattern syntax. This + * should be checked during construction/applyPattern/readObject and should effectively + * prevent parse/format from being invoked with values over the limit. + * @run junit MaxArgumentIndexTest + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class MaxArgumentIndexTest { + + // A MessageFormat pattern that contains an ArgumentIndex value + // which violates this implementation's limit: MAX_ARGUMENT_INDEX(10,000) + // As this check is exclusive, 10,000 will violate the limit + private static final String VIOLATES_MAX_ARGUMENT_INDEX = "{10000}"; + + // Check String constructor enforces the limit + @Test + public void constructorTest() { + assertThrows(IllegalArgumentException.class, + () -> new MessageFormat(VIOLATES_MAX_ARGUMENT_INDEX)); + } + + // Check String, Locale constructor enforces the limit + @ParameterizedTest + @MethodSource + public void constructorWithLocaleTest(Locale locale) { + assertThrows(IllegalArgumentException.class, + () -> new MessageFormat(VIOLATES_MAX_ARGUMENT_INDEX, locale)); + } + + // Provide some basic common locale values + private static Stream constructorWithLocaleTest() { + return Stream.of(null, Locale.US, Locale.ROOT); + } + + // Edge case: Test a locale dependent subformat (with null locale) with a + // violating ArgumentIndex. In this instance, the violating ArgumentIndex + // will be caught and IAE thrown instead of the NPE + @Test + public void localeDependentSubFormatTest() { + assertThrows(IllegalArgumentException.class, + () -> new MessageFormat("{10000,number,short}", null)); + // For reference + assertThrows(NullPointerException.class, + () -> new MessageFormat("{999,number,short}", null)); + } + + // Check that the static format method enforces the limit + @Test + public void staticFormatTest() { + assertThrows(IllegalArgumentException.class, + () -> MessageFormat.format(VIOLATES_MAX_ARGUMENT_INDEX, new Object[]{1})); + } + + // Check that applyPattern(String) enforces the limit + @Test + public void applyPatternTest() { + MessageFormat mf = new MessageFormat(""); + assertThrows(IllegalArgumentException.class, + () -> mf.applyPattern(VIOLATES_MAX_ARGUMENT_INDEX)); + } +} diff --git a/test/jdk/java/text/Format/MessageFormat/SerializationTest.java b/test/jdk/java/text/Format/MessageFormat/SerializationTest.java new file mode 100644 index 0000000000000..ac5fd4d56a7c4 --- /dev/null +++ b/test/jdk/java/text/Format/MessageFormat/SerializationTest.java @@ -0,0 +1,102 @@ +/* + * 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 8331446 8340554 + * @summary Check correctness of deserialization + * @run junit SerializationTest + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SerializationTest { + + // Ensure basic correctness of serialization round trip + @ParameterizedTest + @MethodSource + public void serializationRoundTrip(MessageFormat expectedMf) + throws IOException, ClassNotFoundException { + byte[] bytes = ser(expectedMf); + MessageFormat actualMf = (MessageFormat) deSer(bytes); + assertEquals(expectedMf, actualMf); + } + + // Various valid MessageFormats + private static Stream serializationRoundTrip() { + return Stream.of( + // basic pattern + new MessageFormat("{0} foo"), + // Multiple arguments + new MessageFormat("{0} {1} foo"), + // duplicate arguments + new MessageFormat("{0} {0} {1} foo"), + // Non-ascending arguments + new MessageFormat("{1} {0} foo"), + // With locale + new MessageFormat("{1} {0} foo", Locale.UK), + // With null locale. (NPE not thrown, if no format defined) + new MessageFormat("{1} {0} foo", null), + // With formats + new MessageFormat("{0,number,short} {0} {1,date,long} foo"), + // Offset equal to pattern length (0) + new MessageFormat("{0}"), + // Offset equal to pattern length (1) + new MessageFormat("X{0}"), + // Offset 1 under pattern length + new MessageFormat("X{0}X") + ); + } + + // Utility method to serialize + private static byte[] ser(Object obj) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new + ByteArrayOutputStream(); + ObjectOutputStream oos = new + ObjectOutputStream(byteArrayOutputStream); + oos.writeObject(obj); + return byteArrayOutputStream.toByteArray(); + } + + // Utility method to deserialize + private static Object deSer(byte[] bytes) throws + IOException, ClassNotFoundException { + ByteArrayInputStream byteArrayInputStream = new + ByteArrayInputStream(bytes); + ObjectInputStream ois = new + ObjectInputStream(byteArrayInputStream); + return ois.readObject(); + } +} diff --git a/test/jdk/java/time/tck/java/time/TCKInstant.java b/test/jdk/java/time/tck/java/time/TCKInstant.java index d7a6341527962..c666a1340d388 100644 --- a/test/jdk/java/time/tck/java/time/TCKInstant.java +++ b/test/jdk/java/time/tck/java/time/TCKInstant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, 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 @@ -187,10 +187,21 @@ public void constant_MAX() { //----------------------------------------------------------------------- @Test public void now() { - Instant expected = Instant.now(Clock.systemUTC()); - Instant test = Instant.now(); - long diff = Math.abs(test.toEpochMilli() - expected.toEpochMilli()); - assertTrue(diff < 100); // less than 0.1 secs + long beforeMillis, instantMillis, afterMillis, diff; + int retryRemaining = 5; // MAX_RETRY_COUNT + do { + beforeMillis = Instant.now(Clock.systemUTC()).toEpochMilli(); + instantMillis = Instant.now().toEpochMilli(); + afterMillis = Instant.now(Clock.systemUTC()).toEpochMilli(); + diff = instantMillis - beforeMillis; + if (instantMillis < beforeMillis || instantMillis > afterMillis) { + throw new RuntimeException(": Invalid instant: (~" + instantMillis + "ms)" + + " when systemUTC in millis is in [" + + beforeMillis + ", " + + afterMillis + "]"); + } + } while (diff > 100 && --retryRemaining > 0); // retry if diff more than 0.1 sec + assertTrue(retryRemaining > 0); } //----------------------------------------------------------------------- diff --git a/test/jdk/java/time/tck/java/time/TCKZoneId.java b/test/jdk/java/time/tck/java/time/TCKZoneId.java index a90c9abf48e37..a1d0065d39e68 100644 --- a/test/jdk/java/time/tck/java/time/TCKZoneId.java +++ b/test/jdk/java/time/tck/java/time/TCKZoneId.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 @@ -96,11 +96,11 @@ public class TCKZoneId extends AbstractTCKTest { //----------------------------------------------------------------------- // SHORT_IDS //----------------------------------------------------------------------- - public void test_constant_OLD_IDS_POST_2005() { + public void test_constant_OLD_IDS_POST_2024b() { Map ids = ZoneId.SHORT_IDS; - assertEquals(ids.get("EST"), "-05:00"); - assertEquals(ids.get("MST"), "-07:00"); - assertEquals(ids.get("HST"), "-10:00"); + assertEquals(ids.get("EST"), "America/Panama"); + assertEquals(ids.get("MST"), "America/Phoenix"); + assertEquals(ids.get("HST"), "Pacific/Honolulu"); assertEquals(ids.get("ACT"), "Australia/Darwin"); assertEquals(ids.get("AET"), "Australia/Sydney"); assertEquals(ids.get("AGT"), "America/Argentina/Buenos_Aires"); @@ -129,7 +129,7 @@ public void test_constant_OLD_IDS_POST_2005() { } @Test(expectedExceptions=UnsupportedOperationException.class) - public void test_constant_OLD_IDS_POST_2005_immutable() { + public void test_constant_OLD_IDS_POST_2024b_immutable() { Map ids = ZoneId.SHORT_IDS; ids.clear(); } diff --git a/test/jdk/java/util/ArrayList/SortingModCount.java b/test/jdk/java/util/ArrayList/SortingModCount.java new file mode 100644 index 0000000000000..394c74cf4448c --- /dev/null +++ b/test/jdk/java/util/ArrayList/SortingModCount.java @@ -0,0 +1,59 @@ +/* + * 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.util.ArrayList; +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.List; + +/** + * @test + * @bug 8340572 + * @summary ConcurrentModificationException when sorting ArrayList sublists + */ + +public class SortingModCount { + public static void main(String[] args) { + testSortingSubListsDoesNotIncrementModCount(); + testSortingListDoesIncrementModCount(); + } + + private static void testSortingSubListsDoesNotIncrementModCount() { + List l = new ArrayList<>(List.of(1, 2, 3, 4)); + var a = l.subList(0, 2); + var b = l.subList(2, 4); + Collections.sort(a); + Collections.sort(b); + } + + private static void testSortingListDoesIncrementModCount() { + List l = new ArrayList<>(List.of(1, 2, 3, 4)); + var b = l.subList(2, 4); + Collections.sort(l); + try { + Collections.sort(b); + throw new Error("expected ConcurrentModificationException not thrown"); + } catch (ConcurrentModificationException expected) { + } + } +} diff --git a/test/jdk/java/util/Locale/UserRegionTest.java b/test/jdk/java/util/Locale/UserRegionTest.java new file mode 100644 index 0000000000000..72a7106b26708 --- /dev/null +++ b/test/jdk/java/util/Locale/UserRegionTest.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. + */ + +/* + * @test + * @bug 8342582 + * @summary Test if "user.region" system property successfully overrides + * other locale related system properties at startup + * @modules jdk.localedata + * @run junit/othervm + * -Duser.region=DE + * -Duser.language=en + * -Duser.script=Latn + * -Duser.country=US + * -Duser.variant=FOO UserRegionTest + * @run junit/othervm + * -Duser.region=DE_POSIX + * -Duser.language=en + * -Duser.script=Latn + * -Duser.country=US + * -Duser.variant=FOO UserRegionTest + * @run junit/othervm + * -Duser.region=_POSIX + * -Duser.language=en + * -Duser.script=Latn + * -Duser.country=US + * -Duser.variant=FOO UserRegionTest + */ + +import java.util.Locale; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class UserRegionTest { + @Test + public void testDefaultLocale() { + var region = System.getProperty("user.region").split("_"); + var expected = Locale.of(System.getProperty("user.language"), + region[0], region.length > 1 ? region[1] : ""); + assertEquals(expected, Locale.getDefault()); + assertEquals(expected, Locale.getDefault(Locale.Category.FORMAT)); + assertEquals(expected, Locale.getDefault(Locale.Category.DISPLAY)); + } + + @Test + public void testNumberFormat() { + if (System.getProperty("user.region").startsWith("DE")) { + assertEquals("0,50000", String.format("%.5f", 0.5f)); + } else { + assertEquals("0.50000", String.format("%.5f", 0.5f)); + } + } +} diff --git a/test/jdk/java/util/PluggableLocale/DateFormatProviderTest.java b/test/jdk/java/util/PluggableLocale/DateFormatProviderTest.java index 876fe3526cf9d..4e3fdfbaf7a05 100644 --- a/test/jdk/java/util/PluggableLocale/DateFormatProviderTest.java +++ b/test/jdk/java/util/PluggableLocale/DateFormatProviderTest.java @@ -31,7 +31,7 @@ * java.base/sun.util.resources * @build com.foobar.Utils * com.foo.* - * @run main/othervm -Djava.locale.providers=CLDR,SPI DateFormatProviderTest + * @run main/othervm/timeout=300 -Djava.locale.providers=CLDR,SPI DateFormatProviderTest */ import java.text.DateFormat; diff --git a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.html b/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.html deleted file mode 100644 index 1fa0659ed6392..0000000000000 --- a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - Disable Auto-adjust Daylight Saving Time Test - - - -This applet tests the platform time zone detection on all platforms (Part I) -and on/off of DST adjustment on Windows (Part II). - -Part I: - -Observe the displayed Time zone ID and the local time. If you can change -the platform time zone setting, try several time zones. If both the ID and -the local time, including the time zone name and its time zone offset, are -always correct, Part I passes. Note that some time zone IDs have their -aliases that may be displayed. For example, "US/Pacific" is an alias of -"America/Los_Angeles". - -If you are running this applet in non-English locale, the time zone names -can be displayed in the local language and English by pushing the -English/Local button. - -If platform time zones are NOT detected correctly, press the Fail button -to finish this applet. - -If this platform is Windows, proceed to Part II. Otherwise, press the Pass -button to finish this applet. - -Part II: - -Note that Part II may require the Administrator privilege to change -Windows setting. - - 1. Open the Date and Time control panel. - 2. Select any time zone where daylight saving time is *currently* in effect, - such as "(GMT-08:00) Pacific Time (US & Canada); Tijuana", - "(GMT+10:00) Canberra, Melbourne, Sydney", and Apply. - 3. Observe the local time on the control panel (Date&Time pane) and - the applet local time should be the same (daylight time). - 4. Clear "Automatically adjust clock for daylight saving changes" and Apply. - 5. Observe the two local times should be the same (standard time). - 6. Select "Automatically adjust clock for daylight saving changes" and Apply. - -If the local time in the control panel and applet are always the same, -then this test passes. Press the Pass or Fail button based on the Part II -result and finish this applet. - - - - diff --git a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java b/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java index a6d3ac50866c0..4dd644d58b529 100644 --- a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java +++ b/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, 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,85 +24,94 @@ /* * @test * @bug 4296930 5033603 7092679 - * @summary Make sure that Java runtime detects the platform time zone - * correctly. Also make sure that the system time zone detection code - * detects the "Automatically adjust clock for daylight saving - * changes" setting correctly on Windows. - * @run applet/manual=yesno DefaultTimeZoneTest.html + * @summary Ensure that Java detects the platform time zone correctly, even + * if changed during runtime. Also ensure that the system time zone detection code + * detects the "Automatically adjust clock for daylight saving changes" setting + * correctly on Windows. This is a manual test dependent on making changes to + * the platform setting of the machine and thus cannot be automated. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DefaultTimeZoneTest */ -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; -import java.text.*; -import java.util.*; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Window; +import java.lang.reflect.InvocationTargetException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; -public class DefaultTimeZoneTest extends JApplet implements Runnable { - static final String FORMAT = "yyyy-MM-dd HH:mm:ss zzzz (XXX)"; - JLabel tzid; - JLabel label; - SimpleDateFormat sdf = new SimpleDateFormat(FORMAT); - JButton button = new JButton("English"); - Thread clock; - boolean english = false; +public class DefaultTimeZoneTest { - @Override - public void init() { - tzid = new JLabel("Time zone ID: " + sdf.getTimeZone().getID(), SwingConstants.CENTER); - tzid.setAlignmentX(Component.CENTER_ALIGNMENT); - label = new JLabel(sdf.format(new Date()), SwingConstants.CENTER); - label.setAlignmentX(Component.CENTER_ALIGNMENT); - button.addActionListener(new ActionListener() { - @Override - @SuppressWarnings("deprecation") - public void actionPerformed(ActionEvent e) { - english = (english == false); - Locale loc = english ? Locale.US : Locale.getDefault(); - sdf = new SimpleDateFormat(FORMAT, loc); - button.setLabel(!english ? "English" : "Local"); - } - }); - button.setAlignmentX(Component.CENTER_ALIGNMENT); - JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); - panel.add(Box.createRigidArea(new Dimension(0, 10))); - panel.add(tzid); - panel.add(Box.createRigidArea(new Dimension(0, 5))); - panel.add(label); - panel.add(Box.createRigidArea(new Dimension(0, 10))); - panel.add(button); - getContentPane().add(panel); - } + private static final SimpleDateFormat SDF = + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzzz (XXX)"); + private static final String INSTRUCTIONS = + """ + Tests the platform time zone detection on all platforms. + (Part I) and on/off of DST adjustment on Windows (Part II). - @Override - public void start() { - clock = new Thread(this); - clock.start(); - } + Part I: + Observe the displayed Time zone ID and the local time. + Change the platform time zone setting, then click the + "Update Time Zone" button. If the ID and local time + update correctly, part I passes, otherwise press fail. Note that + some time zone IDs have their aliases that may be displayed. + For example, "US/Pacific" is an alias of "America/Los_Angeles". + If this platform is Windows, proceed to Part II. Otherwise, press + the Pass button to complete this test. - @Override - public void stop() { - clock = null; - } + Part II: + Note that Part II may require the Administrator privilege to change + Windows setting. - @Override - public void run() { - Thread me = Thread.currentThread(); + 1. Open the Settings app and navigate to Time & Language > Date & Time + 2. Select any time zone where daylight saving time is *currently* + in effect, such as "(GMT-08:00) Pacific Time (US & Canada); + Tijuana", "(GMT+10:00) Canberra, Melbourne, Sydney", and Apply. + 3. After pressing "Update Time Zone" button, observe that the local + time on the Settings app and the test local time are the same (daylight time). + 4. Turn off "Adjust for daylight saving time automatically" + 5. Observe the two local times should be the same (standard time). + 6. Turn on "Adjust for daylight saving time automatically" - while (clock == me) { - // Reset the default time zone so that - // TimeZone.getDefault will detect the platform time zone - TimeZone.setDefault(null); - System.setProperty("user.timezone", ""); + If the local time in the Settings app and test window are always the same, + then this test passes. Press the Pass or Fail button based on the Part II + result and complete the test. + """; + + public static void main(String[] args) + throws InterruptedException, InvocationTargetException { + // Force platform time zone as default time zone + TimeZone.setDefault(null); + System.setProperty("user.timezone", ""); + // Construct test window + PassFailJFrame.builder() + .title("DefaultTimeZoneTest Instructions") + .testUI(createTest()) + .instructions(INSTRUCTIONS) + .build().awaitAndCheck(); + } + + private static Window createTest() { + var contents = new JFrame("DefaultTimeZoneTest"); + var label = new JLabel(SDF.format(new Date())); + var panel = new JPanel(); + var button = new JButton("Update Time Zone"); + panel.add(button); + contents.setSize(350, 250); + contents.add(label, BorderLayout.NORTH); + contents.add(panel, BorderLayout.CENTER); + // Update default time zone on button click + button.addActionListener(e -> { TimeZone tz = TimeZone.getDefault(); - sdf.setTimeZone(tz); - tzid.setText("Time zone ID: " + tz.getID()); - label.setText(sdf.format(new Date())); - repaint(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - } + SDF.setTimeZone(tz); + label.setText(SDF.format(new Date())); + contents.repaint(); + }); + return contents; } } diff --git a/test/jdk/java/util/TimeZone/OldIDMappingTest.java b/test/jdk/java/util/TimeZone/OldIDMappingTest.java deleted file mode 100644 index 8436080b0416f..0000000000000 --- a/test/jdk/java/util/TimeZone/OldIDMappingTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2008, 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 6466476 - * @summary Compatibility test for the old JDK ID mapping and Olson IDs - * @comment Expecting the new (Olson compatible) mapping (default) - * @run main/othervm -Dsun.timezone.ids.oldmapping=null OldIDMappingTest -new - * @run main/othervm -Dsun.timezone.ids.oldmapping="" OldIDMappingTest -new - * @run main/othervm -Dsun.timezone.ids.oldmapping=no OldIDMappingTest -new - * @run main/othervm -Dsun.timezone.ids.oldmapping=No OldIDMappingTest -new - * @run main/othervm -Dsun.timezone.ids.oldmapping=NO OldIDMappingTest -new - * @run main/othervm -Dsun.timezone.ids.oldmapping=false OldIDMappingTest -new - * @run main/othervm -Dsun.timezone.ids.oldmapping=False OldIDMappingTest -new - * @run main/othervm -Dsun.timezone.ids.oldmapping=FALSE OldIDMappingTest -new - * @run main/othervm -Dsun.timezone.ids.oldmapping=Hello OldIDMappingTest -new - * @comment Expecting the old mapping - * @run main/othervm -Dsun.timezone.ids.oldmapping=true OldIDMappingTest -old - * @run main/othervm -Dsun.timezone.ids.oldmapping=True OldIDMappingTest -old - * @run main/othervm -Dsun.timezone.ids.oldmapping=TRUE OldIDMappingTest -old - * @run main/othervm -Dsun.timezone.ids.oldmapping=yes OldIDMappingTest -old - * @run main/othervm -Dsun.timezone.ids.oldmapping=Yes OldIDMappingTest -old - * @run main/othervm -Dsun.timezone.ids.oldmapping=YES OldIDMappingTest -old - */ - -import java.util.HashMap; -import java.util.Map; -import java.util.TimeZone; - -public class OldIDMappingTest { - private static final String MAPPING_PROPERTY_NAME = "sun.timezone.ids.oldmapping"; - private static final Map newmap = new HashMap(); - static { - // Add known new mappings - newmap.put("EST", "EST"); - newmap.put("MST", "MST"); - newmap.put("HST", "HST"); - } - - public static void main(String[] args) { - boolean useOldMapping = true; - String arg = args[0]; - if (arg.equals("-new")) { - useOldMapping = false; - } else if (arg.equals("-old")) { - useOldMapping = true; - } else { - throw new RuntimeException("-old or -new must be specified; got " + arg); - } - - Map oldmap = TzIDOldMapping.MAP; - String prop = System.getProperty(MAPPING_PROPERTY_NAME); - System.out.println(MAPPING_PROPERTY_NAME + "=" + prop); - - // Try the test multiple times with modifying TimeZones to - // make sure TimeZone instances for the old mapping are - // properly copied (defensive copy). - for (int count = 0; count < 3; count++) { - for (String id : oldmap.keySet()) { - TimeZone tzAlias = TimeZone.getTimeZone(id); - TimeZone tz = TimeZone.getTimeZone(oldmap.get(id)); - if (useOldMapping) { - if (!tzAlias.hasSameRules(tz)) { - throw new RuntimeException("OLDMAP: " + MAPPING_PROPERTY_NAME - + "=" + prop + ": " + id - + " isn't an alias of " + oldmap.get(id)); - } - if (count == 0) { - System.out.println(" " + id + " => " + oldmap.get(id)); - } - tzAlias.setRawOffset(tzAlias.getRawOffset() * count); - } else { - if (!newmap.containsKey(id)) { - // ignore ids not contained in the new map - if (count == 0) { - System.out.println(" " + id + " => " + oldmap.get(id)); - } - tzAlias.setRawOffset(tzAlias.getRawOffset() * count); - continue; - } - if (tzAlias.hasSameRules(tz)) { - throw new RuntimeException("NEWMAP: " + MAPPING_PROPERTY_NAME - + "=" + prop + ": " + id - + " is an alias of " + oldmap.get(id)); - } - tz = TimeZone.getTimeZone(newmap.get(id)); - if (!tzAlias.hasSameRules(tz)) { - throw new RuntimeException("NEWMAP: " + MAPPING_PROPERTY_NAME - + "=" + prop + ": " + id - + " isn't an alias of " + newmap.get(id)); - } - if (count == 0) { - System.out.println(" " + id + " => " + newmap.get(id)); - } - tzAlias.setRawOffset(tzAlias.getRawOffset() * count); - } - } - } - } -} diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION index bf027918ce734..f40be22e9abc1 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION +++ b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION @@ -1 +1 @@ -tzdata2024a +tzdata2024b diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt index 82bad17c55320..3217f68b82578 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt +++ b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt @@ -15,6 +15,8 @@ Link America/Rio_Branco Brazil/Acre #= America/Porto_Acre Link America/Noronha Brazil/DeNoronha Link America/Sao_Paulo Brazil/East Link America/Manaus Brazil/West +Link Europe/Brussels CET +Link America/Chicago CST6CDT Link America/Halifax Canada/Atlantic Link America/Winnipeg Canada/Central Link America/Toronto Canada/Eastern @@ -26,6 +28,9 @@ Link America/Whitehorse Canada/Yukon Link America/Santiago Chile/Continental Link Pacific/Easter Chile/EasterIsland Link America/Havana Cuba +Link Europe/Athens EET +Link America/Panama EST +Link America/New_York EST5EDT Link Africa/Cairo Egypt Link Europe/Dublin Eire Link Etc/GMT Etc/GMT+0 @@ -49,6 +54,9 @@ Link America/Jamaica Jamaica Link Asia/Tokyo Japan Link Pacific/Kwajalein Kwajalein Link Africa/Tripoli Libya +Link Europe/Brussels MET +Link America/Phoenix MST +Link America/Denver MST7MDT Link America/Tijuana Mexico/BajaNorte Link America/Mazatlan Mexico/BajaSur Link America/Mexico_City Mexico/General @@ -212,6 +220,7 @@ Link America/Denver America/Shiprock Link America/Toronto America/Thunder_Bay Link America/Edmonton America/Yellowknife Link Pacific/Auckland Antarctica/South_Pole +Link Asia/Ulaanbaatar Asia/Choibalsan Link Asia/Shanghai Asia/Chongqing Link Asia/Shanghai Asia/Harbin Link Asia/Urumqi Asia/Kashgar @@ -226,6 +235,7 @@ Link Europe/Kyiv Europe/Zaporozhye Link Pacific/Kanton Pacific/Enderbury Link Pacific/Honolulu Pacific/Johnston Link Pacific/Port_Moresby Pacific/Yap +Link Europe/Lisbon WET Link Africa/Nairobi Africa/Asmera #= Africa/Asmara Link America/Nuuk America/Godthab Link Asia/Ashgabat Asia/Ashkhabad @@ -243,5 +253,7 @@ Link Asia/Ulaanbaatar Asia/Ulan_Bator Link Atlantic/Faroe Atlantic/Faeroe Link Europe/Kyiv Europe/Kiev Link Asia/Nicosia Europe/Nicosia +Link Pacific/Honolulu HST +Link America/Los_Angeles PST8PDT Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt b/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt index 2bcccf8f88005..e7b6ea8bf3cb7 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt +++ b/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt @@ -122,11 +122,6 @@ Australia/Lindeman AEST AEDT Australia/Melbourne AEST AEDT Australia/Perth AWST AWDT Australia/Sydney AEST AEDT -CET CET CEST -CST6CDT CST CDT -EET EET EEST -EST EST -EST5EDT EST EDT Europe/Andorra CET CEST Europe/Athens EET EEST Europe/Belgrade CET CEST @@ -159,13 +154,7 @@ Europe/Vilnius EET EEST Europe/Volgograd MSK Europe/Warsaw CET CEST Europe/Zurich CET CEST -HST HST -MET MET MEST -MST MST -MST7MDT MST MDT -PST8PDT PST PDT Pacific/Auckland NZST NZDT Pacific/Guam ChST Pacific/Honolulu HST Pacific/Pago_Pago SST -WET WET WEST diff --git a/test/jdk/java/util/TimeZone/TzIDOldMapping.java b/test/jdk/java/util/TimeZone/TzIDOldMapping.java deleted file mode 100644 index 7bfcf04854c89..0000000000000 --- a/test/jdk/java/util/TimeZone/TzIDOldMapping.java +++ /dev/null @@ -1,64 +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. - */ - -import java.util.Map; -import java.util.HashMap; - -class TzIDOldMapping { - static final Map MAP = new HashMap(); - static { - String[][] oldmap = { - { "ACT", "Australia/Darwin" }, - { "AET", "Australia/Sydney" }, - { "AGT", "America/Argentina/Buenos_Aires" }, - { "ART", "Africa/Cairo" }, - { "AST", "America/Anchorage" }, - { "BET", "America/Sao_Paulo" }, - { "BST", "Asia/Dhaka" }, - { "CAT", "Africa/Harare" }, - { "CNT", "America/St_Johns" }, - { "CST", "America/Chicago" }, - { "CTT", "Asia/Shanghai" }, - { "EAT", "Africa/Addis_Ababa" }, - { "ECT", "Europe/Paris" }, - { "EST", "America/New_York" }, - { "HST", "Pacific/Honolulu" }, - { "IET", "America/Indianapolis" }, - { "IST", "Asia/Calcutta" }, - { "JST", "Asia/Tokyo" }, - { "MIT", "Pacific/Apia" }, - { "MST", "America/Denver" }, - { "NET", "Asia/Yerevan" }, - { "NST", "Pacific/Auckland" }, - { "PLT", "Asia/Karachi" }, - { "PNT", "America/Phoenix" }, - { "PRT", "America/Puerto_Rico" }, - { "PST", "America/Los_Angeles" }, - { "SST", "Pacific/Guadalcanal" }, - { "VST", "Asia/Saigon" }, - }; - for (String[] pair : oldmap) { - MAP.put(pair[0], pair[1]); - } - } -} diff --git a/test/jdk/java/util/logging/TestMainAppContext.java b/test/jdk/java/util/logging/TestMainAppContext.java index 49f371aa32160..0bfcbbad9d85b 100644 --- a/test/jdk/java/util/logging/TestMainAppContext.java +++ b/test/jdk/java/util/logging/TestMainAppContext.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 @@ -46,8 +46,8 @@ public static void main(String... args) throws Exception { rootTG = rootTG.getParent(); } - ThreadGroup tg = new ThreadGroup(rootTG, "FakeApplet"); - final Thread t1 = new Thread(tg, "createNewAppContext") { + ThreadGroup tg = new ThreadGroup(rootTG, "main"); + final Thread t1 = new Thread(tg, "child") { @Override public void run() { try { diff --git a/test/jdk/java/util/zip/ZipEntry/MaxZipEntryFieldSizeTest.java b/test/jdk/java/util/zip/ZipEntry/MaxZipEntryFieldSizeTest.java new file mode 100644 index 0000000000000..40c2234f54720 --- /dev/null +++ b/test/jdk/java/util/zip/ZipEntry/MaxZipEntryFieldSizeTest.java @@ -0,0 +1,174 @@ +/* + * 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 8340553 + * @summary Verify that ZipEntry(String), ZipEntry::setComment, and + * ZipEntry::setExtra throws a IllegalArgumentException when the + * combined length of the fields, including the size of the CEN Header, + * exceeds 65,535 bytes + * @run junit MaxZipEntryFieldSizeTest + */ + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class MaxZipEntryFieldSizeTest { + + // CEN header size + name length + comment length + extra length + // should not exceed 65,535 bytes per the PKWare APP.NOTE + // 4.4.10, 4.4.11, & 4.4.12. + static final int MAX_COMBINED_CEN_HEADER_SIZE = 0xFFFF; + // Maximum possible size of name length + comment length + extra length + // for entries in order to not exceed 65,489 bytes + static final int MAX_NAME_COMMENT_EXTRA_SIZE = + MAX_COMBINED_CEN_HEADER_SIZE - ZipFile.CENHDR; + // Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings' + static final short UNKNOWN_ZIP_TAG = (short) 0x9902; + // Zip Entry name used by tests + static final String ENTRY_NAME = "EntryName"; + // Max length minus the size of the ENTRY_NAME or ENTRY_COMMENT + static final int MAX_FIELD_LEN_MINUS_ENTRY_NAME = + MAX_NAME_COMMENT_EXTRA_SIZE - 9; + + /** + * Validate an IllegalArgumentException is thrown when the + * combined length of the entry name, entry comment, entry extra data, + * and CEN Header size exceeds 65,535 bytes. + */ + @ParameterizedTest + @ValueSource(ints = {30000, 35000}) + void combinedLengthTest(int length) { + String comment = "a".repeat(length); + byte[] bytes = creatExtraData(length); + int combinedLength = ENTRY_NAME.length() + comment.length() + bytes.length; + boolean expectException = combinedLength > MAX_COMBINED_CEN_HEADER_SIZE; + System.out.printf("Combined Len= %s, exception: %s%n", combinedLength, expectException); + ZipEntry zipEntry = new ZipEntry(ENTRY_NAME); + zipEntry.setComment(comment); + // The extra data length will trigger the IllegalArgumentException + if (expectException) { + assertThrows(IllegalArgumentException.class, () -> + zipEntry.setExtra(bytes)); + } else { + zipEntry.setExtra(bytes); + } + } + + /** + * Validate an IllegalArgumentException is thrown when the comment + * length exceeds 65,489 bytes. + */ + @ParameterizedTest + @ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE, + MAX_NAME_COMMENT_EXTRA_SIZE, + MAX_NAME_COMMENT_EXTRA_SIZE + 1, + MAX_FIELD_LEN_MINUS_ENTRY_NAME, + MAX_FIELD_LEN_MINUS_ENTRY_NAME - 1}) + void setCommentLengthTest(int length) { + boolean expectException = length >= MAX_NAME_COMMENT_EXTRA_SIZE; + ZipEntry zipEntry = new ZipEntry(ENTRY_NAME); + String comment = "a".repeat(length); + System.out.printf("Comment Len= %s, exception: %s%n", comment.length(), expectException); + // The comment length will trigger the IllegalArgumentException + if (expectException) { + assertThrows(IllegalArgumentException.class, () -> + zipEntry.setComment(comment)); + } else { + zipEntry.setComment(comment); + } + } + + /** + * Validate an IllegalArgumentException is thrown when the name + * length exceeds 65,489 bytes. + */ + @ParameterizedTest + @ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE, + MAX_NAME_COMMENT_EXTRA_SIZE, + MAX_NAME_COMMENT_EXTRA_SIZE + 1, + MAX_FIELD_LEN_MINUS_ENTRY_NAME, + MAX_FIELD_LEN_MINUS_ENTRY_NAME - 1}) + void nameLengthTest(int length) { + boolean expectException = length > MAX_NAME_COMMENT_EXTRA_SIZE; + String name = "a".repeat(length); + System.out.printf("name Len= %s, exception: %s%n", name.length(), expectException); + // The name length will trigger the IllegalArgumentException + if (expectException) { + assertThrows(IllegalArgumentException.class, () -> new ZipEntry(name)); + } else { + new ZipEntry(name); + } + } + + /** + * Validate an IllegalArgumentException is thrown when the extra data + * length exceeds 65,489 bytes. + */ + @ParameterizedTest + @ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE, + MAX_NAME_COMMENT_EXTRA_SIZE, + MAX_NAME_COMMENT_EXTRA_SIZE + 1, + MAX_FIELD_LEN_MINUS_ENTRY_NAME, + MAX_FIELD_LEN_MINUS_ENTRY_NAME - 1}) + void setExtraLengthTest(int length) { + boolean expectException = length >= MAX_NAME_COMMENT_EXTRA_SIZE; + byte[] bytes = creatExtraData(length); + ZipEntry zipEntry = new ZipEntry(ENTRY_NAME); + System.out.printf("extra Len= %s, exception: %s%n", bytes.length, expectException); + // The extra data length will trigger the IllegalArgumentException + if (expectException) { + assertThrows(IllegalArgumentException.class, () -> zipEntry.setExtra(bytes)); + } else { + zipEntry.setExtra(bytes); + } + } + + /** + * Create the extra field data which will be passed to ZipEntry::setExtra + * @param length size of the extra data + * @return byte array containing the extra data + */ + private static byte[] creatExtraData(int length) { + byte[] bytes = new byte[length]; + // Little-endian ByteBuffer for updating the header fields + ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + // We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings' + buffer.putShort(UNKNOWN_ZIP_TAG); + // Size of the actual (empty) data + buffer.putShort((short) (length - 2 * Short.BYTES)); + return bytes; + } +} diff --git a/test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java b/test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java new file mode 100644 index 0000000000000..a63464eb72b88 --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java @@ -0,0 +1,246 @@ +/* + * 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 + * 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 8341595 + * @modules java.base/jdk.internal.util + * @summary Verify that ZipFile can read from a ZIP file with a maximally large CEN size + * @run junit/othervm/manual -Xmx2500M CenSizeMaximum + */ + +import jdk.internal.util.ArraysSupport; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.*; + +public class CenSizeMaximum { + + // Maximum allowed CEN size allowed by the ZipFile implementation + static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; + + /** + * From the APPNOTE.txt specification: + * 4.4.10 file name length: (2 bytes) + * 4.4.11 extra field length: (2 bytes) + * 4.4.12 file comment length: (2 bytes) + * + * The length of the file name, extra field, and comment + * fields respectively. The combined length of any + * directory record and these three fields SHOULD NOT + * generally exceed 65,535 bytes. + *. + * Create a maximum extra field which does not exceed 65,535 bytes + */ + static final int MAX_EXTRA_FIELD_SIZE = 65_535 - ZipFile.CENHDR; + + // Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings' + static final short UNKNOWN_ZIP_TAG = (short) 0x9902; + + // The size of one CEN header, including the name and the extra field + static final int CEN_HEADER_SIZE = ZipFile.CENHDR + MAX_EXTRA_FIELD_SIZE; + + // The size of the extra data field header (tag id + data block length) + static final int EXTRA_FIELD_HEADER_SIZE = 2 * Short.BYTES; + + // Zip file to create for testing + private Path hugeZipFile = Path.of("cen-size-on-limit.zip"); + + /** + * Clean up ZIP file created in this test + */ + @AfterEach + public void cleanup() throws IOException { + //Files.deleteIfExists(hugeZipFile); + } + + /** + * Validates that ZipFile opens a ZIP file with a CEN size close + * to the {@link #MAX_CEN_SIZE} implementation limit. + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + public void maximumCenSize() throws IOException { + int numCenHeaders = zipWithWithExactCenSize(MAX_CEN_SIZE, true, false); + try (var zf = new ZipFile(hugeZipFile.toFile())) { + assertEquals(numCenHeaders, zf.size()); + } + } + + /** + * Validates that ZipFile rejects a ZIP where the last CEN record + * overflows the CEN size and the END header CENTOT field is smaller + * than the actual number of headers + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + public void lastCENHeaderBadSize() throws IOException { + int numCenHeaders = zipWithWithExactCenSize(1024, true, true); + ZipException zipException = assertThrows(ZipException.class, () -> { + try (var zf = new ZipFile(hugeZipFile.toFile())) { + assertEquals(numCenHeaders, zf.size()); + } + }); + assertEquals("invalid CEN header (bad header size)", zipException.getMessage()); + + } + + /** + * Produce a ZIP file with an exact CEN size. To minimize the number of CEN headers + * written, maximally large, empty extra data blocks are written sparsely. + * + * @param cenSize the exact CEN size of the ZIP file to produce + * @param invalidateEndTotal whether to decrement the END header's TOT field by one + * @return the number of CEN headers produced + * @throws IOException if an unexpected IO error occurs + */ + private int zipWithWithExactCenSize(long cenSize, boolean invalidateEndTotal, boolean overflowLastCEN) + throws IOException { + // Sanity check + assertTrue(cenSize <= MAX_CEN_SIZE); + + // The number of CEN headers we need to write + int numCenHeaders = (int) (cenSize / CEN_HEADER_SIZE) + 1; + // Size if all extra data fields were of maximum size + long overSized = numCenHeaders * (long) CEN_HEADER_SIZE; + // Length to trim from the first CEN's extra data + int negativPadding = (int) (overSized - cenSize); + int firstExtraSize = MAX_EXTRA_FIELD_SIZE - negativPadding; + + // Sanity check + long computedCenSize = (numCenHeaders -1L ) * CEN_HEADER_SIZE + ZipEntry.CENHDR + firstExtraSize; + assertEquals(computedCenSize, cenSize); + + // A CEN header, followed by the four-bytes extra data header + ByteBuffer cenHeader = createCENHeader(); + // An END header + ByteBuffer endHeader = createENDHeader(); + // Update the END header + if (invalidateEndTotal) { + // To trigger countCENHeaders + endHeader.putShort(ZipEntry.ENDTOT, (short) (numCenHeaders -1 & 0xFFFF)); + } else { + endHeader.putShort(ZipEntry.ENDTOT, (short) (numCenHeaders & 0xFFFF)); + } + // Update CEN size and offset fields + endHeader.putInt(ZipEntry.ENDSIZ, (int) (cenSize & 0xFFFFFFFFL)); + endHeader.putInt(ZipEntry.ENDOFF, 0); + + // When creating a sparse file, the file must not already exit + Files.deleteIfExists(hugeZipFile); + + // Open a FileChannel for writing a sparse file + EnumSet options = EnumSet.of(StandardOpenOption.CREATE_NEW, + StandardOpenOption.WRITE, + StandardOpenOption.SPARSE); + + try (FileChannel channel = FileChannel.open(hugeZipFile, options)) { + // Write CEN headers + for (int i = 0; i < numCenHeaders; i++) { + // The first CEN header has trimmed extra data + int extraSize = i == 0 ? firstExtraSize : MAX_EXTRA_FIELD_SIZE; + if (overflowLastCEN && i == numCenHeaders - 1) { + // make last CEN header overflow the CEN size + cenHeader.putShort(ZipEntry.CENNAM, Short.MAX_VALUE); + } + // update elen field + cenHeader.putShort(ZipEntry.CENEXT, (short) (extraSize & 0xFFFF)); + // update data block len of the extra field header + short dlen = (short) ((extraSize - EXTRA_FIELD_HEADER_SIZE) & 0xFFFF); + cenHeader.putShort(ZipEntry.CENHDR + Short.BYTES, dlen); + // Write the CEN header plus the four-byte extra header + channel.write(cenHeader.rewind()); + // Sparse "write" of the extra data block + channel.position(channel.position() + extraSize - EXTRA_FIELD_HEADER_SIZE); + } + // Sanity check + assertEquals(cenSize, channel.position()); + // Write the END header + channel.write(endHeader.rewind()); + } + return numCenHeaders; + } + + // Creates a ByteBuffer representing a CEN header with a trailing extra field header + private ByteBuffer createCENHeader() throws IOException { + byte[] bytes = smallZipfile(); + ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + int endOff = bytes.length - ZipEntry.ENDHDR; + int cenSize = buf.getInt(endOff + ZipEntry.ENDSIZ); + int cenOff = buf.getInt(endOff + ZipEntry.ENDOFF); + return ByteBuffer.wrap( + Arrays.copyOfRange(bytes, cenOff, cenOff + ZipEntry.CENHDR + EXTRA_FIELD_HEADER_SIZE) + ).order(ByteOrder.LITTLE_ENDIAN); + } + + // Creates a ByteBuffer representing an END header + private ByteBuffer createENDHeader() throws IOException { + byte[] bytes = smallZipfile(); + ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + int endOff = bytes.length - ZipEntry.ENDHDR; + return ByteBuffer.wrap( + Arrays.copyOfRange(bytes, endOff, endOff + ZipEntry.ENDHDR) + ).order(ByteOrder.LITTLE_ENDIAN); + } + + // Create a byte array with a minimal ZIP file + private static byte[] smallZipfile() throws IOException { + var out = new ByteArrayOutputStream(); + try (var zo = new ZipOutputStream(out)) { + ZipEntry entry = new ZipEntry(""); + entry.setExtra(makeDummyExtraField()); + zo.putNextEntry(entry); + } + return out.toByteArray(); + } + + // Create a minimally sized extra field + private static byte[] makeDummyExtraField() { + byte[] extra = new byte[EXTRA_FIELD_HEADER_SIZE]; + // Little-endian ByteBuffer for updating the header fields + ByteBuffer buffer = ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN); + + // We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings' + buffer.putShort(UNKNOWN_ZIP_TAG); + + // Size of the actual (empty) data + buffer.putShort((short) 0); + return extra; + } +} diff --git a/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java b/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java index ec6542768c58f..7adcfb9c12845 100644 --- a/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java +++ b/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java @@ -25,13 +25,15 @@ * @bug 8272746 * @modules java.base/jdk.internal.util * @summary Verify that ZipFile rejects files with CEN sizes exceeding the implementation limit - * @run testng/othervm EndOfCenValidation + * @run junit/othervm EndOfCenValidation */ import jdk.internal.util.ArraysSupport; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import java.io.*; import java.nio.ByteBuffer; @@ -43,12 +45,13 @@ import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.EnumSet; +import java.util.HexFormat; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; /** * This test augments {@link TestTooManyEntries}. It creates sparse ZIPs where @@ -70,7 +73,7 @@ public class EndOfCenValidation { private static final int ENDSIZ = ZipFile.ENDSIZ; // Offset of CEN size field within ENDHDR private static final int ENDOFF = ZipFile.ENDOFF; // Offset of CEN offset field within ENDHDR // Maximum allowed CEN size allowed by ZipFile - private static int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; + private static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; // Expected message when CEN size does not match file size private static final String INVALID_CEN_BAD_SIZE = "invalid END header (bad central directory size)"; @@ -78,6 +81,8 @@ public class EndOfCenValidation { private static final String INVALID_CEN_BAD_OFFSET = "invalid END header (bad central directory offset)"; // Expected message when CEN size is too large private static final String INVALID_CEN_SIZE_TOO_LARGE = "invalid END header (central directory size too large)"; + // Expected message when total entry count is too large + private static final String INVALID_BAD_ENTRY_COUNT = "invalid END header (total entries count too large)"; // A valid ZIP file, used as a template private byte[] zipBytes; @@ -86,7 +91,7 @@ public class EndOfCenValidation { * Create a valid ZIP file, used as a template * @throws IOException if an error occurs */ - @BeforeTest + @BeforeEach public void setup() throws IOException { zipBytes = templateZip(); } @@ -95,7 +100,7 @@ public void setup() throws IOException { * Delete big files after test, in case the file system did not support sparse files. * @throws IOException if an error occurs */ - @AfterTest + @AfterEach public void cleanup() throws IOException { Files.deleteIfExists(CEN_TOO_LARGE_ZIP); Files.deleteIfExists(INVALID_CEN_SIZE); @@ -113,11 +118,11 @@ public void shouldRejectTooLargeCenSize() throws IOException { Path zip = zipWithModifiedEndRecord(size, true, 0, CEN_TOO_LARGE_ZIP); - ZipException ex = expectThrows(ZipException.class, () -> { + ZipException ex = assertThrows(ZipException.class, () -> { new ZipFile(zip.toFile()); }); - assertEquals(ex.getMessage(), INVALID_CEN_SIZE_TOO_LARGE); + assertEquals(INVALID_CEN_SIZE_TOO_LARGE, ex.getMessage()); } /** @@ -133,11 +138,11 @@ public void shouldRejectInvalidCenSize() throws IOException { Path zip = zipWithModifiedEndRecord(size, false, 0, INVALID_CEN_SIZE); - ZipException ex = expectThrows(ZipException.class, () -> { + ZipException ex = assertThrows(ZipException.class, () -> { new ZipFile(zip.toFile()); }); - assertEquals(ex.getMessage(), INVALID_CEN_BAD_SIZE); + assertEquals(INVALID_CEN_BAD_SIZE, ex.getMessage()); } /** @@ -153,11 +158,138 @@ public void shouldRejectInvalidCenOffset() throws IOException { Path zip = zipWithModifiedEndRecord(size, true, 100, BAD_CEN_OFFSET_ZIP); - ZipException ex = expectThrows(ZipException.class, () -> { + ZipException ex = assertThrows(ZipException.class, () -> { new ZipFile(zip.toFile()); }); - assertEquals(ex.getMessage(), INVALID_CEN_BAD_OFFSET); + assertEquals(INVALID_CEN_BAD_OFFSET, ex.getMessage()); + } + + /** + * Validate that a 'Zip64 End of Central Directory' record (the END header) + * where the value of the 'total entries' field is larger than what fits + * in the CEN size is rejected. + * + * @throws IOException if an error occurs + */ + @ParameterizedTest + @ValueSource(longs = { + -1, // Negative + Long.MIN_VALUE, // Very negative + 0x3B / 3L - 1, // Cannot fit in test ZIP's CEN + MAX_CEN_SIZE / 3 + 1, // Too large to allocate int[] entries array + Long.MAX_VALUE // Unreasonably large + }) + public void shouldRejectBadTotalEntries(long totalEntries) throws IOException { + /** + * A small ZIP using the ZIP64 format. + * + * ZIP created using: "echo -n hello | zip zip64.zip -" + * Hex encoded using: "cat zip64.zip | xxd -ps" + * + * The file has the following structure: + * + * 0000 LOCAL HEADER #1 04034B50 + * 0004 Extract Zip Spec 2D '4.5' + * 0005 Extract OS 00 'MS-DOS' + * 0006 General Purpose Flag 0000 + * 0008 Compression Method 0000 'Stored' + * 000A Last Mod Time 5947AB78 'Mon Oct 7 21:27:48 2024' + * 000E CRC 363A3020 + * 0012 Compressed Length FFFFFFFF + * 0016 Uncompressed Length FFFFFFFF + * 001A Filename Length 0001 + * 001C Extra Length 0014 + * 001E Filename '-' + * 001F Extra ID #0001 0001 'ZIP64' + * 0021 Length 0010 + * 0023 Uncompressed Size 0000000000000006 + * 002B Compressed Size 0000000000000006 + * 0033 PAYLOAD hello. + * + * 0039 CENTRAL HEADER #1 02014B50 + * 003D Created Zip Spec 1E '3.0' + * 003E Created OS 03 'Unix' + * 003F Extract Zip Spec 2D '4.5' + * 0040 Extract OS 00 'MS-DOS' + * 0041 General Purpose Flag 0000 + * 0043 Compression Method 0000 'Stored' + * 0045 Last Mod Time 5947AB78 'Mon Oct 7 21:27:48 2024' + * 0049 CRC 363A3020 + * 004D Compressed Length 00000006 + * 0051 Uncompressed Length FFFFFFFF + * 0055 Filename Length 0001 + * 0057 Extra Length 000C + * 0059 Comment Length 0000 + * 005B Disk Start 0000 + * 005D Int File Attributes 0001 + * [Bit 0] 1 Text Data + * 005F Ext File Attributes 11B00000 + * 0063 Local Header Offset 00000000 + * 0067 Filename '-' + * 0068 Extra ID #0001 0001 'ZIP64' + * 006A Length 0008 + * 006C Uncompressed Size 0000000000000006 + * + * 0074 ZIP64 END CENTRAL DIR 06064B50 + * RECORD + * 0078 Size of record 000000000000002C + * 0080 Created Zip Spec 1E '3.0' + * 0081 Created OS 03 'Unix' + * 0082 Extract Zip Spec 2D '4.5' + * 0083 Extract OS 00 'MS-DOS' + * 0084 Number of this disk 00000000 + * 0088 Central Dir Disk no 00000000 + * 008C Entries in this disk 0000000000000001 + * 0094 Total Entries 0000000000000001 + * 009C Size of Central Dir 000000000000003B + * 00A4 Offset to Central dir 0000000000000039 + * + * 00AC ZIP64 END CENTRAL DIR 07064B50 + * LOCATOR + * 00B0 Central Dir Disk no 00000000 + * 00B4 Offset to Central dir 0000000000000074 + * 00BC Total no of Disks 00000001 + * + * 00C0 END CENTRAL HEADER 06054B50 + * 00C4 Number of this disk 0000 + * 00C6 Central Dir Disk no 0000 + * 00C8 Entries in this disk 0001 + * 00CA Total Entries 0001 + * 00CC Size of Central Dir 0000003B + * 00D0 Offset to Central Dir FFFFFFFF + * 00D4 Comment Length 0000 + */ + + byte[] zipBytes = HexFormat.of().parseHex(""" + 504b03042d000000000078ab475920303a36ffffffffffffffff01001400 + 2d010010000600000000000000060000000000000068656c6c6f0a504b01 + 021e032d000000000078ab475920303a3606000000ffffffff01000c0000 + 00000001000000b011000000002d010008000600000000000000504b0606 + 2c000000000000001e032d00000000000000000001000000000000000100 + 0000000000003b000000000000003900000000000000504b060700000000 + 740000000000000001000000504b050600000000010001003b000000ffff + ffff0000 + """.replaceAll("\n","")); + + // Buffer to manipulate the above ZIP + ByteBuffer buf = ByteBuffer.wrap(zipBytes).order(ByteOrder.LITTLE_ENDIAN); + // Offset of the 'total entries' in the 'ZIP64 END CENTRAL DIR' record + // Update ZIP64 entry count to a value which cannot possibly fit in the small CEN + buf.putLong(0x94, totalEntries); + // The corresponding END field needs the ZIP64 magic value + buf.putShort(0xCA, (short) 0xFFFF); + // Write the ZIP to disk + Path zipFile = Path.of("bad-entry-count.zip"); + Files.write(zipFile, zipBytes); + + // Verify that the END header is rejected + ZipException ex = assertThrows(ZipException.class, () -> { + try (var zf = new ZipFile(zipFile.toFile())) { + } + }); + + assertEquals(INVALID_BAD_ENTRY_COUNT, ex.getMessage()); } /** diff --git a/test/jdk/java/util/zip/ZipOutputStream/ZipOutputStreamMaxCenHdrTest.java b/test/jdk/java/util/zip/ZipOutputStream/ZipOutputStreamMaxCenHdrTest.java deleted file mode 100644 index 286e043c2256f..0000000000000 --- a/test/jdk/java/util/zip/ZipOutputStream/ZipOutputStreamMaxCenHdrTest.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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 8336025 - * @summary Verify that ZipOutputStream throws a ZipException when the - * CEN header size + name length + comment length + extra length exceeds - * 65,535 bytes - * @run junit ZipOutputStreamMaxCenHdrTest - */ -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.io.*; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; - -import static org.junit.jupiter.api.Assertions.*; - -public class ZipOutputStreamMaxCenHdrTest { - - // CEN header size + name length + comment length + extra length - // should not exceed 65,535 bytes per the PKWare APP.NOTE - // 4.4.10, 4.4.11, & 4.4.12. - static final int MAX_COMBINED_CEN_HEADER_SIZE = 0xFFFF; - - // Maximum possible size of name length + comment length + extra length - // for entries in order to not exceed 65,489 bytes minus 46 bytes for the CEN - // header length - static final int MAX_NAME_COMMENT_EXTRA_SIZE = - MAX_COMBINED_CEN_HEADER_SIZE - ZipFile.CENHDR; - - // Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings' - static final short UNKNOWN_ZIP_TAG = (short) 0x9902; - - // ZIP file to be used by the tests - static final Path ZIP_FILE = Path.of("maxCENHdrTest.zip"); - - /** - * Clean up prior to test run - * - * @throws IOException if an error occurs - */ - @BeforeEach - public void startUp() throws IOException { - Files.deleteIfExists(ZIP_FILE); - } - - /** - * Validate a ZipException is thrown when the combined CEN Header, name - * length, comment length, and extra data length exceeds 65,535 bytes when - * the ZipOutputStream is closed. - */ - @ParameterizedTest - @ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE, - MAX_COMBINED_CEN_HEADER_SIZE - 1, - MAX_NAME_COMMENT_EXTRA_SIZE, - MAX_NAME_COMMENT_EXTRA_SIZE - 1}) - void setCommentTest(int length) throws IOException { - boolean expectZipException = length > MAX_NAME_COMMENT_EXTRA_SIZE; - final byte[] bytes = new byte[length]; - Arrays.fill(bytes, (byte) 'a'); - ZipEntry zipEntry = new ZipEntry(""); - // The comment length will trigger the ZipException - zipEntry.setComment(new String(bytes, StandardCharsets.UTF_8)); - boolean receivedException = writeZipEntry(zipEntry, expectZipException); - assertEquals(receivedException, expectZipException); - } - - /** - * Validate an ZipException is thrown when the combined CEN Header, name - * length, comment length, and extra data length exceeds 65,535 bytes when - * the ZipOutputStream is closed. - */ - @ParameterizedTest - @ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE, - MAX_COMBINED_CEN_HEADER_SIZE - 1, - MAX_NAME_COMMENT_EXTRA_SIZE, - MAX_NAME_COMMENT_EXTRA_SIZE - 1}) - void setNameTest(int length) throws IOException { - boolean expectZipException = length > MAX_NAME_COMMENT_EXTRA_SIZE; - final byte[] bytes = new byte[length]; - Arrays.fill(bytes, (byte) 'a'); - // The name length will trigger the ZipException - ZipEntry zipEntry = new ZipEntry(new String(bytes, StandardCharsets.UTF_8)); - boolean receivedException = writeZipEntry(zipEntry, expectZipException); - assertEquals(receivedException, expectZipException); - } - - /** - * Validate an ZipException is thrown when the combined CEN Header, name - * length, comment length, and extra data length exceeds 65,535 bytes when - * the ZipOutputStream is closed. - */ - @ParameterizedTest - @ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE, - MAX_COMBINED_CEN_HEADER_SIZE - 1, - MAX_NAME_COMMENT_EXTRA_SIZE, - MAX_NAME_COMMENT_EXTRA_SIZE - 1}) - void setExtraTest(int length) throws IOException { - boolean expectZipException = length > MAX_NAME_COMMENT_EXTRA_SIZE; - final byte[] bytes = new byte[length]; - // Little-endian ByteBuffer for updating the header fields - ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); - // We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings' - buffer.putShort(UNKNOWN_ZIP_TAG); - // Size of the actual (empty) data - buffer.putShort((short) (length - 2 * Short.BYTES)); - ZipEntry zipEntry = new ZipEntry(""); - // The extra data length will trigger the ZipException - zipEntry.setExtra(bytes); - boolean receivedException = writeZipEntry(zipEntry, expectZipException); - assertEquals(receivedException, expectZipException); - } - - /** - * Write a single Zip entry using ZipOutputStream - * @param zipEntry the ZipEntry to write - * @param expectZipException true if a ZipException is expected, false otherwse - * @return true if a ZipException was thrown - * @throws IOException if an error occurs - */ - private static boolean writeZipEntry(ZipEntry zipEntry, boolean expectZipException) - throws IOException { - boolean receivedException = false; - try (ZipOutputStream zos = new ZipOutputStream( - new BufferedOutputStream(Files.newOutputStream(ZIP_FILE)))) { - zos.putNextEntry(zipEntry); - if (expectZipException) { - ZipException ex = assertThrows(ZipException.class, zos::close); - assertTrue(ex.getMessage().matches(".*bad header size.*"), - "Unexpected ZipException message: " + ex.getMessage()); - receivedException = true; - } - } catch (Exception e) { - throw new RuntimeException("Received Unexpected Exception", e); - } - return receivedException; - } -} diff --git a/test/jdk/javax/crypto/Cipher/ByteBuffers.java b/test/jdk/javax/crypto/Cipher/ByteBuffers.java index 233e62fb83a73..4dd6d86b476be 100644 --- a/test/jdk/javax/crypto/Cipher/ByteBuffers.java +++ b/test/jdk/javax/crypto/Cipher/ByteBuffers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, 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 @@ -27,6 +27,8 @@ * @summary Test the Cipher.update/doFinal(ByteBuffer, ByteBuffer) methods * @author Andreas Sterbenz * @key randomness + * @run main ByteBuffers DES 8 + * @run main ByteBuffers AES 16 */ import java.util.*; @@ -40,17 +42,20 @@ public class ByteBuffers { public static void main(String[] args) throws Exception { - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); Random random = new Random(); int n = 10 * 1024; byte[] t = new byte[n]; random.nextBytes(t); - byte[] keyBytes = new byte[8]; + int keyInt = Integer.parseInt(args[1]); + byte[] keyBytes = new byte[keyInt]; random.nextBytes(keyBytes); - SecretKey key = new SecretKeySpec(keyBytes, "DES"); + String algo = args[0]; + SecretKey key = new SecretKeySpec(keyBytes, algo); - Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding"); + Cipher cipher = Cipher.getInstance(algo + "/ECB/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] outBytes = cipher.doFinal(t); diff --git a/test/jdk/javax/crypto/Cipher/CipherInputStreamExceptions.java b/test/jdk/javax/crypto/Cipher/CipherInputStreamExceptions.java index 15cacec707f02..8ffbb6f6a26c4 100644 --- a/test/jdk/javax/crypto/Cipher/CipherInputStreamExceptions.java +++ b/test/jdk/javax/crypto/Cipher/CipherInputStreamExceptions.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 @@ -357,10 +357,12 @@ static byte[] encryptedText(String mode, int length) throws Exception{ static byte[] encryptedText(String mode, byte[] pt) throws Exception{ Cipher c; if (mode.compareTo("GCM") == 0) { - c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + c = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); c.init(Cipher.ENCRYPT_MODE, key, gcmspec); } else if (mode.compareTo("CBC") == 0) { - c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE"); + c = Cipher.getInstance("AES/CBC/PKCS5Padding", + System.getProperty("test.provider.name", "SunJCE")); c.init(Cipher.ENCRYPT_MODE, key, iv); } else { return null; @@ -380,10 +382,12 @@ static CipherInputStream getStream(String mode, byte[] ct, int length) Cipher c; if (mode.compareTo("GCM") == 0) { - c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + c = Cipher.getInstance("AES/GCM/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); c.init(Cipher.DECRYPT_MODE, key, gcmspec); } else if (mode.compareTo("CBC") == 0) { - c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE"); + c = Cipher.getInstance("AES/CBC/PKCS5Padding", + System.getProperty("test.provider.name", "SunJCE")); c.init(Cipher.DECRYPT_MODE, key, iv); } else { return null; diff --git a/test/jdk/javax/crypto/Cipher/GetMaxAllowed.java b/test/jdk/javax/crypto/Cipher/GetMaxAllowed.java index 7ef6f439aacde..ee0b9c487a651 100644 --- a/test/jdk/javax/crypto/Cipher/GetMaxAllowed.java +++ b/test/jdk/javax/crypto/Cipher/GetMaxAllowed.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, 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 @@ -96,7 +96,8 @@ public static void main(String[] args) throws Exception { // decide if the installed jurisdiction policy file is the // unlimited version boolean isUnlimited = true; - Cipher c = Cipher.getInstance("AES", "SunJCE"); + Cipher c = Cipher.getInstance("AES", + System.getProperty("test.provider.name", "SunJCE")); try { c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[24], "AES")); } catch (InvalidKeyException ike) { diff --git a/test/jdk/javax/crypto/Cipher/TestCipherMode.java b/test/jdk/javax/crypto/Cipher/TestCipherMode.java index 19e854bca3488..83ea6340871f7 100644 --- a/test/jdk/javax/crypto/Cipher/TestCipherMode.java +++ b/test/jdk/javax/crypto/Cipher/TestCipherMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2021, 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 @@ -103,7 +103,9 @@ private static Key getKey(String t, CipherMode m) public static void main(String[] argv) throws Exception { - TestCipherMode test = new TestCipherMode("SunJCE", TRANSFORMATIONS); + TestCipherMode test = new TestCipherMode( + System.getProperty("test.provider.name", "SunJCE"), + TRANSFORMATIONS); System.out.println("All Tests Passed"); } diff --git a/test/jdk/javax/crypto/Cipher/TestGetInstance.java b/test/jdk/javax/crypto/Cipher/TestGetInstance.java index 01d60f63a847e..8d2616574981f 100644 --- a/test/jdk/javax/crypto/Cipher/TestGetInstance.java +++ b/test/jdk/javax/crypto/Cipher/TestGetInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2008, 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,10 +26,13 @@ * @bug 4898428 * @summary test that the new getInstance() implementation works correctly * @author Andreas Sterbenz + * @run main TestGetInstance DES PBEWithMD5AndTripleDES + * @run main TestGetInstance AES PBEWithHmacSHA1AndAES_128 */ import java.security.*; import java.security.spec.*; +import java.util.Locale; import javax.crypto.*; @@ -42,56 +45,64 @@ private static void same(Provider p1, Provider p2) throws Exception { } public static void main(String[] args) throws Exception { - Provider p = Security.getProvider("SunJCE"); + String algo = args[0]; + String algoLC = algo.toLowerCase(Locale.ROOT); + String pbeAlgo = args[1]; + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); Cipher c; - c = Cipher.getInstance("PBEWithMD5AndTripleDES"); + c = Cipher.getInstance(pbeAlgo); same(p, c.getProvider()); - c = Cipher.getInstance("des", "SunJCE"); + c = Cipher.getInstance(algoLC, + System.getProperty("test.provider.name", "SunJCE")); same(p, c.getProvider()); - c = Cipher.getInstance("des/cbc/pkcs5padding", "SunJCE"); + c = Cipher.getInstance(algoLC + "/cbc/pkcs5padding", + System.getProperty("test.provider.name", "SunJCE")); same(p, c.getProvider()); - c = Cipher.getInstance("des", p); + c = Cipher.getInstance(algoLC, p); same(p, c.getProvider()); - c = Cipher.getInstance("des/cbc/pkcs5padding", p); + c = Cipher.getInstance(algoLC + "/cbc/pkcs5padding", p); same(p, c.getProvider()); try { - c = Cipher.getInstance("DES/XYZ/PKCS5Padding"); + c = Cipher.getInstance(algo + "/XYZ/PKCS5Padding"); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); } try { - c = Cipher.getInstance("DES/XYZ/PKCS5Padding", "SunJCE"); + c = Cipher.getInstance(algo + "/XYZ/PKCS5Padding", + System.getProperty("test.provider.name", "SunJCE")); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); } try { - c = Cipher.getInstance("DES/XYZ/PKCS5Padding", p); + c = Cipher.getInstance(algo + "/XYZ/PKCS5Padding", p); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); } try { - c = Cipher.getInstance("DES/CBC/XYZPadding"); + c = Cipher.getInstance(algo + "/CBC/XYZPadding"); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); } try { - c = Cipher.getInstance("DES/CBC/XYZPadding", "SunJCE"); + c = Cipher.getInstance(algo + "/CBC/XYZPadding", + System.getProperty("test.provider.name", "SunJCE")); throw new AssertionError(); } catch (NoSuchPaddingException e) { System.out.println(e); } try { - c = Cipher.getInstance("DES/CBC/XYZPadding", p); + c = Cipher.getInstance(algo + "/CBC/XYZPadding", p); throw new AssertionError(); } catch (NoSuchPaddingException e) { System.out.println(e); @@ -104,7 +115,8 @@ public static void main(String[] args) throws Exception { System.out.println(e); } try { - c = Cipher.getInstance("foo", "SunJCE"); + c = Cipher.getInstance("foo", + System.getProperty("test.provider.name", "SunJCE")); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); @@ -117,13 +129,15 @@ public static void main(String[] args) throws Exception { } try { - c = Cipher.getInstance("foo", "SUN"); + c = Cipher.getInstance("foo", + System.getProperty("test.provider.name", "SUN")); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); } try { - c = Cipher.getInstance("foo", Security.getProvider("SUN")); + c = Cipher.getInstance("foo", Security.getProvider( + System.getProperty("test.provider.name", "SUN"))); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); diff --git a/test/jdk/javax/crypto/CipherSpi/DirectBBRemaining.java b/test/jdk/javax/crypto/CipherSpi/DirectBBRemaining.java index 9e03c9086609c..9487792df08fb 100644 --- a/test/jdk/javax/crypto/CipherSpi/DirectBBRemaining.java +++ b/test/jdk/javax/crypto/CipherSpi/DirectBBRemaining.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 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,6 +27,8 @@ * @summary Cipher.doFinal(ByteBuffer,ByteBuffer) fails to * process when in.remaining() == 0 * @key randomness + * @run main DirectBBRemaining DES 8 + * @run main DirectBBRemaining AES 16 */ import java.nio.ByteBuffer; @@ -53,11 +55,14 @@ public static void main(String args[]) throws Exception { boolean failedOnce = false; Exception failedReason = null; - byte[] keyBytes = new byte[8]; + int keyInt = Integer.parseInt(args[1]); + byte[] keyBytes = new byte[keyInt]; random.nextBytes(keyBytes); - SecretKey key = new SecretKeySpec(keyBytes, "DES"); + String algo = args[0]; + SecretKey key = new SecretKeySpec(keyBytes, algo); - Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding", "SunJCE"); + Cipher cipher = Cipher.getInstance(algo + "/CBC/PKCS5Padding", + System.getProperty("test.provider.name", "SunJCE")); cipher.init(Cipher.ENCRYPT_MODE, key); /* diff --git a/test/jdk/javax/crypto/CryptoPermission/AllPermCheck.java b/test/jdk/javax/crypto/CryptoPermission/AllPermCheck.java index d7a1ad40e39a6..c2fef8785e170 100644 --- a/test/jdk/javax/crypto/CryptoPermission/AllPermCheck.java +++ b/test/jdk/javax/crypto/CryptoPermission/AllPermCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, 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 @@ -29,6 +29,8 @@ * crypto permssion checks failed. * @author Valerie Peng * @key randomness + * @run main AllPermCheck DES + * @run main AllPermCheck AES */ import java.io.*; @@ -84,9 +86,10 @@ public static void runTest(Cipher c, Key key) throws Exception { } public static void main(String[] args) throws Exception { - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + p.getName() + "..."); - if (Cipher.getMaxAllowedKeyLength("DES") == Integer.MAX_VALUE) { + String transformation = args[0]; + if (Cipher.getMaxAllowedKeyLength(transformation) == Integer.MAX_VALUE) { // skip this test for unlimited jurisdiction policy files System.out.println("Skip this test due to unlimited version"); return; diff --git a/test/jdk/javax/crypto/CryptoPermission/LowercasePermCheck.java b/test/jdk/javax/crypto/CryptoPermission/LowercasePermCheck.java index c358cb108441f..97f6f4fd1036d 100644 --- a/test/jdk/javax/crypto/CryptoPermission/LowercasePermCheck.java +++ b/test/jdk/javax/crypto/CryptoPermission/LowercasePermCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2007, 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 @@ -46,9 +46,9 @@ public class LowercasePermCheck { }; public static void main(String[] args) throws Exception { - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + p.getName() + "..."); - if (Cipher.getMaxAllowedKeyLength("DES") == Integer.MAX_VALUE) { + if (Cipher.getMaxAllowedKeyLength("AES") == Integer.MAX_VALUE) { // skip this test for unlimited jurisdiction policy files System.out.println("Skip this test due to unlimited version"); return; diff --git a/test/jdk/javax/crypto/CryptoPermission/RSANoLimit.java b/test/jdk/javax/crypto/CryptoPermission/RSANoLimit.java index 4f54ff8ce3e92..54ba18b98e10c 100644 --- a/test/jdk/javax/crypto/CryptoPermission/RSANoLimit.java +++ b/test/jdk/javax/crypto/CryptoPermission/RSANoLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2007, 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 @@ -135,7 +135,7 @@ public class RSANoLimit { }; public static void main(String[] args) throws Exception { boolean result = true; - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); System.out.println("Testing provider " + p.getName() + "..."); // Test#1: make sure Cipher.getMaxAllowedKeyLength returns the // correct value diff --git a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetAlgName.java b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetAlgName.java index 33b624e4a2890..3b89257323bc1 100644 --- a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetAlgName.java +++ b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetAlgName.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 @@ -47,9 +47,11 @@ public static void main(String[] argv) throws Exception { String algo = ALGOS[i]; // generate AlgorithmParameters object SecretKeyFactory skf = - SecretKeyFactory.getInstance(algo, "SunJCE"); + SecretKeyFactory.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); SecretKey key = skf.generateSecret(ks); - Cipher c = Cipher.getInstance(algo, "SunJCE"); + Cipher c = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); c.init(Cipher.ENCRYPT_MODE, key); c.doFinal(BYTES); // force the parameter generation if not already diff --git a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpec.java b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpec.java index 314742cbf8d66..cc0adc18e56aa 100644 --- a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpec.java +++ b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, 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,8 @@ * @bug 4508341 * @summary Test the EncryptedPrivateKeyInfo.getKeySpec(...) methods. * @author Valerie Peng + * @run main/othervm -DcipherAlg=PBEWithMD5AndDES GetKeySpec + * @run main/othervm -DcipherAlg=PBEWithSHA1AndDESede GetKeySpec */ import java.util.*; import java.nio.*; @@ -37,16 +39,17 @@ import javax.crypto.spec.*; public class GetKeySpec { - private static final String cipherAlg = "PBEWithMD5AndDES"; + private static String cipherAlg; private static final char[] passwd = { 'p','a','s','s','w','d' }; private static AlgorithmParameters GOOD_PARAMS; static { try { + cipherAlg = System.getProperty("cipherAlg"); PBEParameterSpec goodParamSpec = new PBEParameterSpec(new byte[8], 1024); GOOD_PARAMS = AlgorithmParameters.getInstance - (cipherAlg, "SunJCE"); + (cipherAlg, System.getProperty("test.provider.name", "SunJCE")); GOOD_PARAMS.init(goodParamSpec); } catch (Exception ex) { // should never happen @@ -55,7 +58,8 @@ public class GetKeySpec { } private static String pkcs8Encoded = "30:82:01:53:02:01:00:30:0D:06:09:2A:86:48:86:F7:0D:01:01:01:05:00:04:82:01:3D:30:82:01:39:02:01:00:02:40:6E:A4:13:65:97:A2:C2:47:5E:F2:23:6B:94:D8:D7:25:13:BB:A4:AE:8A:AA:A7:27:A4:9A:04:DC:15:F7:9B:E4:39:18:99:9E:27:EA:92:BB:D0:0E:F3:26:F4:95:89:33:02:65:6D:84:69:2C:CE:B7:FA:68:8E:FE:8D:63:44:6B:02:03:01:00:01:02:40:59:6E:1C:13:98:FE:C1:04:89:75:35:36:27:29:22:B5:E0:7E:62:BD:86:6E:2C:10:7A:16:D8:68:C1:04:D4:A7:10:41:F7:B9:B4:84:05:03:A5:C0:28:73:24:A7:24:F1:1B:C3:4F:BF:05:20:D0:D9:00:08:7F:C3:29:64:1B:29:02:21:00:C4:63:4D:0C:32:51:44:AE:DD:90:A9:B7:B6:C2:6B:11:BE:D2:07:E7:B5:C2:4A:9F:4D:0F:2F:30:5F:E6:1C:6D:02:21:00:90:39:A4:2D:93:0B:08:AF:2F:6F:18:CC:1A:EF:B6:E6:01:E7:21:3A:7F:45:C7:3F:39:12:B8:CC:DF:44:2D:37:02:21:00:B3:9B:61:9E:B2:F2:12:4F:9E:C1:2C:06:A1:B5:A3:38:62:7D:31:CF:9F:32:67:0E:D3:E9:FC:2D:50:B7:61:ED:02:20:5B:FD:77:FB:5D:A3:97:09:6E:1E:D5:59:32:01:1D:CE:7C:FE:38:12:80:A5:38:1D:DA:40:57:C0:CC:D3:46:67:02:20:52:EC:61:05:0D:EC:8A:ED:F7:1E:95:67:D0:7C:8B:D9:AA:A5:33:B8:26:26:2E:8F:D7:A7:18:16:2A:83:63:5C"; - private static String encryptedPKCS8 = "AE:20:81:4F:4D:38:73:C0:51:70:42:DA:C2:EF:61:49:07:E9:B5:D5:55:6D:D1:50:54:B2:0B:41:3E:2F:B6:00:BC:30:89:7B:32:A5:5F:B6:86:92:9E:06:6E:E2:40:8E:3E:E8:0B:CA:97:DB:3E:72:3E:03:22:34:35:EA:5F:B0:71:B2:07:BC:0D:97:94:0A:E6:12:9B:60:7A:77:D4:6C:99:60:2E:68:D6:55:BE:83:B8:A9:0F:19:8A:BE:91:30:D0:FE:52:94:5A:4C:D7:24:07:B3:61:EB:B5:4A:C6:6F:96:8A:C0:20:E9:73:40:FA:A2:56:04:F2:43:35:90:EA:35:C9:8C:08:9D:0B:BC:37:F0:01:D5:DF:BE:E4:4A:57:E0:13:0C:D5:F0:E8:5C:3B:B3:CD:7E:B5:E8:A5:84:63:F6:DA:3E:F2:CF:53:1F:A2:86:44:61:DD:AF:C1:78:70:3A:E6:06:41:77:6C:5B:8D:FA:C4:39:D7:4D:2F:87:D8:31:F4:B6:2B:94:D9:87:17:0E:C8:E3:FA:54:C8:B2:44:56:E0:37:5F:4C:5D:B2:21:DD:15:9E:94:63:89:CF:07:8C:79:F8:65:B2:22:45:D5:F0:2A:70:19:61:16:1D:52:5E:0C:35:3B:20:88:17:7E:FD:05:CC:08:09:2F:05:61:F7:A8:F5:EA:DE:77:DE:5D:55:4E:A0:36:A1:13:FF:2D:57:E8:4E:06:CE:C9:C1:B1:AE:C6:52:A6:EB:35:4C:81:91:DE:71:BA:34:DA:8A:99:1A:47:2E:66:52:AF:E3:2A:E4:0A:27:7F:72:C4:90:7E:8D:8F:64:8D:21:7E:00:DC:1C:62:0F:CC:96:80:C7:E5:5B:70:48:A5:E7:34:27:1A:7C:48:A7:9E:8B:2B:A6:E2"; + private static String sha1EncryptedPKCS8 = "0D:CA:00:8F:64:91:9C:60:36:F5:9B:BD:DD:C5:A9:A2:27:9E:6B:AE:CB:23:0E:2F:DA:76:03:A5:B7:C0:D5:3E:B9:03:60:62:41:2C:D6:51:37:F0:D9:ED:B2:CC:E7:99:28:03:CD:20:5D:EC:56:77:FC:61:57:D7:8C:F3:F6:10:F7:E5:BA:88:04:FE:1A:17:B3:8C:36:BF:70:2D:CD:6F:BF:83:ED:03:41:22:95:68:E3:08:90:76:B5:97:CB:FF:CE:51:27:14:F6:38:00:22:E9:0F:86:9F:64:D2:47:34:F6:50:DA:A9:80:F5:67:BF:C7:51:B3:38:AF:CD:15:96:50:8F:33:F3:8B:43:4C:AF:ED:DD:37:03:EC:B1:CC:57:53:0A:AF:0D:53:CD:D7:2B:A2:20:C5:37:AF:09:78:8E:3F:A0:E4:EC:22:C6:71:EC:D1:42:15:9D:1D:E9:E3:9D:8F:D6:0B:2A:99:C9:C8:90:B1:CD:AB:17:DD:A3:6F:64:43:23:26:25:7B:A5:E0:1F:2E:AF:18:89:C8:D6:97:28:32:A1:01:22:6F:14:B6:6C:4E:8A:83:47:16:99:51:B4:8D:85:9E:AB:00:B5:18:BB:49:97:47:59:F8:A7:A8:64:76:3F:41:5F:71:1A:F3:4A:96:F2:B4:44:38:42:4B:AE:0F:08:83:5C:33:F8:6A:8F:B9:6A:3D:1C:06:02:4E:07:48:46:E0:6D:6D:ED:E8:19:CB:3F:B0:6F:10:68:3A:5E:F5:8F:94:EF:B4:8B:58:5F:50:0A:E5:F2:13:54:59:14:99:C5:74:02:A2:B1:73:16:7F:F2:D4:DE:E0:12:86:55:46:9C:57:D1:7A:5C:8B:46:E1:7E:C3:32:14:31:52:64:07:52:9D:65:04:9D:54:89"; + private static String md5EncryptedPKCS8 = "AE:20:81:4F:4D:38:73:C0:51:70:42:DA:C2:EF:61:49:07:E9:B5:D5:55:6D:D1:50:54:B2:0B:41:3E:2F:B6:00:BC:30:89:7B:32:A5:5F:B6:86:92:9E:06:6E:E2:40:8E:3E:E8:0B:CA:97:DB:3E:72:3E:03:22:34:35:EA:5F:B0:71:B2:07:BC:0D:97:94:0A:E6:12:9B:60:7A:77:D4:6C:99:60:2E:68:D6:55:BE:83:B8:A9:0F:19:8A:BE:91:30:D0:FE:52:94:5A:4C:D7:24:07:B3:61:EB:B5:4A:C6:6F:96:8A:C0:20:E9:73:40:FA:A2:56:04:F2:43:35:90:EA:35:C9:8C:08:9D:0B:BC:37:F0:01:D5:DF:BE:E4:4A:57:E0:13:0C:D5:F0:E8:5C:3B:B3:CD:7E:B5:E8:A5:84:63:F6:DA:3E:F2:CF:53:1F:A2:86:44:61:DD:AF:C1:78:70:3A:E6:06:41:77:6C:5B:8D:FA:C4:39:D7:4D:2F:87:D8:31:F4:B6:2B:94:D9:87:17:0E:C8:E3:FA:54:C8:B2:44:56:E0:37:5F:4C:5D:B2:21:DD:15:9E:94:63:89:CF:07:8C:79:F8:65:B2:22:45:D5:F0:2A:70:19:61:16:1D:52:5E:0C:35:3B:20:88:17:7E:FD:05:CC:08:09:2F:05:61:F7:A8:F5:EA:DE:77:DE:5D:55:4E:A0:36:A1:13:FF:2D:57:E8:4E:06:CE:C9:C1:B1:AE:C6:52:A6:EB:35:4C:81:91:DE:71:BA:34:DA:8A:99:1A:47:2E:66:52:AF:E3:2A:E4:0A:27:7F:72:C4:90:7E:8D:8F:64:8D:21:7E:00:DC:1C:62:0F:CC:96:80:C7:E5:5B:70:48:A5:E7:34:27:1A:7C:48:A7:9E:8B:2B:A6:E2"; private static byte[] parse(String s) { try { @@ -99,10 +103,10 @@ public static void main(String[] argv) throws Exception { throw new Exception("Static parameter generation failed"); } byte[] encodedKey = parse(pkcs8Encoded); - byte[] encryptedData = parse(encryptedPKCS8); + byte[] encryptedData = parse(cipherAlg.contains("MD5") ? md5EncryptedPKCS8 : sha1EncryptedPKCS8); boolean result = true; - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); // generate encrypted data and EncryptedPrivateKeyInfo object EncryptedPrivateKeyInfo epki = diff --git a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecException.java b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecException.java index e3ecb33d91c2a..f55f1eea42ce6 100644 --- a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecException.java +++ b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,8 @@ * @summary Test the error conditions of * EncryptedPrivateKeyInfo.getKeySpec(...) methods. * @author Valerie Peng + * @run main/othervm -DcipherAlg=PBEWithMD5AndDES GetKeySpecException + * @run main/othervm -DcipherAlg=PBEWithSHA1AndDESede GetKeySpecException */ import java.security.*; import java.util.Arrays; @@ -37,7 +39,7 @@ import javax.crypto.spec.*; public class GetKeySpecException { - private static final String cipherAlg = "PBEWithMD5AndDES"; + private static String cipherAlg; private static final char[] passwd = { 'p','a','s','s','w','d' }; private static SecretKey cipherKey; private static Cipher cipher = null; @@ -50,7 +52,8 @@ public class GetKeySpecException { static { try { - sunjce = Security.getProvider("SunJCE"); + cipherAlg = System.getProperty("cipherAlg"); + sunjce = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); PBEParameterSpec badParamSpec = new PBEParameterSpec(new byte[10], 10); BAD_PARAMS = AlgorithmParameters.getInstance(cipherAlg, sunjce); @@ -61,7 +64,7 @@ public class GetKeySpecException { GOOD_PARAMS.init(goodParamSpec); PBEKeySpec keySpec = new PBEKeySpec(passwd); SecretKeyFactory skf = - SecretKeyFactory.getInstance(cipherAlg, "SunJCE"); + SecretKeyFactory.getInstance(cipherAlg, System.getProperty("test.provider.name", "SunJCE")); cipherKey = skf.generateSecret(keySpec); } catch (Exception ex) { // should never happen @@ -164,7 +167,7 @@ public static void main0(String[] args) throws Exception { // TEST#3: getKeySpec(Key, String) System.out.println("Testing getKeySpec(Key, String)..."); try { - pkcs8Spec = epki.getKeySpec(null, "SunJCE"); + pkcs8Spec = epki.getKeySpec(null, System.getProperty("test.provider.name", "SunJCE")); throwException("Should throw NPE for null Key!"); } catch (NullPointerException npe) { System.out.println("Expected NPE thrown"); @@ -176,13 +179,13 @@ public static void main0(String[] args) throws Exception { System.out.println("Expected NPE thrown"); } try { - pkcs8Spec = epki.getKeySpec(INVALID_KEY, "SunJCE"); + pkcs8Spec = epki.getKeySpec(INVALID_KEY, System.getProperty("test.provider.name", "SunJCE")); throwException("Should throw IKE for invalid Key!"); } catch (InvalidKeyException ikse) { System.out.println("Expected IKE thrown"); } try { - pkcs8Spec = epkiBad.getKeySpec(cipherKey, "SunJCE"); + pkcs8Spec = epkiBad.getKeySpec(cipherKey, System.getProperty("test.provider.name", "SunJCE")); throwException("Should throw IKE for corrupted epki!"); } catch (InvalidKeyException ike) { System.out.println("Expected IKE thrown"); @@ -195,8 +198,9 @@ public static void main0(String[] args) throws Exception { System.out.println("Expected NSAE thrown"); } try { - Security.removeProvider("SunJCE"); - pkcs8Spec = epki.getKeySpec(cipherKey, "SunJCE"); + Security.removeProvider(System.getProperty("test.provider.name", "SunJCE")); + pkcs8Spec = epki.getKeySpec(cipherKey, + System.getProperty("test.provider.name", "SunJCE")); throwException("Should throw NSPE for unconfigured provider!"); } catch (NoSuchProviderException nspe) { System.out.println("Expected NSPE thrown"); diff --git a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecException2.java b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecException2.java index a3f983d0ea409..1fad8b7007128 100644 --- a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecException2.java +++ b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecException2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2007, 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 @@ -28,6 +28,8 @@ * with wrong mode with EncryptedPrivateKeyInfo.getKeySpec * (Cipher) method. * @author Valerie Peng + * @run main GetKeySpecException2 PBEWithMD5AndDES + * @run main GetKeySpecException2 PBEWithSHA1AndDESede */ import java.security.*; import java.util.Arrays; @@ -38,11 +40,10 @@ import javax.crypto.spec.*; public class GetKeySpecException2 { - private static final String cipherAlg = "PBEWithMD5AndDES"; private static final char[] passwd = { 'p','a','s','s','w','d' }; - public static void main(String[] argv) throws Exception { - + public static void main(String[] args) throws Exception { + String cipherAlg = args[0]; // use random data byte[] encryptedData = new byte[30]; encryptedData[20] = (byte) 8; @@ -54,7 +55,8 @@ public static void main(String[] argv) throws Exception { // TEST#1: getKeySpec(Cipher) with Cipher in an illegal state, // i.e. WRAP_MODE, UNWRAP_MODE. System.out.println("Testing getKeySpec(Cipher) with WRAP_MODE..."); - Cipher c = Cipher.getInstance(cipherAlg, "SunJCE"); + Cipher c = Cipher.getInstance(cipherAlg, + System.getProperty("test.provider.name", "SunJCE")); MyPBEKey key = new MyPBEKey(passwd); c.init(Cipher.WRAP_MODE, key); try { diff --git a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecInvalidEncoding.java b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecInvalidEncoding.java index fcc5133248828..40c112b42eefd 100644 --- a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecInvalidEncoding.java +++ b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeySpecInvalidEncoding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,8 @@ * methods with scenarios where the decrypted bytes are not * encoded correctly per PKCS#8 standard. * @author Valerie Peng + * @run main/othervm -DcipherAlg=PBEWithMD5AndDES GetKeySpecInvalidEncoding + * @run main/othervm -DcipherAlg=PBEWithSHA1AndDESede GetKeySpecInvalidEncoding */ import java.util.*; import java.nio.*; @@ -39,16 +41,17 @@ import javax.crypto.spec.*; public class GetKeySpecInvalidEncoding { - private static final String cipherAlg = "PBEWithMD5AndDES"; + private static String cipherAlg; private static final char[] passwd = { 'p','a','s','s', 'w', 'd' }; private static AlgorithmParameters GOOD_PARAMS; static { try { + cipherAlg = System.getProperty("cipherAlg"); PBEParameterSpec goodParamSpec = new PBEParameterSpec(new byte[8], 6); GOOD_PARAMS = AlgorithmParameters.getInstance - (cipherAlg, "SunJCE"); + (cipherAlg, System.getProperty("test.provider.name", "SunJCE")); GOOD_PARAMS.init(goodParamSpec); } catch (Exception ex) { // should never happen @@ -101,7 +104,7 @@ public static void main(String[] argv) throws Exception { } byte[] encryptedData = parse(encryptedPKCS8); - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); // generate encrypted data and EncryptedPrivateKeyInfo object EncryptedPrivateKeyInfo epki = diff --git a/test/jdk/javax/crypto/KeyGenerator/TestGetInstance.java b/test/jdk/javax/crypto/KeyGenerator/TestGetInstance.java index 53c766874edaf..96e8f794d9b1b 100644 --- a/test/jdk/javax/crypto/KeyGenerator/TestGetInstance.java +++ b/test/jdk/javax/crypto/KeyGenerator/TestGetInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, 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,8 @@ * @bug 4898428 * @summary test that the new getInstance() implementation works correctly * @author Andreas Sterbenz + * @run main TestGetInstance des + * @run main TestGetInstance aes */ import java.security.*; @@ -43,15 +45,17 @@ private static void same(Object o1, Object o2) throws Exception { public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); KeyGenerator kg; - kg = KeyGenerator.getInstance("des"); + String algo = args[0]; + kg = KeyGenerator.getInstance(algo); System.out.println("Default: " + kg.getProvider().getName()); - kg = KeyGenerator.getInstance("des", "SunJCE"); + kg = KeyGenerator.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); same(p, kg.getProvider()); - kg = KeyGenerator.getInstance("des", p); + kg = KeyGenerator.getInstance(algo, p); same(p, kg.getProvider()); try { @@ -61,7 +65,8 @@ public static void main(String[] args) throws Exception { System.out.println(e); } try { - kg = KeyGenerator.getInstance("foo", "SunJCE"); + kg = KeyGenerator.getInstance("foo", + System.getProperty("test.provider.name", "SunJCE")); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); @@ -74,13 +79,15 @@ public static void main(String[] args) throws Exception { } try { - kg = KeyGenerator.getInstance("foo", "SUN"); + kg = KeyGenerator.getInstance("foo", + System.getProperty("test.provider.name", "SUN")); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); } try { - kg = KeyGenerator.getInstance("foo", Security.getProvider("SUN")); + kg = KeyGenerator.getInstance("foo", + Security.getProvider(System.getProperty("test.provider.name", "SUN"))); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); diff --git a/test/jdk/javax/crypto/KeyGenerator/TestKGParity.java b/test/jdk/javax/crypto/KeyGenerator/TestKGParity.java index efaefb06199f6..65e9b062de7a1 100644 --- a/test/jdk/javax/crypto/KeyGenerator/TestKGParity.java +++ b/test/jdk/javax/crypto/KeyGenerator/TestKGParity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,8 +54,10 @@ private void run() throws Exception { Provider[] providers = Security.getProviders(); for (Provider p : providers) { String prvName = p.getName(); - if (prvName.startsWith("SunJCE") - || prvName.startsWith("SunPKCS11-")) { + if ((System.getProperty("test.provider.name") != null && + prvName.equals(System.getProperty("test.provider.name"))) || + (System.getProperty("test.provider.name") == null && + (prvName.startsWith("SunJCE") || prvName.startsWith("SunPKCS11-")))) { for (String algorithm : ALGORITHM_ARR) { if (!runTest(p, algorithm)) { throw new RuntimeException( diff --git a/test/jdk/javax/crypto/Mac/ByteBuffers.java b/test/jdk/javax/crypto/Mac/ByteBuffers.java index a00e5a43cd6c6..eafd2b89e1a1c 100644 --- a/test/jdk/javax/crypto/Mac/ByteBuffers.java +++ b/test/jdk/javax/crypto/Mac/ByteBuffers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, 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 @@ -27,6 +27,8 @@ * @summary Test the Mac.update(ByteBuffer) method * @author Andreas Sterbenz * @key randomness + * @run main ByteBuffers HmacMD5 + * @run main ByteBuffers HmacSha256 */ import java.util.*; @@ -40,17 +42,18 @@ public class ByteBuffers { public static void main(String[] args) throws Exception { - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); Random random = new Random(); int n = 10 * 1024; byte[] t = new byte[n]; random.nextBytes(t); + String algo = args[0]; byte[] keyBytes = new byte[16]; random.nextBytes(keyBytes); - SecretKey key = new SecretKeySpec(keyBytes, "HmacMD5"); + SecretKey key = new SecretKeySpec(keyBytes, algo); - Mac mac = Mac.getInstance("HmacMD5"); + Mac mac = Mac.getInstance(algo); mac.init(key); byte[] macValue = mac.doFinal(t); diff --git a/test/jdk/javax/crypto/Mac/TestGetInstance.java b/test/jdk/javax/crypto/Mac/TestGetInstance.java index 30d055423db4b..85982799bd054 100644 --- a/test/jdk/javax/crypto/Mac/TestGetInstance.java +++ b/test/jdk/javax/crypto/Mac/TestGetInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, 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,8 @@ * @bug 4898428 * @summary test that the new getInstance() implementation works correctly * @author Andreas Sterbenz + * @run main TestGetInstance hmacmd5 + * @run main TestGetInstance hmacsha256 */ import java.security.*; @@ -43,15 +45,16 @@ private static void same(Object o1, Object o2) throws Exception { public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); - Provider p = Security.getProvider("SunJCE"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SunJCE")); Mac mac; - mac = Mac.getInstance("hmacmd5"); + String algo = args[0]; + mac = Mac.getInstance(algo); System.out.println("Default: " + mac.getProvider().getName()); - mac = Mac.getInstance("hmacmd5", "SunJCE"); + mac = Mac.getInstance(algo, System.getProperty("test.provider.name", "SunJCE")); same(p, mac.getProvider()); - mac = Mac.getInstance("hmacmd5", p); + mac = Mac.getInstance(algo, p); same(p, mac.getProvider()); try { @@ -61,7 +64,7 @@ public static void main(String[] args) throws Exception { System.out.println(e); } try { - mac = Mac.getInstance("foo", "SunJCE"); + mac = Mac.getInstance("foo", System.getProperty("test.provider.name", "SunJCE")); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); @@ -74,13 +77,14 @@ public static void main(String[] args) throws Exception { } try { - mac = Mac.getInstance("foo", "SUN"); + mac = Mac.getInstance("foo", System.getProperty("test.provider.name", "SUN")); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); } try { - mac = Mac.getInstance("foo", Security.getProvider("SUN")); + mac = Mac.getInstance("foo", Security.getProvider( + System.getProperty("test.provider.name", "SUN"))); throw new AssertionError(); } catch (NoSuchAlgorithmException e) { System.out.println(e); diff --git a/test/jdk/javax/crypto/SecretKeyFactory/SecKFTranslateTest.java b/test/jdk/javax/crypto/SecretKeyFactory/SecKFTranslateTest.java index f1b5c82579889..398cf12a97eaa 100644 --- a/test/jdk/javax/crypto/SecretKeyFactory/SecKFTranslateTest.java +++ b/test/jdk/javax/crypto/SecretKeyFactory/SecKFTranslateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, 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 @@ -50,7 +50,8 @@ */ public class SecKFTranslateTest { - private static final String SUN_JCE = "SunJCE"; + private static final String PROVIDER_NAME = + System.getProperty("test.provider.name", "SunJCE"); public static void main(String[] args) throws Exception { @@ -77,10 +78,10 @@ private void runTest(Algorithm algo) throws NoSuchAlgorithmException, Random random = new Random(); // Initialization SecretKeyFactory skf = SecretKeyFactory.getInstance(algo.toString(), - SUN_JCE); + PROVIDER_NAME); random.nextBytes(plainText); - Cipher ci = Cipher.getInstance(algo.toString(), SUN_JCE); + Cipher ci = Cipher.getInstance(algo.toString(), PROVIDER_NAME); // Encryption ci.init(Cipher.ENCRYPT_MODE, key1, aps[0]); byte[] cipherText = new byte[ci.getOutputSize(plainText.length)]; diff --git a/test/jdk/javax/crypto/SecretKeyFactory/SecKeyFacSunJCEPrf.java b/test/jdk/javax/crypto/SecretKeyFactory/SecKeyFacSunJCEPrf.java index c5080ba33c5fc..8501f888e0f83 100644 --- a/test/jdk/javax/crypto/SecretKeyFactory/SecKeyFacSunJCEPrf.java +++ b/test/jdk/javax/crypto/SecretKeyFactory/SecKeyFacSunJCEPrf.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -42,11 +42,11 @@ public class SecKeyFacSunJCEPrf { // One of the PBKDF2 HMAC-SHA1 test vectors from RFC 6070 - private static final byte[] SALT = "salt".getBytes(); + private static final byte[] SALT = "16-byte salt val".getBytes(); private static final char[] PASS = "password".toCharArray(); private static final int ITER = 4096; private static final byte[] EXP_OUT = - HexFormat.of().parseHex("4B007901B765489ABEAD49D926F721D065A429C1"); + HexFormat.of().parseHex("D2CACD3F1D44AF293C704F0B1005338D903C688C"); public static void main(String[] args) throws Exception { // Instantiate the Evil Provider and insert it in the @@ -56,7 +56,8 @@ public static void main(String[] args) throws Exception { Security.insertProviderAt(evilProv, 1); SecretKeyFactory pbkdf2 = - SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1", "SunJCE"); + SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1", + System.getProperty("test.provider.name", "SunJCE")); PBEKeySpec pbks = new PBEKeySpec(PASS, SALT, ITER, 160); SecretKey secKey1 = pbkdf2.generateSecret(pbks); diff --git a/test/jdk/javax/crypto/SecretKeyFactory/evilprov/com/evilprovider/EvilHmacSHA1.java b/test/jdk/javax/crypto/SecretKeyFactory/evilprov/com/evilprovider/EvilHmacSHA1.java index 2617928ff161b..06310056274f9 100644 --- a/test/jdk/javax/crypto/SecretKeyFactory/evilprov/com/evilprovider/EvilHmacSHA1.java +++ b/test/jdk/javax/crypto/SecretKeyFactory/evilprov/com/evilprovider/EvilHmacSHA1.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 @@ -33,7 +33,8 @@ public final class EvilHmacSHA1 extends MacSpi { private final Mac internalMac; public EvilHmacSHA1() throws GeneralSecurityException { - internalMac = Mac.getInstance("HmacSHA1", "SunJCE"); + internalMac = Mac.getInstance("HmacSHA1", + System.getProperty("test.provider.name", "SunJCE")); } @Override diff --git a/test/jdk/javax/imageio/plugins/wbmp/WBMPStreamTruncateTest.java b/test/jdk/javax/imageio/plugins/wbmp/WBMPStreamTruncateTest.java index 36b8d4a72e0fd..0d38869634e6b 100644 --- a/test/jdk/javax/imageio/plugins/wbmp/WBMPStreamTruncateTest.java +++ b/test/jdk/javax/imageio/plugins/wbmp/WBMPStreamTruncateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,6 @@ public class WBMPStreamTruncateTest static final int height = 100; public static void main(String[] args) throws IOException { - String sep = System.getProperty("file.separator"); - String dir = System.getProperty("test.src", "."); - String filePath = dir+sep; BufferedImage srcImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); Graphics2D g = (Graphics2D) srcImage.getGraphics(); @@ -57,7 +54,7 @@ public static void main(String[] args) throws IOException g.dispose(); // create WBMP image File imageFile = File. - createTempFile("test", ".wbmp", new File(filePath)); + createTempFile("test", ".wbmp", new File("./")); imageFile.deleteOnExit(); ImageIO.write(srcImage, "wbmp", imageFile); BufferedImage testImg = diff --git a/test/jdk/javax/management/remote/mandatory/connection/DeadLockTest.java b/test/jdk/javax/management/remote/mandatory/connection/DeadLockTest.java index e9f060248ec58..0526f86b4a1f1 100644 --- a/test/jdk/javax/management/remote/mandatory/connection/DeadLockTest.java +++ b/test/jdk/javax/management/remote/mandatory/connection/DeadLockTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2015, 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 @@ -46,21 +46,23 @@ public class DeadLockTest { public static void main(String[] args) { System.out.println(">>> test on a client notification deadlock."); - boolean ok = true; + boolean fail = false; for (int i = 0; i < protocols.length; i++) { try { test(protocols[i]); } catch (Exception e) { + fail = true; // any one protocol failure, fails the test System.out.println(">>> Test failed for " + protocols[i]); e.printStackTrace(System.out); } } - + if (fail) { + throw new RuntimeException("FAILED"); + } System.out.println(">>> Test passed"); } - private static void test(String proto) - throws Exception { + private static void test(String proto) throws Exception { System.out.println(">>> Test for protocol " + proto); JMXServiceURL u = null; @@ -78,6 +80,7 @@ private static void test(String proto) server = JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs); } catch (MalformedURLException e) { System.out.println(">>> Skipping unsupported URL " + proto); + return; // skip testing this protocol } server.start(); @@ -101,10 +104,10 @@ private static void test(String proto) // which should be closed by the server. conn.getDefaultDomain(); - // allow the listner to have time to work + // allow the listener to have time to work Thread.sleep(100); - // get a closed notif, should no block. + // get a closed notif, should not block. client.close(); Thread.sleep(100); diff --git a/test/jdk/javax/management/remote/mandatory/connection/IIOPURLTest.java b/test/jdk/javax/management/remote/mandatory/connection/IIOPURLTest.java deleted file mode 100644 index cdbf829a9b22e..0000000000000 --- a/test/jdk/javax/management/remote/mandatory/connection/IIOPURLTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4886799 - * @summary Check that IIOP URLs have /ior/ in the path - * @author Eamonn McManus - * - * @run clean IIOPURLTest - * @run build IIOPURLTest - * @run main IIOPURLTest - */ - -import javax.management.MBeanServer; -import javax.management.MBeanServerConnection; -import javax.management.MBeanServerFactory; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.ObjectName; - -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXServiceURL; - -public class IIOPURLTest { - - public static void main(String[] args) throws Exception { - JMXServiceURL inputAddr = - new JMXServiceURL("service:jmx:iiop://"); - JMXConnectorServer s; - try { - s = JMXConnectorServerFactory.newJMXConnectorServer(inputAddr, null, null); - } catch (java.net.MalformedURLException x) { - try { - Class.forName("javax.management.remote.rmi._RMIConnectionImpl_Tie"); - throw new RuntimeException("MalformedURLException thrown but iiop appears to be supported"); - } catch (ClassNotFoundException expected) { } - System.out.println("IIOP protocol not supported, test skipped"); - return; - } - MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - mbs.registerMBean(s, new ObjectName("a:b=c")); - s.start(); - JMXServiceURL outputAddr = s.getAddress(); - if (!outputAddr.getURLPath().startsWith("/ior/IOR:")) { - throw new RuntimeException("URL path should start with \"/ior/IOR:\": " + - outputAddr); - } - System.out.println("IIOP URL path looks OK: " + outputAddr); - JMXConnector c = JMXConnectorFactory.connect(outputAddr); - System.out.println("Successfully got default domain: " + - c.getMBeanServerConnection().getDefaultDomain()); - c.close(); - s.stop(); - } -} diff --git a/test/jdk/javax/management/security/HashedPasswordFileTest.java b/test/jdk/javax/management/security/HashedPasswordFileTest.java index 195a9cd344993..f84e00abd4ede 100644 --- a/test/jdk/javax/management/security/HashedPasswordFileTest.java +++ b/test/jdk/javax/management/security/HashedPasswordFileTest.java @@ -110,9 +110,7 @@ private String[] getHash(String algorithm, String password) { } private String getPasswordFilePath() { - String testDir = System.getProperty("test.src"); - String testFileName = "jmxremote.password"; - return testDir + File.separator + testFileName; + return "jmxremote.password"; } private File createNewPasswordFile() throws IOException { diff --git a/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java b/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java index 304cb0695d618..120e6b258e630 100644 --- a/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java +++ b/test/jdk/javax/net/ssl/DTLS/InvalidRecords.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 @@ -26,7 +26,7 @@ /* * @test - * @bug 8043758 + * @bug 8043758 8307383 * @summary Datagram Transport Layer Security (DTLS) * @modules java.base/sun.security.util * @library /test/lib @@ -36,6 +36,7 @@ import java.net.DatagramPacket; import java.net.SocketAddress; +import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -73,11 +74,34 @@ DatagramPacket createHandshakePacket(byte[] ba, SocketAddress socketAddr) { // ClientHello with cookie needInvalidRecords.set(false); System.out.println("invalidate ClientHello message"); - if (ba[ba.length - 1] == (byte)0xFF) { - ba[ba.length - 1] = (byte)0xFE; + // We will alter the compression method field in order to make the cookie + // check fail. + ByteBuffer chRec = ByteBuffer.wrap(ba); + // Skip 59 bytes past the record header (13), the handshake header (12), + // the protocol version (2), and client random (32) + chRec.position(59); + // Jump past the session ID + int len = Byte.toUnsignedInt(chRec.get()); + chRec.position(chRec.position() + len); + // Skip the cookie + len = Byte.toUnsignedInt(chRec.get()); + chRec.position(chRec.position() + len); + // Skip past cipher suites + len = Short.toUnsignedInt(chRec.getShort()); + chRec.position(chRec.position() + len); + // Read the data on the compression methods, should be at least 1 + len = Byte.toUnsignedInt(chRec.get()); + if (len >= 1) { + System.out.println("Detected compression methods (count = " + len + ")"); } else { ba[ba.length - 1] = (byte)0xFF; + throw new RuntimeException("Got zero length comp methods"); } + // alter the first comp method. + int compMethodVal = Byte.toUnsignedInt(chRec.get(chRec.position())); + System.out.println("Changing value at position " + chRec.position() + + " from " + compMethodVal + " to " + ++compMethodVal); + chRec.put(chRec.position(), (byte)compMethodVal); } return super.createHandshakePacket(ba, socketAddr); diff --git a/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java b/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java index ee50f21ae27d1..0867925f1359e 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java +++ b/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,15 @@ public class MFLNTest extends SSLEngineTestCase { public static void main(String[] args) { setUpAndStartKDCIfNeeded(); System.setProperty("jsse.enableMFLNExtension", "true"); - for (int mfl = 4096; mfl >= 256; mfl /= 2) { + String testMode = System.getProperty("test.mode", "norm"); + int mflLen; + if (testMode.equals("norm_sni")) { + mflLen = 512; + } else { + mflLen = 256; + } + + for (int mfl = 4096; mfl >= mflLen; mfl /= 2) { System.out.println("==============================================" + "=============="); System.out.printf("Testsing DTLS handshake with MFL = %d%n", mfl); diff --git a/test/jdk/javax/print/PostScriptRotatedScaledFontTest.java b/test/jdk/javax/print/PostScriptRotatedScaledFontTest.java new file mode 100644 index 0000000000000..e6e274f7cac42 --- /dev/null +++ b/test/jdk/javax/print/PostScriptRotatedScaledFontTest.java @@ -0,0 +1,211 @@ +/* + * 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.Graphics; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import javax.print.Doc; +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.SimpleDoc; +import javax.print.StreamPrintService; +import javax.print.StreamPrintServiceFactory; +import javax.print.event.PrintJobAdapter; +import javax.print.event.PrintJobEvent; + +/* + * @test + * @bug 8339974 + * @summary Verifies that text prints correctly using scaled and rotated fonts. + */ +public class PostScriptRotatedScaledFontTest { + + public static void main(String[] args) throws Exception { + test(0); + test(1); + test(2); + test(3); + test(4); + } + + private static void test(int quadrants) throws Exception { + + DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE; + String mime = "application/postscript"; + StreamPrintServiceFactory[] factories = StreamPrintServiceFactory.lookupStreamPrintServiceFactories(flavor, mime); + if (factories.length == 0) { + throw new RuntimeException("Unable to find PostScript print service factory"); + } + + StreamPrintServiceFactory factory = factories[0]; + + // required to trigger "text-as-shapes" code path in + // PSPathGraphics.drawString(String, float, float, Font, FontRenderContext, float) + // for *all* text, not just text that uses a transformed font + String shapeText = "sun.java2d.print.shapetext"; + System.setProperty(shapeText, "true"); + + try { + for (int scale = 1; scale <= 100; scale++) { + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + StreamPrintService service = factory.getPrintService(output); + DocPrintJob job = service.createPrintJob(); + + PrintJobMonitor monitor = new PrintJobMonitor(); + job.addPrintJobListener(monitor); + + Printable printable = new TestPrintable(scale, quadrants); + Doc doc = new SimpleDoc(printable, flavor, null); + job.print(doc, null); + monitor.waitForJobToFinish(); + + byte[] ps = output.toByteArray(); + Rectangle2D.Double bounds = findTextBoundingBox(ps); + if (bounds == null) { + throw new RuntimeException("Text missing: scale=" + scale + + ", quadrants=" + quadrants); + } + + boolean horizontal = (bounds.width > bounds.height); + boolean expectedHorizontal = (quadrants % 2 == 0); + if (horizontal != expectedHorizontal) { + throw new RuntimeException("Wrong orientation: scale=" + scale + + ", quadrants=" + quadrants + ", bounds=" + bounds + + ", expectedHorizontal=" + expectedHorizontal + + ", horizontal=" + horizontal); + } + } + } finally { + System.clearProperty(shapeText); + } + } + + // very basic, uses moveto ("x y M"), lineto ("x y L"), and curveto ("x1 y1 x2 y2 x3 y3 C") + private static Rectangle2D.Double findTextBoundingBox(byte[] ps) { + double minX = Double.MAX_VALUE; + double minY = Double.MAX_VALUE; + double maxX = Double.MIN_VALUE; + double maxY = Double.MIN_VALUE; + boolean pastPageClip = false; + List< String > lines = new String(ps, StandardCharsets.ISO_8859_1).lines().toList(); + for (String line : lines) { + if (!pastPageClip) { + pastPageClip = "WC".equals(line); + continue; + } + String[] values = line.split(" "); + if (values.length == 3 || values.length == 7) { + String cmd = values[values.length - 1]; + if ("M".equals(cmd) || "L".equals(cmd) || "C".equals(cmd)) { + String sx = values[values.length - 3]; + String sy = values[values.length - 2]; + double x = Double.parseDouble(sx); + double y = Double.parseDouble(sy); + if (x < minX) { + minX = x; + } + if (y < minY) { + minY = y; + } + if (x > maxX) { + maxX = x; + } + if (y > maxY) { + maxY = y; + } + } + } + } + if (minX != Double.MAX_VALUE) { + return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY); + } else { + return null; + } + } + + private static final class TestPrintable implements Printable { + private final int scale; + private final int quadrants; + public TestPrintable(int scale, int quadrants) { + this.scale = scale; + this.quadrants = quadrants; + } + @Override + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { + if (pageIndex > 0) { + return NO_SUCH_PAGE; + } + AffineTransform at = AffineTransform.getQuadrantRotateInstance(quadrants); + at.scale(scale, scale); + Font base = new Font("SansSerif", Font.PLAIN, 10); + Font font = base.deriveFont(at); + graphics.setFont(font); + graphics.drawString("TEST", 300, 300); + return PAGE_EXISTS; + } + } + + private static class PrintJobMonitor extends PrintJobAdapter { + private boolean finished; + @Override + public void printJobCanceled(PrintJobEvent pje) { + finished(); + } + @Override + public void printJobCompleted(PrintJobEvent pje) { + finished(); + } + @Override + public void printJobFailed(PrintJobEvent pje) { + finished(); + } + @Override + public void printJobNoMoreEvents(PrintJobEvent pje) { + finished(); + } + private synchronized void finished() { + finished = true; + notify(); + } + public synchronized void waitForJobToFinish() { + try { + while (!finished) { + wait(); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/test/jdk/javax/security/auth/Destroyable/KeyDestructionTest.java b/test/jdk/javax/security/auth/Destroyable/KeyDestructionTest.java index 71570807e4aab..6a664cebf7e9e 100644 --- a/test/jdk/javax/security/auth/Destroyable/KeyDestructionTest.java +++ b/test/jdk/javax/security/auth/Destroyable/KeyDestructionTest.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 @@ -24,6 +24,7 @@ /* * @test * @bug 6263419 + * @library /test/lib * @summary No way to clean the memory for a java.security.Key */ @@ -32,10 +33,12 @@ import javax.crypto.*; import javax.security.auth.Destroyable; import javax.security.auth.DestroyFailedException; +import jdk.test.lib.security.SecurityUtils; public class KeyDestructionTest { public static void main(String[] args) throws Exception { - KeyPair keypair = generateKeyPair("RSA", 1024); + String kpgAlgorithm = "RSA"; + KeyPair keypair = generateKeyPair(kpgAlgorithm, SecurityUtils.getTestKeySize(kpgAlgorithm)); // Check keys that support and have implemented key destruction testKeyDestruction(new MyDestroyableSecretKey()); diff --git a/test/jdk/javax/security/auth/login/Configuration/GetInstance.java b/test/jdk/javax/security/auth/login/Configuration/GetInstance.java index 4be056bd26ce6..41820c907435a 100644 --- a/test/jdk/javax/security/auth/login/Configuration/GetInstance.java +++ b/test/jdk/javax/security/auth/login/Configuration/GetInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, 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 @@ -84,12 +84,14 @@ private int testDefault(int testnum) throws Exception { private int testStringProvider(int testnum) throws Exception { // get an instance of JavaLoginConfig from SUN - Configuration c = Configuration.getInstance(JAVA_CONFIG, null, "SUN"); + Configuration c = Configuration.getInstance(JAVA_CONFIG, null, + System.getProperty("test.provider.name", "SUN")); doTest(c, testnum++); // get an instance of JavaLoginConfig from SunRsaSign try { - c = Configuration.getInstance(JAVA_CONFIG, null, "SunRsaSign"); + c = Configuration.getInstance(JAVA_CONFIG, null, + System.getProperty("test.provider.name", "SunRsaSign")); throw new SecurityException("test " + testnum++ + " failed"); } catch (NoSuchAlgorithmException nsae) { // good @@ -112,14 +114,16 @@ private int testProvider(int testnum) throws Exception { // get an instance of JavaLoginConfig from SUN Configuration c = Configuration.getInstance(JAVA_CONFIG, null, - Security.getProvider("SUN")); + Security.getProvider( + System.getProperty("test.provider.name", "SUN"))); doTest(c, testnum++); // get an instance of JavaLoginConfig from SunRsaSign try { c = Configuration.getInstance(JAVA_CONFIG, null, - Security.getProvider("SunRsaSign")); + Security.getProvider( + System.getProperty("test.provider.name","SunRsaSign"))); throw new SecurityException("test " + testnum++ + " failed"); } catch (NoSuchAlgorithmException nsae) { // good @@ -186,7 +190,7 @@ private int testException(int testnum) throws Exception { try { Configuration c = Configuration.getInstance(JAVA_CONFIG, new BadParam(), - "SUN"); + System.getProperty("test.provider.name","SUN")); throw new SecurityException("test " + testnum++ + " failed"); } catch (IllegalArgumentException iae) { // good @@ -196,7 +200,7 @@ private int testException(int testnum) throws Exception { try { Configuration c = Configuration.getInstance(JAVA_CONFIG, new BadParam(), - Security.getProvider("SUN")); + Security.getProvider(System.getProperty("test.provider.name","SUN"))); throw new SecurityException("test " + testnum++ + " failed"); } catch (IllegalArgumentException iae) { // good @@ -285,7 +289,7 @@ private void doTest(Configuration c, int testnum) throws Exception { testnum = doCommon(c, testnum); // test getProvider - if ("SUN".equals(c.getProvider().getName())) { + if (System.getProperty("test.provider.name","SUN").equals(c.getProvider().getName())) { System.out.println("test " + testnum + " (getProvider) passed"); } else { throw new SecurityException("test " + testnum + @@ -325,7 +329,7 @@ private void doTestURI(Configuration c, } // test getProvider - if ("SUN".equals(c.getProvider().getName())) { + if (System.getProperty("test.provider.name","SUN").equals(c.getProvider().getName())) { System.out.println("test " + testnum + " (getProvider) passed"); } else { throw new SecurityException("test " + testnum + diff --git a/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.grantedPolicy b/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.grantedPolicy index bcb47b245a741..f92b9fa63ad49 100644 --- a/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.grantedPolicy +++ b/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.grantedPolicy @@ -1,4 +1,5 @@ grant { + permission java.util.PropertyPermission "test.provider.name", "read"; permission java.util.PropertyPermission "test.src", "read"; permission java.io.FilePermission "${test.src}${/}*", "read"; diff --git a/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.java b/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.java index fc2bec082218c..68417a34bd98a 100644 --- a/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.java +++ b/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, 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 @@ -51,7 +51,7 @@ public static void main(String[] args) throws Exception { try { Configuration c = Configuration.getInstance - (JAVA_CONFIG, null, "SUN"); + (JAVA_CONFIG, null, System.getProperty("test.provider.name","SUN")); throw new RuntimeException("did not catch security exception"); } catch (SecurityException se) { // good @@ -59,7 +59,8 @@ public static void main(String[] args) throws Exception { try { Configuration c = Configuration.getInstance - (JAVA_CONFIG, null, Security.getProvider("SUN")); + (JAVA_CONFIG, null, Security.getProvider( + System.getProperty("test.provider.name","SUN"))); throw new RuntimeException("did not catch security exception"); } catch (SecurityException se) { // good @@ -71,7 +72,8 @@ public static void main(String[] args) throws Exception { "GetInstanceSecurity.grantedPolicy"); URI uri = file.toURI(); URIParameter param = new URIParameter(uri); - Policy p = Policy.getInstance("JavaPolicy", param, "SUN"); + Policy p = Policy.getInstance("JavaPolicy", param, + System.getProperty("test.provider.name","SUN")); Policy.setPolicy(p); // retry operations @@ -88,7 +90,7 @@ public static void main(String[] args) throws Exception { try { Configuration c = Configuration.getInstance - (JAVA_CONFIG, uriParam, "SUN"); + (JAVA_CONFIG, uriParam, System.getProperty("test.provider.name","SUN")); // good } catch (SecurityException se) { throw new RuntimeException("unexpected SecurityException"); @@ -96,7 +98,8 @@ public static void main(String[] args) throws Exception { try { Configuration c = Configuration.getInstance - (JAVA_CONFIG, uriParam, Security.getProvider("SUN")); + (JAVA_CONFIG, uriParam, Security.getProvider( + System.getProperty("test.provider.name","SUN"))); // good } catch (SecurityException se) { throw new RuntimeException("unexpected SecurityException"); diff --git a/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.policy b/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.policy index 4c0f7acfc888c..162168a3ffd98 100644 --- a/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.policy +++ b/test/jdk/javax/security/auth/login/Configuration/GetInstanceSecurity.policy @@ -1,6 +1,6 @@ grant { - + permission java.util.PropertyPermission "test.provider.name", "read"; permission java.util.PropertyPermission "test.src", "read"; permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www"; permission java.io.FilePermission diff --git a/test/jdk/javax/swing/JButton/bug4490179.java b/test/jdk/javax/swing/JButton/bug4490179.java index 079c7a026f83c..e36e01e2d95bf 100644 --- a/test/jdk/javax/swing/JButton/bug4490179.java +++ b/test/jdk/javax/swing/JButton/bug4490179.java @@ -31,61 +31,107 @@ import java.awt.Point; import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.concurrent.CountDownLatch; + import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.SwingUtilities; -public class bug4490179 { +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +public final class bug4490179 + extends MouseAdapter + implements ActionListener { static JFrame frame; static JButton button; - static volatile Point pt; - static volatile int buttonW; - static volatile int buttonH; - static volatile boolean passed = true; + + private static volatile Point buttonCenter; + + private static final CountDownLatch windowGainedFocus = new CountDownLatch(1); + + private static final CountDownLatch mouseButton1Released = new CountDownLatch(1); + private static final CountDownLatch mouseButton3Released = new CountDownLatch(2); + + private static final CountDownLatch actionPerformed = new CountDownLatch(1); public static void main(String[] args) throws Exception { Robot robot = new Robot(); robot.setAutoDelay(100); - robot.setAutoWaitForIdle(true); + + final bug4490179 eventHandler = new bug4490179(); try { SwingUtilities.invokeAndWait(() -> { - frame = new JFrame("bug4490179"); button = new JButton("Button"); + button.addActionListener(eventHandler); + button.addMouseListener(eventHandler); + + frame = new JFrame("bug4490179"); frame.getContentPane().add(button); - button.addActionListener(e -> { - if ((e.getModifiers() & InputEvent.BUTTON1_MASK) - != InputEvent.BUTTON1_MASK) { - System.out.println("Status: Failed"); - passed = false; + + frame.addWindowFocusListener(new WindowAdapter() { + @Override + public void windowGainedFocus(WindowEvent e) { + windowGainedFocus.countDown(); } }); + frame.pack(); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }); + + if (!windowGainedFocus.await(1, SECONDS)) { + throw new RuntimeException("Window didn't gain focus"); + } robot.waitForIdle(); - robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { - pt = button.getLocationOnScreen(); - buttonW = button.getSize().width; - buttonH = button.getSize().height; + Point location = button.getLocationOnScreen(); + buttonCenter = new Point(location.x + button.getWidth() / 2, + location.y + button.getHeight() / 2); }); - robot.mouseMove(pt.x + buttonW / 2, pt.y + buttonH / 2); - robot.waitForIdle(); + robot.mouseMove(buttonCenter.x, buttonCenter.y); + System.out.println("Press / Release button 3"); robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + System.out.println("Press button 1"); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + System.out.println("Press button 3"); robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + System.out.println("Release button 3"); robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); - robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); - robot.delay(500); - if (!passed) { - throw new RuntimeException("Test Failed"); + try { + if (!mouseButton3Released.await(1, SECONDS)) { + throw new RuntimeException("Mouse button 3 isn't released"); + } + + robot.waitForIdle(); + + if (actionPerformed.await(100, MILLISECONDS)) { + throw new RuntimeException("Action event triggered by releasing button 3"); + } + } finally { + System.out.println("Release button 1"); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + if (!mouseButton1Released.await(1, SECONDS)) { + throw new RuntimeException("Mouse button 1 isn't released"); + } + if (!actionPerformed.await(100, MILLISECONDS)) { + throw new RuntimeException("Action event isn't triggered by releasing button 1"); } } finally { SwingUtilities.invokeAndWait(() -> { @@ -95,4 +141,21 @@ public static void main(String[] args) throws Exception { }); } } + + @Override + public void actionPerformed(ActionEvent e) { + System.out.println(" actionPerformed"); + actionPerformed.countDown(); + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + System.out.println(" mouseReleased: button 1"); + mouseButton1Released.countDown(); + } else if (e.getButton() == MouseEvent.BUTTON3) { + System.out.println(" mouseReleased: button 3"); + mouseButton3Released.countDown(); + } + } } diff --git a/test/jdk/javax/swing/JColorChooser/Test4887836.java b/test/jdk/javax/swing/JColorChooser/Test4887836.java index 4043dbdd88ae6..82a09c460853b 100644 --- a/test/jdk/javax/swing/JColorChooser/Test4887836.java +++ b/test/jdk/javax/swing/JColorChooser/Test4887836.java @@ -26,10 +26,12 @@ import javax.swing.JColorChooser; import javax.swing.UIManager; +import jtreg.SkippedException; + /* * @test * @bug 4887836 - * @library /java/awt/regtesthelpers + * @library /java/awt/regtesthelpers /test/lib * @build PassFailJFrame * @summary Checks for white area under the JColorChooser Swatch tab * @run main/manual Test4887836 @@ -38,6 +40,13 @@ public class Test4887836 { public static void main(String[] args) throws Exception { + + // ColorChooser UI design is different for GTK L&F. + // There is no Swatches tab available for GTK L&F, skip the testing. + if (UIManager.getLookAndFeel().getName().contains("GTK")) { + throw new SkippedException("Test not applicable for GTK L&F"); + } + String instructions = """ If you do not see white area under the \"Swatches\" tab, then test passed, otherwise it failed."""; @@ -45,9 +54,7 @@ public static void main(String[] args) throws Exception { PassFailJFrame.builder() .title("Test4759306") .instructions(instructions) - .rows(5) .columns(40) - .testTimeOut(10) .testUI(Test4887836::createColorChooser) .build() .awaitAndCheck(); diff --git a/test/jdk/javax/swing/JFileChooser/FileSystemView/WindowsDefaultIconSizeTest.java b/test/jdk/javax/swing/JFileChooser/FileSystemView/WindowsDefaultIconSizeTest.java index 081277ca2d470..dcdc7ca7b96ce 100644 --- a/test/jdk/javax/swing/JFileChooser/FileSystemView/WindowsDefaultIconSizeTest.java +++ b/test/jdk/javax/swing/JFileChooser/FileSystemView/WindowsDefaultIconSizeTest.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 @@ -44,18 +44,16 @@ public static void main(String[] args) { } public void test() { - String sep = System.getProperty("file.separator"); - String dir = System.getProperty("test.src", "."); String filename = "test.not"; - File testFile = new File(dir + sep + filename); + File testFile = new File(filename); try { if (!testFile.exists()) { testFile.createNewFile(); testFile.deleteOnExit(); } FileSystemView fsv = FileSystemView.getFileSystemView(); - Icon icon = fsv.getSystemIcon(new File(dir + sep + filename)); + Icon icon = fsv.getSystemIcon(new File(filename)); if (icon instanceof ImageIcon) { Image image = ((ImageIcon) icon).getImage(); if (image instanceof MultiResolutionImage) { diff --git a/test/jdk/javax/swing/JFileChooser/bug4587721.java b/test/jdk/javax/swing/JFileChooser/bug4587721.java new file mode 100644 index 0000000000000..408f4e47f49f7 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/bug4587721.java @@ -0,0 +1,77 @@ +/* + * 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 4587721 + * @summary Tests if JFileChooser details view chops off text + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4587721 + */ + +import java.awt.Font; +import java.util.Enumeration; + +import javax.swing.JFileChooser; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.metal.MetalLookAndFeel; + +public class bug4587721 { + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + + String instructions = """ + Click on the Details button in JFileChooser Window. + If the filename text is chopped off by height, + then Press FAIL else Press PASS. + """; + + PassFailJFrame.builder() + .title("bug4587721") + .instructions(instructions) + .columns(40) + .testUI(bug4587721::createUI) + .build() + .awaitAndCheck(); + } + + public static JFileChooser createUI() { + setFonts(); + JFileChooser fc = new JFileChooser(); + return fc; + } + + public static void setFonts() { + UIDefaults defaults = UIManager.getDefaults(); + Enumeration keys = defaults.keys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + if (defaults.get(key) instanceof Font) + UIManager.put(key, new FontUIResource(new Font("Courier", Font.BOLD, 30))); + } + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java b/test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java deleted file mode 100644 index 25d3ad41eca59..0000000000000 --- a/test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.awt.*; -import java.util.ArrayList; -import java.util.concurrent.CountDownLatch; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JTabbedPane; - -import static javax.swing.UIManager.*; -import static javax.swing.SwingUtilities.*; - -/* - * @test - * @key headful - * @bug 8007563 - * @summary Tests JTabbedPane background - * @author Sergey Malenkov - */ - -public class Test8007563 implements Runnable { - private static final ArrayList LIST = new ArrayList<>(); - private static final LookAndFeelInfo[] INFO = getInstalledLookAndFeels(); - private static final CountDownLatch LATCH = new CountDownLatch(INFO.length); - private static Robot ROBOT; - - public static void main(String[] args) throws Exception { - ROBOT = new Robot(); - invokeLater(new Test8007563()); - LATCH.await(); - if (!LIST.isEmpty()) { - throw new Error(LIST.toString()); - } - } - - private static void addOpaqueError(boolean opaque) { - LIST.add(getLookAndFeel().getName() + " opaque=" + opaque); - } - - private static boolean updateLookAndFeel() { - int index = (int) LATCH.getCount() - 1; - if (index >= 0) { - try { - LookAndFeelInfo info = INFO[index]; - System.err.println("L&F: " + info.getName()); - setLookAndFeel(info.getClassName()); - return true; - } catch (Exception exception) { - exception.printStackTrace(); - } - } - return false; - } - - private JFrame frame; - private JTabbedPane pane; - - public void run() { - if (this.frame == null) { - if (!updateLookAndFeel()) { - return; - } - this.pane = new JTabbedPane(); - this.pane.setOpaque(false); - this.pane.setBackground(Color.RED); - for (int i = 0; i < 3; i++) { - this.pane.addTab("Tab " + i, new JLabel("Content area " + i)); - } - this.frame = new JFrame(getClass().getSimpleName()); - this.frame.getContentPane().setBackground(Color.BLUE); - this.frame.add(this.pane); - this.frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - this.frame.setSize(400, 200); - this.frame.setLocationRelativeTo(null); - this.frame.setVisible(true); - } else { - Point point = new Point(this.pane.getWidth() - 2, 2); - convertPointToScreen(point, this.pane); - Color actual = ROBOT.getPixelColor(point.x, point.y); - - boolean opaque = this.pane.isOpaque(); - Color expected = opaque - ? this.pane.getBackground() - : this.frame.getContentPane().getBackground(); - - if (!expected.equals(actual)){ - addOpaqueError(opaque); - } - if (!opaque) { - this.pane.setOpaque(true); - this.pane.repaint(); - } else { - this.frame.dispose(); - this.frame = null; - this.pane = null; - LATCH.countDown(); - } - - } - SecondaryLoop secondaryLoop = - Toolkit.getDefaultToolkit().getSystemEventQueue() - .createSecondaryLoop(); - new Thread() { - @Override - public void run() { - try { - Thread.sleep(200); - } catch (InterruptedException e) { - } - secondaryLoop.exit(); - invokeLater(Test8007563.this); - } - }.start(); - secondaryLoop.enter(); - } -} diff --git a/test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java b/test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java new file mode 100644 index 0000000000000..d4bed5ac2dafa --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java @@ -0,0 +1,137 @@ +/* + * 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 + * 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.Point; +import java.awt.Robot; +import java.util.ArrayList; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +/* + * @test + * @key headful + * @bug 8007563 + * @summary Tests JTabbedPane background + */ + +public class TestJTabbedPaneBackgroundColor { + private static ArrayList lafList = new ArrayList<>(); + private static JFrame frame; + private static JTabbedPane pane; + private static Robot robot; + private static volatile Dimension dim; + private static volatile Point loc; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + + for (UIManager.LookAndFeelInfo laf : + UIManager.getInstalledLookAndFeels()) { + System.out.println("Testing: " + laf.getName()); + setLookAndFeel(laf); + + try { + SwingUtilities.invokeAndWait(TestJTabbedPaneBackgroundColor::createAndShowUI); + robot.waitForIdle(); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> { + loc = pane.getLocationOnScreen(); + dim = pane.getSize(); + }); + + loc = new Point(loc.x + dim.width - 2, loc.y + 2); + doTesting(loc, laf); + + if (!pane.isOpaque()) { + pane.setOpaque(true); + pane.repaint(); + } + robot.waitForIdle(); + robot.delay(500); + + doTesting(loc, laf); + + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + if (!lafList.isEmpty()) { + throw new RuntimeException(lafList.toString()); + } + } + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported LAF: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static void createAndShowUI() { + pane = new JTabbedPane(); + pane.setOpaque(false); + pane.setBackground(Color.RED); + for (int i = 0; i < 3; i++) { + pane.addTab("Tab " + i, new JLabel("Content area " + i)); + } + frame = new JFrame("Test Background Color"); + frame.getContentPane().setBackground(Color.BLUE); + frame.add(pane); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setSize(400, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void doTesting(Point p, UIManager.LookAndFeelInfo laf) { + boolean isOpaque = pane.isOpaque(); + Color actual = robot.getPixelColor(p.x, p.y); + Color expected = isOpaque + ? pane.getBackground() + : frame.getContentPane().getBackground(); + + if (!expected.equals(actual)) { + addOpaqueError(laf.getName(), isOpaque); + } + } + + private static void addOpaqueError(String lafName, boolean opaque) { + lafList.add(lafName + " opaque=" + opaque); + } +} diff --git a/test/jdk/javax/swing/ProgressMonitor/ProgressMonitorEscapeKeyPress.java b/test/jdk/javax/swing/ProgressMonitor/ProgressMonitorEscapeKeyPress.java index 4ea1f48ae7a34..77fac43d26263 100644 --- a/test/jdk/javax/swing/ProgressMonitor/ProgressMonitorEscapeKeyPress.java +++ b/test/jdk/javax/swing/ProgressMonitor/ProgressMonitorEscapeKeyPress.java @@ -29,66 +29,64 @@ * @run main ProgressMonitorEscapeKeyPress */ -import java.awt.AWTException; -import java.awt.EventQueue; -import java.awt.Robot; -import java.awt.event.KeyEvent; + import javax.swing.JFrame; import javax.swing.ProgressMonitor; import javax.swing.SwingUtilities; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class ProgressMonitorEscapeKeyPress { + static volatile int counter = 0; static ProgressMonitor monitor; - static int counter = 0; - static TestThread robotThread; + static TestThread testThread; static JFrame frame; + static CountDownLatch progressLatch; + static Robot robot; public static void main(String[] args) throws Exception { - - createTestUI(); - - monitor = new ProgressMonitor(frame, "Progress", null, 0, 100); - - robotThread = new TestThread(); - robotThread.start(); - - for (counter = 0; counter <= 100; counter += 10) { - Thread.sleep(1000); - - EventQueue.invokeAndWait(new Runnable() { - @Override - public void run() { - if (!monitor.isCanceled()) { - monitor.setProgress(counter); - System.out.println("Progress bar is in progress"); - } - } - }); - - if (monitor.isCanceled()) { - break; + try { + progressLatch = new CountDownLatch(20); + createTestUI(); + robot = new Robot(); + robot.setAutoDelay(50); + robot.setAutoWaitForIdle(true); + testThread = new TestThread(); + testThread.start(); + Thread.sleep(100); + if (progressLatch.await(15, TimeUnit.SECONDS)) { + System.out.println("Progress monitor completed 20%, lets press Esc..."); + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + System.out.println("ESC pressed...."); + } else { + System.out.println("Failure : No status available from Progress monitor..."); + throw new RuntimeException( + "Can't get the status from Progress monitor even after waiting too long.."); } - } - - disposeTestUI(); - if (counter >= monitor.getMaximum()) { - throw new RuntimeException("Escape key did not cancel the ProgressMonitor"); + if (counter >= monitor.getMaximum()) { + throw new RuntimeException("Escape key did not cancel the ProgressMonitor"); + } + System.out.println("Test Passed..."); + } finally { + disposeTestUI(); } } - private static void createTestUI() throws Exception { - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - frame = new JFrame("Test"); - frame.setSize(300, 300); - frame.setLocationByPlatform(true); - frame.setVisible(true); - }}); - } + private static void createTestUI() throws Exception { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("Test"); + frame.setSize(300, 300); + monitor = new ProgressMonitor(frame, "Progress", "1", 0, 100); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setLocationByPlatform(true); + }); + } private static void disposeTestUI() throws Exception { @@ -100,26 +98,25 @@ private static void disposeTestUI() throws Exception { class TestThread extends Thread { - - Robot testRobot; - - TestThread() throws AWTException { - super(); - testRobot = new Robot(); - } - @Override public void run() { - try { - // Sleep for 5 seconds - so that the ProgressMonitor starts - Thread.sleep(5000); - - // Press and release Escape key - testRobot.keyPress(KeyEvent.VK_ESCAPE); - testRobot.delay(20); - testRobot.keyRelease(KeyEvent.VK_ESCAPE); - } catch (InterruptedException ex) { - throw new RuntimeException("Exception in TestThread"); + System.out.println("TestThread started........."); + for (ProgressMonitorEscapeKeyPress.counter = 0; + ProgressMonitorEscapeKeyPress.counter <= 100; + ProgressMonitorEscapeKeyPress.counter += 1) { + ProgressMonitorEscapeKeyPress.robot.delay(100); + ProgressMonitor monitor = ProgressMonitorEscapeKeyPress.monitor; + if (!monitor.isCanceled()) { + monitor.setNote("" + ProgressMonitorEscapeKeyPress.counter); + monitor.setProgress(ProgressMonitorEscapeKeyPress.counter); + ProgressMonitorEscapeKeyPress.progressLatch.countDown(); + System.out.println("Progress bar is in progress....." + + ProgressMonitorEscapeKeyPress.counter + "%"); + } + if (monitor.isCanceled()) { + System.out.println("$$$$$$$$$$$$$$$ Monitor canceled"); + break; + } } } } diff --git a/test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4419255.java b/test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4419255.java new file mode 100644 index 0000000000000..eb23901f60d4b --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4419255.java @@ -0,0 +1,65 @@ +/* + * 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 javax.swing.JColorChooser; +import javax.swing.UIManager; + +import jtreg.SkippedException; + +/* + * @test + * @bug 4419255 + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame + * @summary Tests if Metal Slider's thumb isn't clipped + * @run main/manual bug4419255 + */ + +public class bug4419255 { + + public static void main(String[] args) throws Exception { + + // ColorChooser UI design is different for GTK L&F. + // There is no RGB tab available for GTK L&F, skip the testing. + if (UIManager.getLookAndFeel().getName().contains("GTK")) { + throw new SkippedException("Test not applicable for GTK L&F"); + } + String instructions = """ + Choose RGB tab. If sliders' thumbs are painted correctly + (top is not clipped, black line is visible), + then test passed. Otherwise it failed."""; + + PassFailJFrame.builder() + .title("bug4419255") + .instructions(instructions) + .columns(40) + .testUI(bug4419255::createColorChooser) + .build() + .awaitAndCheck(); + } + + private static JColorChooser createColorChooser() { + return new JColorChooser(Color.BLUE); + } +} diff --git a/test/jdk/jdk/classfile/LDCTest.java b/test/jdk/jdk/classfile/LDCTest.java index 207d53e88204c..63a08b50436f4 100644 --- a/test/jdk/jdk/classfile/LDCTest.java +++ b/test/jdk/jdk/classfile/LDCTest.java @@ -23,88 +23,145 @@ /* * @test + * @bug 8342458 + * @library /test/lib * @summary Testing ClassFile LDC instructions. * @run junit LDCTest */ -import java.lang.constant.ClassDesc; -import static java.lang.classfile.ClassFile.ACC_PUBLIC; -import static java.lang.classfile.ClassFile.ACC_STATIC; -import static java.lang.constant.ConstantDescs.*; -import java.lang.constant.MethodTypeDesc; - -import java.lang.classfile.*; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassFile; +import java.lang.classfile.Instruction; +import java.lang.classfile.MethodModel; +import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.LongEntry; import java.lang.classfile.constantpool.StringEntry; +import java.lang.classfile.instruction.ConstantInstruction; +import java.lang.constant.ClassDesc; +import java.lang.constant.DirectMethodHandleDesc; +import java.lang.constant.DynamicConstantDesc; +import java.lang.constant.MethodHandleDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.AccessFlag; -import static org.junit.jupiter.api.Assertions.*; +import java.util.List; + +import jdk.test.lib.ByteCodeLoader; import org.junit.jupiter.api.Test; -import static helpers.TestConstants.MTD_VOID; + +import static java.lang.classfile.ClassFile.*; import static java.lang.classfile.Opcode.*; -import java.lang.classfile.instruction.ConstantInstruction; +import static java.lang.constant.ConstantDescs.*; +import static org.junit.jupiter.api.Assertions.*; class LDCTest { @Test - void testLDCisConvertedToLDCW() throws Exception { - var cc = ClassFile.of(); - byte[] bytes = cc.build(ClassDesc.of("MyClass"), cb -> { - cb.withFlags(AccessFlag.PUBLIC); - cb.withVersion(52, 0); - cb.withMethod("", MethodTypeDesc.of(CD_void), 0, mb -> mb - .withCode(codeb -> codeb.aload(0) - .invokespecial(CD_Object, "", MTD_VOID, false) - .return_() - ) - ) + void loadConstantGeneralTest() throws Exception { + var otherCp = ConstantPoolBuilder.of(); + var narrowString131 = otherCp.stringEntry("string131"); + assertTrue(narrowString131.index() <= 0xFF); + for (int i = 0; i < 0xFF; i++) { + var unused = otherCp.intEntry(i); + } + var wideString0 = otherCp.stringEntry("string0"); + assertTrue(wideString0.index() > 0xFF); - .withMethod("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), - ACC_PUBLIC | ACC_STATIC, - mb -> mb.withCode(c0 -> { - ConstantPoolBuilder cpb = cb.constantPool(); - for (int i = 0; i <= 256/2 + 2; i++) { // two entries per String - StringEntry s = cpb.stringEntry("string" + i); - } - c0.ldc("string0") - .ldc("string131") - .ldc("string50") - .loadConstant(-0.0f) - .loadConstant(-0.0d) - //non-LDC test cases - .loadConstant(0.0f) - .loadConstant(0.0d) - .return_(); - })); - }); + var cc = ClassFile.of(); + var cd = ClassDesc.of("MyClass"); + MethodTypeDesc bsmType = MethodTypeDesc.of(CD_double, CD_MethodHandles_Lookup, CD_String, CD_Class); + byte[] bytes = cc.build(cd, cb -> cb + .withFlags(AccessFlag.PUBLIC) + .withVersion(JAVA_11_VERSION, 0) // condy support required + .withMethodBody("bsm", bsmType, ACC_STATIC, cob -> cob + .dconst_1() + .dreturn()) + .withMethodBody("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), + ACC_PUBLIC | ACC_STATIC, c0 -> { + ConstantPoolBuilder cpb = cb.constantPool(); + LongEntry l42 = cpb.longEntry(42); + assertTrue(l42.index() <= 0xFF); + for (int i = 0; i <= 256 / 2 + 2; i++) { // two entries per String + StringEntry s = cpb.stringEntry("string" + i); + } + var wideCondy = cpb.constantDynamicEntry(DynamicConstantDesc.of(MethodHandleDesc.ofMethod( + DirectMethodHandleDesc.Kind.STATIC, cd, "bsm", bsmType))); + assertTrue(wideCondy.index() > 0xFF); + var s0 = cpb.stringEntry("string0"); + assertTrue(s0.index() <= 0xFF); + // use line number to match case numbers; pop ensures verification passes + c0.ldc("string0").pop() // regular ldc + .ldc(wideString0).pop() // adaption - narrowed + .with(ConstantInstruction.ofLoad(LDC, wideString0)).pop() // adaption + .with(ConstantInstruction.ofLoad(LDC_W, wideString0)).pop() // adaption - narrowed + .with(ConstantInstruction.ofLoad(LDC_W, s0)).pop() // explicit ldc_w - local + .ldc("string131").pop() // ldc_w + .ldc(narrowString131).pop() // adaption - widened + .with(ConstantInstruction.ofLoad(LDC, narrowString131)).pop() // adaption - widened + .with(ConstantInstruction.ofLoad(LDC_W, narrowString131)).pop() // adaption + .ldc("string50").pop() + .ldc(l42).pop2() // long cases + .loadConstant(l42.longValue()).pop2() + .loadConstant(Long.valueOf(l42.longValue())).pop2() + .loadConstant(-0.0f).pop() // floating cases + .loadConstant(-0.0d).pop2() + .loadConstant(0.0f).pop() // intrinsic cases + .loadConstant(0.0d).pop2() + .ldc(wideCondy).pop2() // no wrong "widening" of condy + .return_(); + })); - var model = cc.parse(bytes); - var code = model.elementStream() - .filter(e -> e instanceof MethodModel) - .map(e -> (MethodModel) e) - .filter(e -> e.methodName().stringValue().equals("main")) - .flatMap(MethodModel::elementStream) - .filter(e -> e instanceof CodeModel) - .map(e -> (CodeModel) e) + var cm = cc.parse(bytes); + var code = cm.elementStream() + .mapMulti((ce, sink) -> { + if (ce instanceof MethodModel mm && mm.methodName().equalsString("main")) { + sink.accept(mm.findAttribute(Attributes.code()).orElseThrow()); + } + }) .findFirst() .orElseThrow(); - var opcodes = code.elementList().stream() - .filter(e -> e instanceof Instruction) - .map(e -> (Instruction)e) - .toList(); + var instructions = code.elementList().stream() + .mapMulti((ce, sink) -> { + if (ce instanceof ConstantInstruction i) { + sink.accept(i); + } + }) + .toList(); - assertEquals(opcodes.size(), 8); - assertEquals(opcodes.get(0).opcode(), LDC); - assertEquals(opcodes.get(1).opcode(), LDC_W); - assertEquals(opcodes.get(2).opcode(), LDC); + assertIterableEquals(List.of( + LDC, // string0 + LDC, + LDC, + LDC, + LDC_W, + LDC_W, // string131 + LDC_W, + LDC_W, + LDC_W, + LDC, // string50 + LDC2_W, // long cases + LDC2_W, + LDC2_W, + LDC_W, // floating cases + LDC2_W, + FCONST_0, // intrinsic cases + DCONST_0, + LDC2_W // wide condy + ), instructions.stream().map(Instruction::opcode).toList()); + + int longCaseStart = 10; + for (int longCaseIndex = longCaseStart; longCaseIndex < longCaseStart + 3; longCaseIndex++) { + var message = "Case " + longCaseIndex; + assertEquals(42, (long) instructions.get(longCaseIndex).constantValue(), message); + } + + int floatingCaseStart = longCaseStart + 3; assertEquals( - Float.floatToRawIntBits((float)((ConstantInstruction)opcodes.get(3)).constantValue()), + Float.floatToRawIntBits((float) instructions.get(floatingCaseStart).constantValue()), Float.floatToRawIntBits(-0.0f)); assertEquals( - Double.doubleToRawLongBits((double)((ConstantInstruction)opcodes.get(4)).constantValue()), + Double.doubleToRawLongBits((double) instructions.get(floatingCaseStart + 1).constantValue()), Double.doubleToRawLongBits(-0.0d)); - assertEquals(opcodes.get(5).opcode(), FCONST_0); - assertEquals(opcodes.get(6).opcode(), DCONST_0); - assertEquals(opcodes.get(7).opcode(), RETURN); - } - // TODO test for explicit LDC_W? -} \ No newline at end of file + assertDoesNotThrow(() -> ByteCodeLoader.load("MyClass", bytes), "Invalid LDC bytecode generated"); + } +} diff --git a/test/jdk/jdk/classfile/UtilTest.java b/test/jdk/jdk/classfile/UtilTest.java index be66d9305808c..cc41a326045ce 100644 --- a/test/jdk/jdk/classfile/UtilTest.java +++ b/test/jdk/jdk/classfile/UtilTest.java @@ -103,24 +103,10 @@ void testPow31() { } } - @ParameterizedTest - @ValueSource(classes = { - Long.class, - Object.class, - Util.class, - Test.class, - CopyOnWriteArrayList.class, - AtomicReferenceFieldUpdater.class - }) - void testInternalNameHash(Class type) { - var cd = type.describeConstable().orElseThrow(); - assertEquals(ConstantUtils.binaryToInternal(type.getName()).hashCode(), Util.internalNameHash(cd.descriptorString())); - } - // Ensures the initialization statement of the powers array is filling in the right values @Test void testPowersArray() { - int[] powers = new int[7 * UtilAccess.significantOctalDigits()]; + int[] powers = new int[64]; for (int i = 1, k = 31; i <= 7; i++, k *= 31) { int t = powers[UtilAccess.powersIndex(i, 0)] = k; diff --git a/test/jdk/jdk/dynalink/TypeConverterFactoryMemoryLeakTest.java b/test/jdk/jdk/dynalink/TypeConverterFactoryMemoryLeakTest.java index 7e907781e9d3d..4735bb4a08fa5 100644 --- a/test/jdk/jdk/dynalink/TypeConverterFactoryMemoryLeakTest.java +++ b/test/jdk/jdk/dynalink/TypeConverterFactoryMemoryLeakTest.java @@ -46,19 +46,11 @@ */ /* - * @test id=with_ZGC_Singlegen - * @requires vm.gc.ZSinglegen + * @test id=with_ZGC + * @requires vm.gc.Z * @bug 8198540 * @summary Test TypeConverterFactory is not leaking method handles (Z GC) - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational TypeConverterFactoryMemoryLeakTest - */ - -/* - * @test id=with_ZGC_Generational - * @requires vm.gc.ZGenerational - * @bug 8198540 - * @summary Test TypeConverterFactory is not leaking method handles (Z GC) - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational TypeConverterFactoryMemoryLeakTest + * @run main/othervm -XX:+UseZGC TypeConverterFactoryMemoryLeakTest */ /* diff --git a/test/jdk/jdk/dynalink/TypeConverterFactoryRetentionTests.java b/test/jdk/jdk/dynalink/TypeConverterFactoryRetentionTests.java index bdfd33eff4801..8ad972d450225 100644 --- a/test/jdk/jdk/dynalink/TypeConverterFactoryRetentionTests.java +++ b/test/jdk/jdk/dynalink/TypeConverterFactoryRetentionTests.java @@ -46,19 +46,11 @@ */ /* - * @test id=with_ZGC_Singlegen - * @requires vm.gc.ZSinglegen + * @test id=with_ZGC + * @requires vm.gc.Z * @bug 8198540 * @summary Test TypeConverterFactory is not leaking class loaders (Z GC) - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational TypeConverterFactoryRetentionTests - */ - -/* - * @test id=with_ZGC_Generational - * @requires vm.gc.ZGenerational - * @bug 8198540 - * @summary Test TypeConverterFactory is not leaking class loaders (Z GC) - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational TypeConverterFactoryRetentionTests + * @run main/othervm -XX:+UseZGC TypeConverterFactoryRetentionTests */ /* diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index 77d0dd20974bc..36a140c474ae5 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.ByteVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(byte[] r, byte[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(byte[] r, byte[] order, byte[] a, byte[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(byte[] r, byte[] a, byte[] order, int vector_len) { int i = 0, j = 0; try { @@ -943,6 +963,33 @@ static byte bits(byte e) { }) ); + static final List> BYTE_SATURATING_GENERATORS = List.of( + withToString("byte[Byte.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MIN_VALUE)); + }), + withToString("byte[Byte.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MAX_VALUE)); + }), + withToString("byte[Byte.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MAX_VALUE - 100)); + }), + withToString("byte[Byte.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MIN_VALUE + 100)); + }), + withToString("byte[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(-i * 5)); + }), + withToString("byte[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> BYTE_GENERATOR_PAIRS = @@ -950,6 +997,11 @@ static byte bits(byte e) { flatMap(fa -> BYTE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> BYTE_SATURATING_GENERATOR_PAIRS = + Stream.of(BYTE_GENERATORS.get(0)). + flatMap(fa -> BYTE_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -962,18 +1014,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> BYTE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("byte[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(RAND.nextInt())); + }) + ); + + static final List>> BYTE_GENERATOR_SELECT_FROM_TRIPLES = + BYTE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] byteBinaryOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSaturatingBinaryOpProvider() { + return BYTE_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteIndexedOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> BYTE_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -989,6 +1068,12 @@ public Object[][] byteTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSelectFromTwoVectorOpProvider() { + return BYTE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2902,6 +2987,252 @@ static void maxByte128VectorTests(IntFunction fa, IntFunction fb assertArraysEquals(r, a, b, Byte128VectorTests::max); } + static byte UMIN(byte a, byte b) { + return (byte)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "byteBinaryOpProvider") + static void UMINByte128VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::UMIN); + } + + @Test(dataProvider = "byteBinaryOpMaskProvider") + static void UMINByte128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte128VectorTests::UMIN); + } + + static byte UMAX(byte a, byte b) { + return (byte)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "byteBinaryOpProvider") + static void UMAXByte128VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::UMAX); + } + + @Test(dataProvider = "byteBinaryOpMaskProvider") + static void UMAXByte128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte128VectorTests::UMAX); + } + + static byte SADD(byte a, byte b) { + return (byte)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SADDByte128VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::SADD); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SADDByte128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte128VectorTests::SADD); + } + + static byte SSUB(byte a, byte b) { + return (byte)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SSUBByte128VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::SSUB); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SSUBByte128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte128VectorTests::SSUB); + } + + static byte SUADD(byte a, byte b) { + return (byte)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SUADDByte128VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::SUADD); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SUADDByte128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte128VectorTests::SUADD); + } + + static byte SUSUB(byte a, byte b) { + return (byte)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SUSUBByte128VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::SUSUB); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SUSUBByte128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte128VectorTests::SUSUB); + } + @Test(dataProvider = "byteBinaryOpProvider") static void MINByte128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -4110,7 +4441,7 @@ static void GEByte128VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTByte128VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4118,7 +4449,7 @@ static void UNSIGNED_LTByte128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4129,7 +4460,7 @@ static void UNSIGNED_LTByte128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTByte128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4141,7 +4472,7 @@ static void UNSIGNED_LTByte128VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4152,7 +4483,7 @@ static void UNSIGNED_LTByte128VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_GTByte128VectorTests(IntFunction fa, IntFunction fb) { + static void UGTByte128VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4160,7 +4491,7 @@ static void UNSIGNED_GTByte128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4171,7 +4502,7 @@ static void UNSIGNED_GTByte128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTByte128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4183,7 +4514,7 @@ static void UNSIGNED_GTByte128VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4194,7 +4525,7 @@ static void UNSIGNED_GTByte128VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_LEByte128VectorTests(IntFunction fa, IntFunction fb) { + static void ULEByte128VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4202,7 +4533,7 @@ static void UNSIGNED_LEByte128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4213,7 +4544,7 @@ static void UNSIGNED_LEByte128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEByte128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4225,7 +4556,7 @@ static void UNSIGNED_LEByte128VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4236,7 +4567,7 @@ static void UNSIGNED_LEByte128VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_GEByte128VectorTests(IntFunction fa, IntFunction fb) { + static void UGEByte128VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4244,7 +4575,7 @@ static void UNSIGNED_GEByte128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4255,7 +4586,7 @@ static void UNSIGNED_GEByte128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEByte128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4267,7 +4598,7 @@ static void UNSIGNED_GEByte128VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5746,6 +6077,24 @@ static void SelectFromByte128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "byteSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorByte128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] idx = fc.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + ByteVector idxv = ByteVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "byteUnaryOpSelectFromMaskProvider") static void SelectFromByte128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index 31e38f633fff8..0ad567b5ee4ed 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.ByteVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(byte[] r, byte[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(byte[] r, byte[] order, byte[] a, byte[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(byte[] r, byte[] a, byte[] order, int vector_len) { int i = 0, j = 0; try { @@ -943,6 +963,33 @@ static byte bits(byte e) { }) ); + static final List> BYTE_SATURATING_GENERATORS = List.of( + withToString("byte[Byte.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MIN_VALUE)); + }), + withToString("byte[Byte.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MAX_VALUE)); + }), + withToString("byte[Byte.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MAX_VALUE - 100)); + }), + withToString("byte[Byte.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MIN_VALUE + 100)); + }), + withToString("byte[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(-i * 5)); + }), + withToString("byte[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> BYTE_GENERATOR_PAIRS = @@ -950,6 +997,11 @@ static byte bits(byte e) { flatMap(fa -> BYTE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> BYTE_SATURATING_GENERATOR_PAIRS = + Stream.of(BYTE_GENERATORS.get(0)). + flatMap(fa -> BYTE_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -962,18 +1014,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> BYTE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("byte[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(RAND.nextInt())); + }) + ); + + static final List>> BYTE_GENERATOR_SELECT_FROM_TRIPLES = + BYTE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] byteBinaryOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSaturatingBinaryOpProvider() { + return BYTE_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteIndexedOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> BYTE_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -989,6 +1068,12 @@ public Object[][] byteTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSelectFromTwoVectorOpProvider() { + return BYTE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2902,6 +2987,252 @@ static void maxByte256VectorTests(IntFunction fa, IntFunction fb assertArraysEquals(r, a, b, Byte256VectorTests::max); } + static byte UMIN(byte a, byte b) { + return (byte)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "byteBinaryOpProvider") + static void UMINByte256VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::UMIN); + } + + @Test(dataProvider = "byteBinaryOpMaskProvider") + static void UMINByte256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte256VectorTests::UMIN); + } + + static byte UMAX(byte a, byte b) { + return (byte)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "byteBinaryOpProvider") + static void UMAXByte256VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::UMAX); + } + + @Test(dataProvider = "byteBinaryOpMaskProvider") + static void UMAXByte256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte256VectorTests::UMAX); + } + + static byte SADD(byte a, byte b) { + return (byte)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SADDByte256VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::SADD); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SADDByte256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte256VectorTests::SADD); + } + + static byte SSUB(byte a, byte b) { + return (byte)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SSUBByte256VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::SSUB); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SSUBByte256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte256VectorTests::SSUB); + } + + static byte SUADD(byte a, byte b) { + return (byte)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SUADDByte256VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::SUADD); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SUADDByte256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte256VectorTests::SUADD); + } + + static byte SUSUB(byte a, byte b) { + return (byte)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SUSUBByte256VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::SUSUB); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SUSUBByte256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte256VectorTests::SUSUB); + } + @Test(dataProvider = "byteBinaryOpProvider") static void MINByte256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -4110,7 +4441,7 @@ static void GEByte256VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTByte256VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4118,7 +4449,7 @@ static void UNSIGNED_LTByte256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4129,7 +4460,7 @@ static void UNSIGNED_LTByte256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTByte256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4141,7 +4472,7 @@ static void UNSIGNED_LTByte256VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4152,7 +4483,7 @@ static void UNSIGNED_LTByte256VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_GTByte256VectorTests(IntFunction fa, IntFunction fb) { + static void UGTByte256VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4160,7 +4491,7 @@ static void UNSIGNED_GTByte256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4171,7 +4502,7 @@ static void UNSIGNED_GTByte256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTByte256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4183,7 +4514,7 @@ static void UNSIGNED_GTByte256VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4194,7 +4525,7 @@ static void UNSIGNED_GTByte256VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_LEByte256VectorTests(IntFunction fa, IntFunction fb) { + static void ULEByte256VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4202,7 +4533,7 @@ static void UNSIGNED_LEByte256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4213,7 +4544,7 @@ static void UNSIGNED_LEByte256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEByte256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4225,7 +4556,7 @@ static void UNSIGNED_LEByte256VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4236,7 +4567,7 @@ static void UNSIGNED_LEByte256VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_GEByte256VectorTests(IntFunction fa, IntFunction fb) { + static void UGEByte256VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4244,7 +4575,7 @@ static void UNSIGNED_GEByte256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4255,7 +4586,7 @@ static void UNSIGNED_GEByte256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEByte256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4267,7 +4598,7 @@ static void UNSIGNED_GEByte256VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5746,6 +6077,24 @@ static void SelectFromByte256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "byteSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorByte256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] idx = fc.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + ByteVector idxv = ByteVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "byteUnaryOpSelectFromMaskProvider") static void SelectFromByte256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index 9204c3ed1ad37..0edc66dfccced 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.ByteVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(byte[] r, byte[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(byte[] r, byte[] order, byte[] a, byte[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(byte[] r, byte[] a, byte[] order, int vector_len) { int i = 0, j = 0; try { @@ -943,6 +963,33 @@ static byte bits(byte e) { }) ); + static final List> BYTE_SATURATING_GENERATORS = List.of( + withToString("byte[Byte.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MIN_VALUE)); + }), + withToString("byte[Byte.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MAX_VALUE)); + }), + withToString("byte[Byte.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MAX_VALUE - 100)); + }), + withToString("byte[Byte.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MIN_VALUE + 100)); + }), + withToString("byte[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(-i * 5)); + }), + withToString("byte[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> BYTE_GENERATOR_PAIRS = @@ -950,6 +997,11 @@ static byte bits(byte e) { flatMap(fa -> BYTE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> BYTE_SATURATING_GENERATOR_PAIRS = + Stream.of(BYTE_GENERATORS.get(0)). + flatMap(fa -> BYTE_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -962,18 +1014,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> BYTE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("byte[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(RAND.nextInt())); + }) + ); + + static final List>> BYTE_GENERATOR_SELECT_FROM_TRIPLES = + BYTE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] byteBinaryOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSaturatingBinaryOpProvider() { + return BYTE_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteIndexedOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> BYTE_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -989,6 +1068,12 @@ public Object[][] byteTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSelectFromTwoVectorOpProvider() { + return BYTE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2902,6 +2987,252 @@ static void maxByte512VectorTests(IntFunction fa, IntFunction fb assertArraysEquals(r, a, b, Byte512VectorTests::max); } + static byte UMIN(byte a, byte b) { + return (byte)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "byteBinaryOpProvider") + static void UMINByte512VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::UMIN); + } + + @Test(dataProvider = "byteBinaryOpMaskProvider") + static void UMINByte512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte512VectorTests::UMIN); + } + + static byte UMAX(byte a, byte b) { + return (byte)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "byteBinaryOpProvider") + static void UMAXByte512VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::UMAX); + } + + @Test(dataProvider = "byteBinaryOpMaskProvider") + static void UMAXByte512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte512VectorTests::UMAX); + } + + static byte SADD(byte a, byte b) { + return (byte)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SADDByte512VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::SADD); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SADDByte512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte512VectorTests::SADD); + } + + static byte SSUB(byte a, byte b) { + return (byte)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SSUBByte512VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::SSUB); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SSUBByte512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte512VectorTests::SSUB); + } + + static byte SUADD(byte a, byte b) { + return (byte)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SUADDByte512VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::SUADD); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SUADDByte512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte512VectorTests::SUADD); + } + + static byte SUSUB(byte a, byte b) { + return (byte)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SUSUBByte512VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::SUSUB); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SUSUBByte512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte512VectorTests::SUSUB); + } + @Test(dataProvider = "byteBinaryOpProvider") static void MINByte512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -4110,7 +4441,7 @@ static void GEByte512VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTByte512VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4118,7 +4449,7 @@ static void UNSIGNED_LTByte512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4129,7 +4460,7 @@ static void UNSIGNED_LTByte512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTByte512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4141,7 +4472,7 @@ static void UNSIGNED_LTByte512VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4152,7 +4483,7 @@ static void UNSIGNED_LTByte512VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_GTByte512VectorTests(IntFunction fa, IntFunction fb) { + static void UGTByte512VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4160,7 +4491,7 @@ static void UNSIGNED_GTByte512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4171,7 +4502,7 @@ static void UNSIGNED_GTByte512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTByte512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4183,7 +4514,7 @@ static void UNSIGNED_GTByte512VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4194,7 +4525,7 @@ static void UNSIGNED_GTByte512VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_LEByte512VectorTests(IntFunction fa, IntFunction fb) { + static void ULEByte512VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4202,7 +4533,7 @@ static void UNSIGNED_LEByte512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4213,7 +4544,7 @@ static void UNSIGNED_LEByte512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEByte512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4225,7 +4556,7 @@ static void UNSIGNED_LEByte512VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4236,7 +4567,7 @@ static void UNSIGNED_LEByte512VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_GEByte512VectorTests(IntFunction fa, IntFunction fb) { + static void UGEByte512VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4244,7 +4575,7 @@ static void UNSIGNED_GEByte512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4255,7 +4586,7 @@ static void UNSIGNED_GEByte512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEByte512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4267,7 +4598,7 @@ static void UNSIGNED_GEByte512VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5746,6 +6077,24 @@ static void SelectFromByte512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "byteSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorByte512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] idx = fc.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + ByteVector idxv = ByteVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "byteUnaryOpSelectFromMaskProvider") static void SelectFromByte512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index 9af640a313393..98c8382c5263e 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.ByteVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(byte[] r, byte[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(byte[] r, byte[] order, byte[] a, byte[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(byte[] r, byte[] a, byte[] order, int vector_len) { int i = 0, j = 0; try { @@ -943,6 +963,33 @@ static byte bits(byte e) { }) ); + static final List> BYTE_SATURATING_GENERATORS = List.of( + withToString("byte[Byte.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MIN_VALUE)); + }), + withToString("byte[Byte.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MAX_VALUE)); + }), + withToString("byte[Byte.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MAX_VALUE - 100)); + }), + withToString("byte[Byte.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MIN_VALUE + 100)); + }), + withToString("byte[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(-i * 5)); + }), + withToString("byte[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> BYTE_GENERATOR_PAIRS = @@ -950,6 +997,11 @@ static byte bits(byte e) { flatMap(fa -> BYTE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> BYTE_SATURATING_GENERATOR_PAIRS = + Stream.of(BYTE_GENERATORS.get(0)). + flatMap(fa -> BYTE_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -962,18 +1014,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> BYTE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("byte[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(RAND.nextInt())); + }) + ); + + static final List>> BYTE_GENERATOR_SELECT_FROM_TRIPLES = + BYTE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] byteBinaryOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSaturatingBinaryOpProvider() { + return BYTE_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteIndexedOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> BYTE_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -989,6 +1068,12 @@ public Object[][] byteTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSelectFromTwoVectorOpProvider() { + return BYTE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2902,6 +2987,252 @@ static void maxByte64VectorTests(IntFunction fa, IntFunction fb) assertArraysEquals(r, a, b, Byte64VectorTests::max); } + static byte UMIN(byte a, byte b) { + return (byte)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "byteBinaryOpProvider") + static void UMINByte64VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::UMIN); + } + + @Test(dataProvider = "byteBinaryOpMaskProvider") + static void UMINByte64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte64VectorTests::UMIN); + } + + static byte UMAX(byte a, byte b) { + return (byte)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "byteBinaryOpProvider") + static void UMAXByte64VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::UMAX); + } + + @Test(dataProvider = "byteBinaryOpMaskProvider") + static void UMAXByte64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte64VectorTests::UMAX); + } + + static byte SADD(byte a, byte b) { + return (byte)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SADDByte64VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::SADD); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SADDByte64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte64VectorTests::SADD); + } + + static byte SSUB(byte a, byte b) { + return (byte)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SSUBByte64VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::SSUB); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SSUBByte64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte64VectorTests::SSUB); + } + + static byte SUADD(byte a, byte b) { + return (byte)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SUADDByte64VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::SUADD); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SUADDByte64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte64VectorTests::SUADD); + } + + static byte SUSUB(byte a, byte b) { + return (byte)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SUSUBByte64VectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::SUSUB); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SUSUBByte64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Byte64VectorTests::SUSUB); + } + @Test(dataProvider = "byteBinaryOpProvider") static void MINByte64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -4110,7 +4441,7 @@ static void GEByte64VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTByte64VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4118,7 +4449,7 @@ static void UNSIGNED_LTByte64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4129,7 +4460,7 @@ static void UNSIGNED_LTByte64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTByte64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4141,7 +4472,7 @@ static void UNSIGNED_LTByte64VectorTestsMasked(IntFunction fa, IntFuncti for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4152,7 +4483,7 @@ static void UNSIGNED_LTByte64VectorTestsMasked(IntFunction fa, IntFuncti } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_GTByte64VectorTests(IntFunction fa, IntFunction fb) { + static void UGTByte64VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4160,7 +4491,7 @@ static void UNSIGNED_GTByte64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4171,7 +4502,7 @@ static void UNSIGNED_GTByte64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTByte64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4183,7 +4514,7 @@ static void UNSIGNED_GTByte64VectorTestsMasked(IntFunction fa, IntFuncti for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4194,7 +4525,7 @@ static void UNSIGNED_GTByte64VectorTestsMasked(IntFunction fa, IntFuncti } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_LEByte64VectorTests(IntFunction fa, IntFunction fb) { + static void ULEByte64VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4202,7 +4533,7 @@ static void UNSIGNED_LEByte64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4213,7 +4544,7 @@ static void UNSIGNED_LEByte64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEByte64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4225,7 +4556,7 @@ static void UNSIGNED_LEByte64VectorTestsMasked(IntFunction fa, IntFuncti for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4236,7 +4567,7 @@ static void UNSIGNED_LEByte64VectorTestsMasked(IntFunction fa, IntFuncti } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_GEByte64VectorTests(IntFunction fa, IntFunction fb) { + static void UGEByte64VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4244,7 +4575,7 @@ static void UNSIGNED_GEByte64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4255,7 +4586,7 @@ static void UNSIGNED_GEByte64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEByte64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4267,7 +4598,7 @@ static void UNSIGNED_GEByte64VectorTestsMasked(IntFunction fa, IntFuncti for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5746,6 +6077,24 @@ static void SelectFromByte64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "byteSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorByte64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] idx = fc.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + ByteVector idxv = ByteVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "byteUnaryOpSelectFromMaskProvider") static void SelectFromByte64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index 1c0d5362b536c..2d9d49f32addf 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.ByteVector; @@ -307,6 +308,25 @@ static void assertexpandArraysEquals(byte[] r, byte[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(byte[] r, byte[] order, byte[] a, byte[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(byte[] r, byte[] a, byte[] order, int vector_len) { int i = 0, j = 0; try { @@ -948,6 +968,33 @@ static byte bits(byte e) { }) ); + static final List> BYTE_SATURATING_GENERATORS = List.of( + withToString("byte[Byte.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MIN_VALUE)); + }), + withToString("byte[Byte.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MAX_VALUE)); + }), + withToString("byte[Byte.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MAX_VALUE - 100)); + }), + withToString("byte[Byte.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(Byte.MIN_VALUE + 100)); + }), + withToString("byte[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(-i * 5)); + }), + withToString("byte[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> BYTE_GENERATOR_PAIRS = @@ -955,6 +1002,11 @@ static byte bits(byte e) { flatMap(fa -> BYTE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> BYTE_SATURATING_GENERATOR_PAIRS = + Stream.of(BYTE_GENERATORS.get(0)). + flatMap(fa -> BYTE_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -967,18 +1019,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> BYTE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("byte[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(RAND.nextInt())); + }) + ); + + static final List>> BYTE_GENERATOR_SELECT_FROM_TRIPLES = + BYTE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] byteBinaryOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSaturatingBinaryOpProvider() { + return BYTE_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteIndexedOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> BYTE_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -994,6 +1073,12 @@ public Object[][] byteTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSelectFromTwoVectorOpProvider() { + return BYTE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2907,6 +2992,252 @@ static void maxByteMaxVectorTests(IntFunction fa, IntFunction fb assertArraysEquals(r, a, b, ByteMaxVectorTests::max); } + static byte UMIN(byte a, byte b) { + return (byte)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "byteBinaryOpProvider") + static void UMINByteMaxVectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::UMIN); + } + + @Test(dataProvider = "byteBinaryOpMaskProvider") + static void UMINByteMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ByteMaxVectorTests::UMIN); + } + + static byte UMAX(byte a, byte b) { + return (byte)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "byteBinaryOpProvider") + static void UMAXByteMaxVectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::UMAX); + } + + @Test(dataProvider = "byteBinaryOpMaskProvider") + static void UMAXByteMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ByteMaxVectorTests::UMAX); + } + + static byte SADD(byte a, byte b) { + return (byte)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SADDByteMaxVectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::SADD); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SADDByteMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ByteMaxVectorTests::SADD); + } + + static byte SSUB(byte a, byte b) { + return (byte)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SSUBByteMaxVectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::SSUB); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SSUBByteMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ByteMaxVectorTests::SSUB); + } + + static byte SUADD(byte a, byte b) { + return (byte)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SUADDByteMaxVectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::SUADD); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SUADDByteMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ByteMaxVectorTests::SUADD); + } + + static byte SUSUB(byte a, byte b) { + return (byte)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "byteSaturatingBinaryOpProvider") + static void SUSUBByteMaxVectorTests(IntFunction fa, IntFunction fb) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::SUSUB); + } + + @Test(dataProvider = "byteSaturatingBinaryOpMaskProvider") + static void SUSUBByteMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ByteMaxVectorTests::SUSUB); + } + @Test(dataProvider = "byteBinaryOpProvider") static void MINByteMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -4115,7 +4446,7 @@ static void GEByteMaxVectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTByteMaxVectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4123,7 +4454,7 @@ static void UNSIGNED_LTByteMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4134,7 +4465,7 @@ static void UNSIGNED_LTByteMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTByteMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4146,7 +4477,7 @@ static void UNSIGNED_LTByteMaxVectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4157,7 +4488,7 @@ static void UNSIGNED_LTByteMaxVectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_GTByteMaxVectorTests(IntFunction fa, IntFunction fb) { + static void UGTByteMaxVectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4165,7 +4496,7 @@ static void UNSIGNED_GTByteMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4176,7 +4507,7 @@ static void UNSIGNED_GTByteMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTByteMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4188,7 +4519,7 @@ static void UNSIGNED_GTByteMaxVectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4199,7 +4530,7 @@ static void UNSIGNED_GTByteMaxVectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_LEByteMaxVectorTests(IntFunction fa, IntFunction fb) { + static void ULEByteMaxVectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4207,7 +4538,7 @@ static void UNSIGNED_LEByteMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4218,7 +4549,7 @@ static void UNSIGNED_LEByteMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEByteMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4230,7 +4561,7 @@ static void UNSIGNED_LEByteMaxVectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4241,7 +4572,7 @@ static void UNSIGNED_LEByteMaxVectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "byteCompareOpProvider") - static void UNSIGNED_GEByteMaxVectorTests(IntFunction fa, IntFunction fb) { + static void UGEByteMaxVectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4249,7 +4580,7 @@ static void UNSIGNED_GEByteMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4260,7 +4591,7 @@ static void UNSIGNED_GEByteMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEByteMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); @@ -4272,7 +4603,7 @@ static void UNSIGNED_GEByteMaxVectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); ByteVector bv = ByteVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5751,6 +6082,24 @@ static void SelectFromByteMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "byteSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorByteMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] idx = fc.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + ByteVector idxv = ByteVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "byteUnaryOpSelectFromMaskProvider") static void SelectFromByteMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 4efeb8f205991..05678c4290beb 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(double[] r, double[] a, boolean[] m, int ve } } + static void assertSelectFromTwoVectorEquals(double[] r, double[] order, double[] a, double[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(double[] r, double[] a, double[] order, int vector_len) { int i = 0, j = 0; try { @@ -1108,6 +1127,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> DOUBLE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("double[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)(RAND.nextInt())); + }) + ); + + static final List>> DOUBLE_GENERATOR_SELECT_FROM_TRIPLES = + DOUBLE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] doubleBinaryOpProvider() { return DOUBLE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1135,6 +1166,12 @@ public Object[][] doubleTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] doubleSelectFromTwoVectorOpProvider() { + return DOUBLE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] doubleTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4799,6 +4836,24 @@ static void SelectFromDouble128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "doubleSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorDouble128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); + double[] idx = fc.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + DoubleVector bv = DoubleVector.fromArray(SPECIES, b, i); + DoubleVector idxv = DoubleVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "doubleUnaryOpSelectFromMaskProvider") static void SelectFromDouble128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index 04b0e7dc0d68e..fe59fc85a2ed1 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(double[] r, double[] a, boolean[] m, int ve } } + static void assertSelectFromTwoVectorEquals(double[] r, double[] order, double[] a, double[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(double[] r, double[] a, double[] order, int vector_len) { int i = 0, j = 0; try { @@ -1108,6 +1127,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> DOUBLE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("double[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)(RAND.nextInt())); + }) + ); + + static final List>> DOUBLE_GENERATOR_SELECT_FROM_TRIPLES = + DOUBLE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] doubleBinaryOpProvider() { return DOUBLE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1135,6 +1166,12 @@ public Object[][] doubleTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] doubleSelectFromTwoVectorOpProvider() { + return DOUBLE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] doubleTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4799,6 +4836,24 @@ static void SelectFromDouble256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "doubleSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorDouble256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); + double[] idx = fc.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + DoubleVector bv = DoubleVector.fromArray(SPECIES, b, i); + DoubleVector idxv = DoubleVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "doubleUnaryOpSelectFromMaskProvider") static void SelectFromDouble256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index ad03b8b5c7b48..1e5b68ab98925 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(double[] r, double[] a, boolean[] m, int ve } } + static void assertSelectFromTwoVectorEquals(double[] r, double[] order, double[] a, double[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(double[] r, double[] a, double[] order, int vector_len) { int i = 0, j = 0; try { @@ -1108,6 +1127,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> DOUBLE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("double[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)(RAND.nextInt())); + }) + ); + + static final List>> DOUBLE_GENERATOR_SELECT_FROM_TRIPLES = + DOUBLE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] doubleBinaryOpProvider() { return DOUBLE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1135,6 +1166,12 @@ public Object[][] doubleTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] doubleSelectFromTwoVectorOpProvider() { + return DOUBLE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] doubleTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4799,6 +4836,24 @@ static void SelectFromDouble512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "doubleSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorDouble512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); + double[] idx = fc.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + DoubleVector bv = DoubleVector.fromArray(SPECIES, b, i); + DoubleVector idxv = DoubleVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "doubleUnaryOpSelectFromMaskProvider") static void SelectFromDouble512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 9321215c3de73..b56b4d237f45c 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(double[] r, double[] a, boolean[] m, int ve } } + static void assertSelectFromTwoVectorEquals(double[] r, double[] order, double[] a, double[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(double[] r, double[] a, double[] order, int vector_len) { int i = 0, j = 0; try { @@ -1108,6 +1127,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> DOUBLE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("double[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)(RAND.nextInt())); + }) + ); + + static final List>> DOUBLE_GENERATOR_SELECT_FROM_TRIPLES = + DOUBLE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] doubleBinaryOpProvider() { return DOUBLE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1135,6 +1166,12 @@ public Object[][] doubleTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] doubleSelectFromTwoVectorOpProvider() { + return DOUBLE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] doubleTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4799,6 +4836,24 @@ static void SelectFromDouble64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "doubleSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorDouble64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); + double[] idx = fc.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + DoubleVector bv = DoubleVector.fromArray(SPECIES, b, i); + DoubleVector idxv = DoubleVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "doubleUnaryOpSelectFromMaskProvider") static void SelectFromDouble64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index a6b80376196c6..43da4f5763641 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -326,6 +326,25 @@ static void assertexpandArraysEquals(double[] r, double[] a, boolean[] m, int ve } } + static void assertSelectFromTwoVectorEquals(double[] r, double[] order, double[] a, double[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(double[] r, double[] a, double[] order, int vector_len) { int i = 0, j = 0; try { @@ -1113,6 +1132,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> DOUBLE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("double[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)(RAND.nextInt())); + }) + ); + + static final List>> DOUBLE_GENERATOR_SELECT_FROM_TRIPLES = + DOUBLE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] doubleBinaryOpProvider() { return DOUBLE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1140,6 +1171,12 @@ public Object[][] doubleTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] doubleSelectFromTwoVectorOpProvider() { + return DOUBLE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] doubleTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4804,6 +4841,24 @@ static void SelectFromDoubleMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "doubleSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorDoubleMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); + double[] idx = fc.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + DoubleVector bv = DoubleVector.fromArray(SPECIES, b, i); + DoubleVector idxv = DoubleVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "doubleUnaryOpSelectFromMaskProvider") static void SelectFromDoubleMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index 6bad90985442e..549199513d532 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(float[] r, float[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(float[] r, float[] order, float[] a, float[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(float[] r, float[] a, float[] order, int vector_len) { int i = 0, j = 0; try { @@ -1119,6 +1138,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> FLOAT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("float[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)(RAND.nextInt())); + }) + ); + + static final List>> FLOAT_GENERATOR_SELECT_FROM_TRIPLES = + FLOAT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] floatBinaryOpProvider() { return FLOAT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1146,6 +1177,12 @@ public Object[][] floatTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] floatSelectFromTwoVectorOpProvider() { + return FLOAT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] floatTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4778,6 +4815,24 @@ static void SelectFromFloat128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "floatSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorFloat128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); + float[] idx = fc.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + FloatVector bv = FloatVector.fromArray(SPECIES, b, i); + FloatVector idxv = FloatVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "floatUnaryOpSelectFromMaskProvider") static void SelectFromFloat128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index e714ace5a7814..6d17727c3257e 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(float[] r, float[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(float[] r, float[] order, float[] a, float[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(float[] r, float[] a, float[] order, int vector_len) { int i = 0, j = 0; try { @@ -1119,6 +1138,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> FLOAT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("float[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)(RAND.nextInt())); + }) + ); + + static final List>> FLOAT_GENERATOR_SELECT_FROM_TRIPLES = + FLOAT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] floatBinaryOpProvider() { return FLOAT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1146,6 +1177,12 @@ public Object[][] floatTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] floatSelectFromTwoVectorOpProvider() { + return FLOAT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] floatTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4778,6 +4815,24 @@ static void SelectFromFloat256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "floatSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorFloat256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); + float[] idx = fc.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + FloatVector bv = FloatVector.fromArray(SPECIES, b, i); + FloatVector idxv = FloatVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "floatUnaryOpSelectFromMaskProvider") static void SelectFromFloat256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index f3c5a316c79db..c2290eb708066 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(float[] r, float[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(float[] r, float[] order, float[] a, float[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(float[] r, float[] a, float[] order, int vector_len) { int i = 0, j = 0; try { @@ -1119,6 +1138,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> FLOAT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("float[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)(RAND.nextInt())); + }) + ); + + static final List>> FLOAT_GENERATOR_SELECT_FROM_TRIPLES = + FLOAT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] floatBinaryOpProvider() { return FLOAT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1146,6 +1177,12 @@ public Object[][] floatTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] floatSelectFromTwoVectorOpProvider() { + return FLOAT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] floatTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4778,6 +4815,24 @@ static void SelectFromFloat512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "floatSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorFloat512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); + float[] idx = fc.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + FloatVector bv = FloatVector.fromArray(SPECIES, b, i); + FloatVector idxv = FloatVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "floatUnaryOpSelectFromMaskProvider") static void SelectFromFloat512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index 378c2ae783fea..0d50726f644fd 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(float[] r, float[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(float[] r, float[] order, float[] a, float[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(float[] r, float[] a, float[] order, int vector_len) { int i = 0, j = 0; try { @@ -1119,6 +1138,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> FLOAT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("float[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)(RAND.nextInt())); + }) + ); + + static final List>> FLOAT_GENERATOR_SELECT_FROM_TRIPLES = + FLOAT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] floatBinaryOpProvider() { return FLOAT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1146,6 +1177,12 @@ public Object[][] floatTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] floatSelectFromTwoVectorOpProvider() { + return FLOAT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] floatTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4778,6 +4815,24 @@ static void SelectFromFloat64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "floatSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorFloat64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); + float[] idx = fc.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + FloatVector bv = FloatVector.fromArray(SPECIES, b, i); + FloatVector idxv = FloatVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "floatUnaryOpSelectFromMaskProvider") static void SelectFromFloat64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index a2dc38413ec35..6a0b1301ab328 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -326,6 +326,25 @@ static void assertexpandArraysEquals(float[] r, float[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(float[] r, float[] order, float[] a, float[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(float[] r, float[] a, float[] order, int vector_len) { int i = 0, j = 0; try { @@ -1124,6 +1143,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> FLOAT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("float[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)(RAND.nextInt())); + }) + ); + + static final List>> FLOAT_GENERATOR_SELECT_FROM_TRIPLES = + FLOAT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] floatBinaryOpProvider() { return FLOAT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1151,6 +1182,12 @@ public Object[][] floatTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] floatSelectFromTwoVectorOpProvider() { + return FLOAT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] floatTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4783,6 +4820,24 @@ static void SelectFromFloatMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "floatSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorFloatMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); + float[] idx = fc.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + FloatVector bv = FloatVector.fromArray(SPECIES, b, i); + FloatVector idxv = FloatVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "floatUnaryOpSelectFromMaskProvider") static void SelectFromFloatMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index 1ee0bbc319717..028e757e8537c 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.IntVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(int[] r, int[] a, boolean[] m, int vector_l } } + static void assertSelectFromTwoVectorEquals(int[] r, int[] order, int[] a, int[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -933,6 +953,33 @@ static int bits(int e) { }) ); + static final List> INT_SATURATING_GENERATORS = List.of( + withToString("int[Integer.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MIN_VALUE)); + }), + withToString("int[Integer.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MAX_VALUE)); + }), + withToString("int[Integer.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MAX_VALUE - 100)); + }), + withToString("int[Integer.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MIN_VALUE + 100)); + }), + withToString("int[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(-i * 5)); + }), + withToString("int[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> INT_GENERATOR_PAIRS = @@ -940,6 +987,11 @@ static int bits(int e) { flatMap(fa -> INT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> INT_SATURATING_GENERATOR_PAIRS = + Stream.of(INT_GENERATORS.get(0)). + flatMap(fa -> INT_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -952,18 +1004,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> INT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("int[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(RAND.nextInt())); + }) + ); + + static final List>> INT_GENERATOR_SELECT_FROM_TRIPLES = + INT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] intBinaryOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] intSaturatingBinaryOpProvider() { + return INT_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intIndexedOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] intSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> INT_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -979,6 +1058,12 @@ public Object[][] intTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] intSelectFromTwoVectorOpProvider() { + return INT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2946,6 +3031,252 @@ static void maxInt128VectorTests(IntFunction fa, IntFunction fb) { assertArraysEquals(r, a, b, Int128VectorTests::max); } + static int UMIN(int a, int b) { + return (int)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "intBinaryOpProvider") + static void UMINInt128VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::UMIN); + } + + @Test(dataProvider = "intBinaryOpMaskProvider") + static void UMINInt128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int128VectorTests::UMIN); + } + + static int UMAX(int a, int b) { + return (int)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "intBinaryOpProvider") + static void UMAXInt128VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::UMAX); + } + + @Test(dataProvider = "intBinaryOpMaskProvider") + static void UMAXInt128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int128VectorTests::UMAX); + } + + static int SADD(int a, int b) { + return (int)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SADDInt128VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::SADD); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SADDInt128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int128VectorTests::SADD); + } + + static int SSUB(int a, int b) { + return (int)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SSUBInt128VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::SSUB); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SSUBInt128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int128VectorTests::SSUB); + } + + static int SUADD(int a, int b) { + return (int)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SUADDInt128VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::SUADD); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SUADDInt128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int128VectorTests::SUADD); + } + + static int SUSUB(int a, int b) { + return (int)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SUSUBInt128VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::SUSUB); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SUSUBInt128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int128VectorTests::SUSUB); + } + @Test(dataProvider = "intBinaryOpProvider") static void MINInt128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -4154,7 +4485,7 @@ static void GEInt128VectorTestsMasked(IntFunction fa, IntFunction } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_LTInt128VectorTests(IntFunction fa, IntFunction fb) { + static void ULTInt128VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4162,7 +4493,7 @@ static void UNSIGNED_LTInt128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4173,7 +4504,7 @@ static void UNSIGNED_LTInt128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTInt128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4185,7 +4516,7 @@ static void UNSIGNED_LTInt128VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4196,7 +4527,7 @@ static void UNSIGNED_LTInt128VectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_GTInt128VectorTests(IntFunction fa, IntFunction fb) { + static void UGTInt128VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4204,7 +4535,7 @@ static void UNSIGNED_GTInt128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4215,7 +4546,7 @@ static void UNSIGNED_GTInt128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTInt128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4227,7 +4558,7 @@ static void UNSIGNED_GTInt128VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4238,7 +4569,7 @@ static void UNSIGNED_GTInt128VectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_LEInt128VectorTests(IntFunction fa, IntFunction fb) { + static void ULEInt128VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4246,7 +4577,7 @@ static void UNSIGNED_LEInt128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4257,7 +4588,7 @@ static void UNSIGNED_LEInt128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEInt128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4269,7 +4600,7 @@ static void UNSIGNED_LEInt128VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4280,7 +4611,7 @@ static void UNSIGNED_LEInt128VectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_GEInt128VectorTests(IntFunction fa, IntFunction fb) { + static void UGEInt128VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4288,7 +4619,7 @@ static void UNSIGNED_GEInt128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4299,7 +4630,7 @@ static void UNSIGNED_GEInt128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEInt128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4311,7 +4642,7 @@ static void UNSIGNED_GEInt128VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5779,6 +6110,24 @@ static void SelectFromInt128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "intSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorInt128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] idx = fc.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + IntVector idxv = IntVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "intUnaryOpShuffleMaskProvider") static void SelectFromInt128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index 5257af21c942d..6dab8a398735c 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.IntVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(int[] r, int[] a, boolean[] m, int vector_l } } + static void assertSelectFromTwoVectorEquals(int[] r, int[] order, int[] a, int[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -933,6 +953,33 @@ static int bits(int e) { }) ); + static final List> INT_SATURATING_GENERATORS = List.of( + withToString("int[Integer.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MIN_VALUE)); + }), + withToString("int[Integer.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MAX_VALUE)); + }), + withToString("int[Integer.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MAX_VALUE - 100)); + }), + withToString("int[Integer.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MIN_VALUE + 100)); + }), + withToString("int[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(-i * 5)); + }), + withToString("int[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> INT_GENERATOR_PAIRS = @@ -940,6 +987,11 @@ static int bits(int e) { flatMap(fa -> INT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> INT_SATURATING_GENERATOR_PAIRS = + Stream.of(INT_GENERATORS.get(0)). + flatMap(fa -> INT_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -952,18 +1004,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> INT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("int[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(RAND.nextInt())); + }) + ); + + static final List>> INT_GENERATOR_SELECT_FROM_TRIPLES = + INT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] intBinaryOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] intSaturatingBinaryOpProvider() { + return INT_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intIndexedOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] intSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> INT_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -979,6 +1058,12 @@ public Object[][] intTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] intSelectFromTwoVectorOpProvider() { + return INT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2946,6 +3031,252 @@ static void maxInt256VectorTests(IntFunction fa, IntFunction fb) { assertArraysEquals(r, a, b, Int256VectorTests::max); } + static int UMIN(int a, int b) { + return (int)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "intBinaryOpProvider") + static void UMINInt256VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::UMIN); + } + + @Test(dataProvider = "intBinaryOpMaskProvider") + static void UMINInt256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int256VectorTests::UMIN); + } + + static int UMAX(int a, int b) { + return (int)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "intBinaryOpProvider") + static void UMAXInt256VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::UMAX); + } + + @Test(dataProvider = "intBinaryOpMaskProvider") + static void UMAXInt256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int256VectorTests::UMAX); + } + + static int SADD(int a, int b) { + return (int)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SADDInt256VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::SADD); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SADDInt256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int256VectorTests::SADD); + } + + static int SSUB(int a, int b) { + return (int)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SSUBInt256VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::SSUB); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SSUBInt256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int256VectorTests::SSUB); + } + + static int SUADD(int a, int b) { + return (int)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SUADDInt256VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::SUADD); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SUADDInt256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int256VectorTests::SUADD); + } + + static int SUSUB(int a, int b) { + return (int)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SUSUBInt256VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::SUSUB); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SUSUBInt256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int256VectorTests::SUSUB); + } + @Test(dataProvider = "intBinaryOpProvider") static void MINInt256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -4154,7 +4485,7 @@ static void GEInt256VectorTestsMasked(IntFunction fa, IntFunction } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_LTInt256VectorTests(IntFunction fa, IntFunction fb) { + static void ULTInt256VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4162,7 +4493,7 @@ static void UNSIGNED_LTInt256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4173,7 +4504,7 @@ static void UNSIGNED_LTInt256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTInt256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4185,7 +4516,7 @@ static void UNSIGNED_LTInt256VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4196,7 +4527,7 @@ static void UNSIGNED_LTInt256VectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_GTInt256VectorTests(IntFunction fa, IntFunction fb) { + static void UGTInt256VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4204,7 +4535,7 @@ static void UNSIGNED_GTInt256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4215,7 +4546,7 @@ static void UNSIGNED_GTInt256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTInt256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4227,7 +4558,7 @@ static void UNSIGNED_GTInt256VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4238,7 +4569,7 @@ static void UNSIGNED_GTInt256VectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_LEInt256VectorTests(IntFunction fa, IntFunction fb) { + static void ULEInt256VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4246,7 +4577,7 @@ static void UNSIGNED_LEInt256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4257,7 +4588,7 @@ static void UNSIGNED_LEInt256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEInt256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4269,7 +4600,7 @@ static void UNSIGNED_LEInt256VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4280,7 +4611,7 @@ static void UNSIGNED_LEInt256VectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_GEInt256VectorTests(IntFunction fa, IntFunction fb) { + static void UGEInt256VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4288,7 +4619,7 @@ static void UNSIGNED_GEInt256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4299,7 +4630,7 @@ static void UNSIGNED_GEInt256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEInt256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4311,7 +4642,7 @@ static void UNSIGNED_GEInt256VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5779,6 +6110,24 @@ static void SelectFromInt256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "intSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorInt256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] idx = fc.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + IntVector idxv = IntVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "intUnaryOpShuffleMaskProvider") static void SelectFromInt256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index 6d4633cc7ae1c..0c86655ff2206 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.IntVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(int[] r, int[] a, boolean[] m, int vector_l } } + static void assertSelectFromTwoVectorEquals(int[] r, int[] order, int[] a, int[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -933,6 +953,33 @@ static int bits(int e) { }) ); + static final List> INT_SATURATING_GENERATORS = List.of( + withToString("int[Integer.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MIN_VALUE)); + }), + withToString("int[Integer.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MAX_VALUE)); + }), + withToString("int[Integer.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MAX_VALUE - 100)); + }), + withToString("int[Integer.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MIN_VALUE + 100)); + }), + withToString("int[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(-i * 5)); + }), + withToString("int[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> INT_GENERATOR_PAIRS = @@ -940,6 +987,11 @@ static int bits(int e) { flatMap(fa -> INT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> INT_SATURATING_GENERATOR_PAIRS = + Stream.of(INT_GENERATORS.get(0)). + flatMap(fa -> INT_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -952,18 +1004,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> INT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("int[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(RAND.nextInt())); + }) + ); + + static final List>> INT_GENERATOR_SELECT_FROM_TRIPLES = + INT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] intBinaryOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] intSaturatingBinaryOpProvider() { + return INT_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intIndexedOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] intSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> INT_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -979,6 +1058,12 @@ public Object[][] intTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] intSelectFromTwoVectorOpProvider() { + return INT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2946,6 +3031,252 @@ static void maxInt512VectorTests(IntFunction fa, IntFunction fb) { assertArraysEquals(r, a, b, Int512VectorTests::max); } + static int UMIN(int a, int b) { + return (int)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "intBinaryOpProvider") + static void UMINInt512VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::UMIN); + } + + @Test(dataProvider = "intBinaryOpMaskProvider") + static void UMINInt512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int512VectorTests::UMIN); + } + + static int UMAX(int a, int b) { + return (int)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "intBinaryOpProvider") + static void UMAXInt512VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::UMAX); + } + + @Test(dataProvider = "intBinaryOpMaskProvider") + static void UMAXInt512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int512VectorTests::UMAX); + } + + static int SADD(int a, int b) { + return (int)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SADDInt512VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::SADD); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SADDInt512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int512VectorTests::SADD); + } + + static int SSUB(int a, int b) { + return (int)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SSUBInt512VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::SSUB); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SSUBInt512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int512VectorTests::SSUB); + } + + static int SUADD(int a, int b) { + return (int)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SUADDInt512VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::SUADD); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SUADDInt512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int512VectorTests::SUADD); + } + + static int SUSUB(int a, int b) { + return (int)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SUSUBInt512VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::SUSUB); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SUSUBInt512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int512VectorTests::SUSUB); + } + @Test(dataProvider = "intBinaryOpProvider") static void MINInt512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -4154,7 +4485,7 @@ static void GEInt512VectorTestsMasked(IntFunction fa, IntFunction } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_LTInt512VectorTests(IntFunction fa, IntFunction fb) { + static void ULTInt512VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4162,7 +4493,7 @@ static void UNSIGNED_LTInt512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4173,7 +4504,7 @@ static void UNSIGNED_LTInt512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTInt512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4185,7 +4516,7 @@ static void UNSIGNED_LTInt512VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4196,7 +4527,7 @@ static void UNSIGNED_LTInt512VectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_GTInt512VectorTests(IntFunction fa, IntFunction fb) { + static void UGTInt512VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4204,7 +4535,7 @@ static void UNSIGNED_GTInt512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4215,7 +4546,7 @@ static void UNSIGNED_GTInt512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTInt512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4227,7 +4558,7 @@ static void UNSIGNED_GTInt512VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4238,7 +4569,7 @@ static void UNSIGNED_GTInt512VectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_LEInt512VectorTests(IntFunction fa, IntFunction fb) { + static void ULEInt512VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4246,7 +4577,7 @@ static void UNSIGNED_LEInt512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4257,7 +4588,7 @@ static void UNSIGNED_LEInt512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEInt512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4269,7 +4600,7 @@ static void UNSIGNED_LEInt512VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4280,7 +4611,7 @@ static void UNSIGNED_LEInt512VectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_GEInt512VectorTests(IntFunction fa, IntFunction fb) { + static void UGEInt512VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4288,7 +4619,7 @@ static void UNSIGNED_GEInt512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4299,7 +4630,7 @@ static void UNSIGNED_GEInt512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEInt512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4311,7 +4642,7 @@ static void UNSIGNED_GEInt512VectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5779,6 +6110,24 @@ static void SelectFromInt512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "intSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorInt512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] idx = fc.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + IntVector idxv = IntVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "intUnaryOpShuffleMaskProvider") static void SelectFromInt512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index 7bd1543ed5c69..b2cb3698f6277 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.IntVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(int[] r, int[] a, boolean[] m, int vector_l } } + static void assertSelectFromTwoVectorEquals(int[] r, int[] order, int[] a, int[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -933,6 +953,33 @@ static int bits(int e) { }) ); + static final List> INT_SATURATING_GENERATORS = List.of( + withToString("int[Integer.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MIN_VALUE)); + }), + withToString("int[Integer.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MAX_VALUE)); + }), + withToString("int[Integer.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MAX_VALUE - 100)); + }), + withToString("int[Integer.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MIN_VALUE + 100)); + }), + withToString("int[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(-i * 5)); + }), + withToString("int[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> INT_GENERATOR_PAIRS = @@ -940,6 +987,11 @@ static int bits(int e) { flatMap(fa -> INT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> INT_SATURATING_GENERATOR_PAIRS = + Stream.of(INT_GENERATORS.get(0)). + flatMap(fa -> INT_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -952,18 +1004,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> INT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("int[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(RAND.nextInt())); + }) + ); + + static final List>> INT_GENERATOR_SELECT_FROM_TRIPLES = + INT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] intBinaryOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] intSaturatingBinaryOpProvider() { + return INT_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intIndexedOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] intSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> INT_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -979,6 +1058,12 @@ public Object[][] intTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] intSelectFromTwoVectorOpProvider() { + return INT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2946,6 +3031,252 @@ static void maxInt64VectorTests(IntFunction fa, IntFunction fb) { assertArraysEquals(r, a, b, Int64VectorTests::max); } + static int UMIN(int a, int b) { + return (int)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "intBinaryOpProvider") + static void UMINInt64VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::UMIN); + } + + @Test(dataProvider = "intBinaryOpMaskProvider") + static void UMINInt64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int64VectorTests::UMIN); + } + + static int UMAX(int a, int b) { + return (int)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "intBinaryOpProvider") + static void UMAXInt64VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::UMAX); + } + + @Test(dataProvider = "intBinaryOpMaskProvider") + static void UMAXInt64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int64VectorTests::UMAX); + } + + static int SADD(int a, int b) { + return (int)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SADDInt64VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::SADD); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SADDInt64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int64VectorTests::SADD); + } + + static int SSUB(int a, int b) { + return (int)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SSUBInt64VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::SSUB); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SSUBInt64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int64VectorTests::SSUB); + } + + static int SUADD(int a, int b) { + return (int)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SUADDInt64VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::SUADD); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SUADDInt64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int64VectorTests::SUADD); + } + + static int SUSUB(int a, int b) { + return (int)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SUSUBInt64VectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::SUSUB); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SUSUBInt64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Int64VectorTests::SUSUB); + } + @Test(dataProvider = "intBinaryOpProvider") static void MINInt64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -4154,7 +4485,7 @@ static void GEInt64VectorTestsMasked(IntFunction fa, IntFunction f } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_LTInt64VectorTests(IntFunction fa, IntFunction fb) { + static void ULTInt64VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4162,7 +4493,7 @@ static void UNSIGNED_LTInt64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4173,7 +4504,7 @@ static void UNSIGNED_LTInt64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTInt64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4185,7 +4516,7 @@ static void UNSIGNED_LTInt64VectorTestsMasked(IntFunction fa, IntFunction for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4196,7 +4527,7 @@ static void UNSIGNED_LTInt64VectorTestsMasked(IntFunction fa, IntFunction } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_GTInt64VectorTests(IntFunction fa, IntFunction fb) { + static void UGTInt64VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4204,7 +4535,7 @@ static void UNSIGNED_GTInt64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4215,7 +4546,7 @@ static void UNSIGNED_GTInt64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTInt64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4227,7 +4558,7 @@ static void UNSIGNED_GTInt64VectorTestsMasked(IntFunction fa, IntFunction for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4238,7 +4569,7 @@ static void UNSIGNED_GTInt64VectorTestsMasked(IntFunction fa, IntFunction } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_LEInt64VectorTests(IntFunction fa, IntFunction fb) { + static void ULEInt64VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4246,7 +4577,7 @@ static void UNSIGNED_LEInt64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4257,7 +4588,7 @@ static void UNSIGNED_LEInt64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEInt64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4269,7 +4600,7 @@ static void UNSIGNED_LEInt64VectorTestsMasked(IntFunction fa, IntFunction for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4280,7 +4611,7 @@ static void UNSIGNED_LEInt64VectorTestsMasked(IntFunction fa, IntFunction } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_GEInt64VectorTests(IntFunction fa, IntFunction fb) { + static void UGEInt64VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4288,7 +4619,7 @@ static void UNSIGNED_GEInt64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4299,7 +4630,7 @@ static void UNSIGNED_GEInt64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEInt64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4311,7 +4642,7 @@ static void UNSIGNED_GEInt64VectorTestsMasked(IntFunction fa, IntFunction for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5779,6 +6110,24 @@ static void SelectFromInt64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "intSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorInt64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] idx = fc.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + IntVector idxv = IntVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "intUnaryOpShuffleMaskProvider") static void SelectFromInt64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index 71d1ce594f909..fc0f6c1c139c1 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.IntVector; @@ -307,6 +308,25 @@ static void assertexpandArraysEquals(int[] r, int[] a, boolean[] m, int vector_l } } + static void assertSelectFromTwoVectorEquals(int[] r, int[] order, int[] a, int[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -938,6 +958,33 @@ static int bits(int e) { }) ); + static final List> INT_SATURATING_GENERATORS = List.of( + withToString("int[Integer.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MIN_VALUE)); + }), + withToString("int[Integer.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MAX_VALUE)); + }), + withToString("int[Integer.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MAX_VALUE - 100)); + }), + withToString("int[Integer.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(Integer.MIN_VALUE + 100)); + }), + withToString("int[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(-i * 5)); + }), + withToString("int[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> INT_GENERATOR_PAIRS = @@ -945,6 +992,11 @@ static int bits(int e) { flatMap(fa -> INT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> INT_SATURATING_GENERATOR_PAIRS = + Stream.of(INT_GENERATORS.get(0)). + flatMap(fa -> INT_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -957,18 +1009,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> INT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("int[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(RAND.nextInt())); + }) + ); + + static final List>> INT_GENERATOR_SELECT_FROM_TRIPLES = + INT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] intBinaryOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] intSaturatingBinaryOpProvider() { + return INT_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intIndexedOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] intSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> INT_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -984,6 +1063,12 @@ public Object[][] intTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] intSelectFromTwoVectorOpProvider() { + return INT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2951,6 +3036,252 @@ static void maxIntMaxVectorTests(IntFunction fa, IntFunction fb) { assertArraysEquals(r, a, b, IntMaxVectorTests::max); } + static int UMIN(int a, int b) { + return (int)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "intBinaryOpProvider") + static void UMINIntMaxVectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::UMIN); + } + + @Test(dataProvider = "intBinaryOpMaskProvider") + static void UMINIntMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, IntMaxVectorTests::UMIN); + } + + static int UMAX(int a, int b) { + return (int)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "intBinaryOpProvider") + static void UMAXIntMaxVectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::UMAX); + } + + @Test(dataProvider = "intBinaryOpMaskProvider") + static void UMAXIntMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, IntMaxVectorTests::UMAX); + } + + static int SADD(int a, int b) { + return (int)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SADDIntMaxVectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::SADD); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SADDIntMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, IntMaxVectorTests::SADD); + } + + static int SSUB(int a, int b) { + return (int)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SSUBIntMaxVectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::SSUB); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SSUBIntMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, IntMaxVectorTests::SSUB); + } + + static int SUADD(int a, int b) { + return (int)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SUADDIntMaxVectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::SUADD); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SUADDIntMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, IntMaxVectorTests::SUADD); + } + + static int SUSUB(int a, int b) { + return (int)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "intSaturatingBinaryOpProvider") + static void SUSUBIntMaxVectorTests(IntFunction fa, IntFunction fb) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::SUSUB); + } + + @Test(dataProvider = "intSaturatingBinaryOpMaskProvider") + static void SUSUBIntMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, IntMaxVectorTests::SUSUB); + } + @Test(dataProvider = "intBinaryOpProvider") static void MINIntMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -4159,7 +4490,7 @@ static void GEIntMaxVectorTestsMasked(IntFunction fa, IntFunction } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_LTIntMaxVectorTests(IntFunction fa, IntFunction fb) { + static void ULTIntMaxVectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4167,7 +4498,7 @@ static void UNSIGNED_LTIntMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4178,7 +4509,7 @@ static void UNSIGNED_LTIntMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTIntMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4190,7 +4521,7 @@ static void UNSIGNED_LTIntMaxVectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4201,7 +4532,7 @@ static void UNSIGNED_LTIntMaxVectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_GTIntMaxVectorTests(IntFunction fa, IntFunction fb) { + static void UGTIntMaxVectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4209,7 +4540,7 @@ static void UNSIGNED_GTIntMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4220,7 +4551,7 @@ static void UNSIGNED_GTIntMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTIntMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4232,7 +4563,7 @@ static void UNSIGNED_GTIntMaxVectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4243,7 +4574,7 @@ static void UNSIGNED_GTIntMaxVectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_LEIntMaxVectorTests(IntFunction fa, IntFunction fb) { + static void ULEIntMaxVectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4251,7 +4582,7 @@ static void UNSIGNED_LEIntMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4262,7 +4593,7 @@ static void UNSIGNED_LEIntMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEIntMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4274,7 +4605,7 @@ static void UNSIGNED_LEIntMaxVectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4285,7 +4616,7 @@ static void UNSIGNED_LEIntMaxVectorTestsMasked(IntFunction fa, IntFunctio } @Test(dataProvider = "intCompareOpProvider") - static void UNSIGNED_GEIntMaxVectorTests(IntFunction fa, IntFunction fb) { + static void UGEIntMaxVectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4293,7 +4624,7 @@ static void UNSIGNED_GEIntMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4304,7 +4635,7 @@ static void UNSIGNED_GEIntMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEIntMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); @@ -4316,7 +4647,7 @@ static void UNSIGNED_GEIntMaxVectorTestsMasked(IntFunction fa, IntFunctio for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); IntVector bv = IntVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5784,6 +6115,24 @@ static void SelectFromIntMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "intSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorIntMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] idx = fc.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + IntVector idxv = IntVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "intUnaryOpShuffleMaskProvider") static void SelectFromIntMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index bcec2dee9fe3c..3694128877adf 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.LongVector; @@ -259,6 +260,25 @@ static void assertexpandArraysEquals(long[] r, long[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(long[] r, long[] order, long[] a, long[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(long[] r, long[] a, long[] order, int vector_len) { int i = 0, j = 0; try { @@ -923,6 +943,33 @@ static long bits(long e) { }) ); + static final List> LONG_SATURATING_GENERATORS = List.of( + withToString("long[Long.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MIN_VALUE)); + }), + withToString("long[Long.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MAX_VALUE)); + }), + withToString("long[Long.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MAX_VALUE - 100)); + }), + withToString("long[Long.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MIN_VALUE + 100)); + }), + withToString("long[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(-i * 5)); + }), + withToString("long[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> LONG_GENERATOR_PAIRS = @@ -930,6 +977,11 @@ static long bits(long e) { flatMap(fa -> LONG_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> LONG_SATURATING_GENERATOR_PAIRS = + Stream.of(LONG_GENERATORS.get(0)). + flatMap(fa -> LONG_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -942,18 +994,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> LONG_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("long[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(RAND.nextInt())); + }) + ); + + static final List>> LONG_GENERATOR_SELECT_FROM_TRIPLES = + LONG_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] longBinaryOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] longSaturatingBinaryOpProvider() { + return LONG_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longIndexedOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] longSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> LONG_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -969,6 +1048,12 @@ public Object[][] longTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] longSelectFromTwoVectorOpProvider() { + return LONG_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2968,6 +3053,252 @@ static void maxLong128VectorTests(IntFunction fa, IntFunction fb assertArraysEquals(r, a, b, Long128VectorTests::max); } + static long UMIN(long a, long b) { + return (long)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "longBinaryOpProvider") + static void UMINLong128VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::UMIN); + } + + @Test(dataProvider = "longBinaryOpMaskProvider") + static void UMINLong128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long128VectorTests::UMIN); + } + + static long UMAX(long a, long b) { + return (long)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "longBinaryOpProvider") + static void UMAXLong128VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::UMAX); + } + + @Test(dataProvider = "longBinaryOpMaskProvider") + static void UMAXLong128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long128VectorTests::UMAX); + } + + static long SADD(long a, long b) { + return (long)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SADDLong128VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::SADD); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SADDLong128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long128VectorTests::SADD); + } + + static long SSUB(long a, long b) { + return (long)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SSUBLong128VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::SSUB); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SSUBLong128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long128VectorTests::SSUB); + } + + static long SUADD(long a, long b) { + return (long)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SUADDLong128VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::SUADD); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SUADDLong128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long128VectorTests::SUADD); + } + + static long SUSUB(long a, long b) { + return (long)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SUSUBLong128VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::SUSUB); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SUSUBLong128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long128VectorTests::SUSUB); + } + @Test(dataProvider = "longBinaryOpProvider") static void MINLong128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -4176,7 +4507,7 @@ static void GELong128VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTLong128VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4184,7 +4515,7 @@ static void UNSIGNED_LTLong128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4195,7 +4526,7 @@ static void UNSIGNED_LTLong128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTLong128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4207,7 +4538,7 @@ static void UNSIGNED_LTLong128VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4218,7 +4549,7 @@ static void UNSIGNED_LTLong128VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_GTLong128VectorTests(IntFunction fa, IntFunction fb) { + static void UGTLong128VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4226,7 +4557,7 @@ static void UNSIGNED_GTLong128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4237,7 +4568,7 @@ static void UNSIGNED_GTLong128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTLong128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4249,7 +4580,7 @@ static void UNSIGNED_GTLong128VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4260,7 +4591,7 @@ static void UNSIGNED_GTLong128VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_LELong128VectorTests(IntFunction fa, IntFunction fb) { + static void ULELong128VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4268,7 +4599,7 @@ static void UNSIGNED_LELong128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4279,7 +4610,7 @@ static void UNSIGNED_LELong128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULELong128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4291,7 +4622,7 @@ static void UNSIGNED_LELong128VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4302,7 +4633,7 @@ static void UNSIGNED_LELong128VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_GELong128VectorTests(IntFunction fa, IntFunction fb) { + static void UGELong128VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4310,7 +4641,7 @@ static void UNSIGNED_GELong128VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4321,7 +4652,7 @@ static void UNSIGNED_GELong128VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGELong128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4333,7 +4664,7 @@ static void UNSIGNED_GELong128VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5665,6 +5996,24 @@ static void SelectFromLong128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "longSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorLong128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] idx = fc.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + LongVector idxv = LongVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "longUnaryOpSelectFromMaskProvider") static void SelectFromLong128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index e8f2fb1301cf8..1fc441680fd51 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.LongVector; @@ -259,6 +260,25 @@ static void assertexpandArraysEquals(long[] r, long[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(long[] r, long[] order, long[] a, long[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(long[] r, long[] a, long[] order, int vector_len) { int i = 0, j = 0; try { @@ -923,6 +943,33 @@ static long bits(long e) { }) ); + static final List> LONG_SATURATING_GENERATORS = List.of( + withToString("long[Long.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MIN_VALUE)); + }), + withToString("long[Long.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MAX_VALUE)); + }), + withToString("long[Long.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MAX_VALUE - 100)); + }), + withToString("long[Long.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MIN_VALUE + 100)); + }), + withToString("long[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(-i * 5)); + }), + withToString("long[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> LONG_GENERATOR_PAIRS = @@ -930,6 +977,11 @@ static long bits(long e) { flatMap(fa -> LONG_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> LONG_SATURATING_GENERATOR_PAIRS = + Stream.of(LONG_GENERATORS.get(0)). + flatMap(fa -> LONG_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -942,18 +994,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> LONG_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("long[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(RAND.nextInt())); + }) + ); + + static final List>> LONG_GENERATOR_SELECT_FROM_TRIPLES = + LONG_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] longBinaryOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] longSaturatingBinaryOpProvider() { + return LONG_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longIndexedOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] longSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> LONG_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -969,6 +1048,12 @@ public Object[][] longTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] longSelectFromTwoVectorOpProvider() { + return LONG_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2968,6 +3053,252 @@ static void maxLong256VectorTests(IntFunction fa, IntFunction fb assertArraysEquals(r, a, b, Long256VectorTests::max); } + static long UMIN(long a, long b) { + return (long)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "longBinaryOpProvider") + static void UMINLong256VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::UMIN); + } + + @Test(dataProvider = "longBinaryOpMaskProvider") + static void UMINLong256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long256VectorTests::UMIN); + } + + static long UMAX(long a, long b) { + return (long)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "longBinaryOpProvider") + static void UMAXLong256VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::UMAX); + } + + @Test(dataProvider = "longBinaryOpMaskProvider") + static void UMAXLong256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long256VectorTests::UMAX); + } + + static long SADD(long a, long b) { + return (long)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SADDLong256VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::SADD); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SADDLong256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long256VectorTests::SADD); + } + + static long SSUB(long a, long b) { + return (long)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SSUBLong256VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::SSUB); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SSUBLong256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long256VectorTests::SSUB); + } + + static long SUADD(long a, long b) { + return (long)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SUADDLong256VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::SUADD); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SUADDLong256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long256VectorTests::SUADD); + } + + static long SUSUB(long a, long b) { + return (long)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SUSUBLong256VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::SUSUB); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SUSUBLong256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long256VectorTests::SUSUB); + } + @Test(dataProvider = "longBinaryOpProvider") static void MINLong256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -4176,7 +4507,7 @@ static void GELong256VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTLong256VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4184,7 +4515,7 @@ static void UNSIGNED_LTLong256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4195,7 +4526,7 @@ static void UNSIGNED_LTLong256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTLong256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4207,7 +4538,7 @@ static void UNSIGNED_LTLong256VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4218,7 +4549,7 @@ static void UNSIGNED_LTLong256VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_GTLong256VectorTests(IntFunction fa, IntFunction fb) { + static void UGTLong256VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4226,7 +4557,7 @@ static void UNSIGNED_GTLong256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4237,7 +4568,7 @@ static void UNSIGNED_GTLong256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTLong256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4249,7 +4580,7 @@ static void UNSIGNED_GTLong256VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4260,7 +4591,7 @@ static void UNSIGNED_GTLong256VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_LELong256VectorTests(IntFunction fa, IntFunction fb) { + static void ULELong256VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4268,7 +4599,7 @@ static void UNSIGNED_LELong256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4279,7 +4610,7 @@ static void UNSIGNED_LELong256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULELong256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4291,7 +4622,7 @@ static void UNSIGNED_LELong256VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4302,7 +4633,7 @@ static void UNSIGNED_LELong256VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_GELong256VectorTests(IntFunction fa, IntFunction fb) { + static void UGELong256VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4310,7 +4641,7 @@ static void UNSIGNED_GELong256VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4321,7 +4652,7 @@ static void UNSIGNED_GELong256VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGELong256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4333,7 +4664,7 @@ static void UNSIGNED_GELong256VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5665,6 +5996,24 @@ static void SelectFromLong256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "longSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorLong256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] idx = fc.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + LongVector idxv = LongVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "longUnaryOpSelectFromMaskProvider") static void SelectFromLong256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 022f1490fcc1e..81d538a55c465 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.LongVector; @@ -259,6 +260,25 @@ static void assertexpandArraysEquals(long[] r, long[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(long[] r, long[] order, long[] a, long[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(long[] r, long[] a, long[] order, int vector_len) { int i = 0, j = 0; try { @@ -923,6 +943,33 @@ static long bits(long e) { }) ); + static final List> LONG_SATURATING_GENERATORS = List.of( + withToString("long[Long.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MIN_VALUE)); + }), + withToString("long[Long.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MAX_VALUE)); + }), + withToString("long[Long.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MAX_VALUE - 100)); + }), + withToString("long[Long.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MIN_VALUE + 100)); + }), + withToString("long[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(-i * 5)); + }), + withToString("long[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> LONG_GENERATOR_PAIRS = @@ -930,6 +977,11 @@ static long bits(long e) { flatMap(fa -> LONG_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> LONG_SATURATING_GENERATOR_PAIRS = + Stream.of(LONG_GENERATORS.get(0)). + flatMap(fa -> LONG_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -942,18 +994,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> LONG_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("long[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(RAND.nextInt())); + }) + ); + + static final List>> LONG_GENERATOR_SELECT_FROM_TRIPLES = + LONG_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] longBinaryOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] longSaturatingBinaryOpProvider() { + return LONG_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longIndexedOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] longSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> LONG_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -969,6 +1048,12 @@ public Object[][] longTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] longSelectFromTwoVectorOpProvider() { + return LONG_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2968,6 +3053,252 @@ static void maxLong512VectorTests(IntFunction fa, IntFunction fb assertArraysEquals(r, a, b, Long512VectorTests::max); } + static long UMIN(long a, long b) { + return (long)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "longBinaryOpProvider") + static void UMINLong512VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::UMIN); + } + + @Test(dataProvider = "longBinaryOpMaskProvider") + static void UMINLong512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long512VectorTests::UMIN); + } + + static long UMAX(long a, long b) { + return (long)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "longBinaryOpProvider") + static void UMAXLong512VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::UMAX); + } + + @Test(dataProvider = "longBinaryOpMaskProvider") + static void UMAXLong512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long512VectorTests::UMAX); + } + + static long SADD(long a, long b) { + return (long)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SADDLong512VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::SADD); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SADDLong512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long512VectorTests::SADD); + } + + static long SSUB(long a, long b) { + return (long)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SSUBLong512VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::SSUB); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SSUBLong512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long512VectorTests::SSUB); + } + + static long SUADD(long a, long b) { + return (long)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SUADDLong512VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::SUADD); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SUADDLong512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long512VectorTests::SUADD); + } + + static long SUSUB(long a, long b) { + return (long)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SUSUBLong512VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::SUSUB); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SUSUBLong512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long512VectorTests::SUSUB); + } + @Test(dataProvider = "longBinaryOpProvider") static void MINLong512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -4176,7 +4507,7 @@ static void GELong512VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTLong512VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4184,7 +4515,7 @@ static void UNSIGNED_LTLong512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4195,7 +4526,7 @@ static void UNSIGNED_LTLong512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTLong512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4207,7 +4538,7 @@ static void UNSIGNED_LTLong512VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4218,7 +4549,7 @@ static void UNSIGNED_LTLong512VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_GTLong512VectorTests(IntFunction fa, IntFunction fb) { + static void UGTLong512VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4226,7 +4557,7 @@ static void UNSIGNED_GTLong512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4237,7 +4568,7 @@ static void UNSIGNED_GTLong512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTLong512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4249,7 +4580,7 @@ static void UNSIGNED_GTLong512VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4260,7 +4591,7 @@ static void UNSIGNED_GTLong512VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_LELong512VectorTests(IntFunction fa, IntFunction fb) { + static void ULELong512VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4268,7 +4599,7 @@ static void UNSIGNED_LELong512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4279,7 +4610,7 @@ static void UNSIGNED_LELong512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULELong512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4291,7 +4622,7 @@ static void UNSIGNED_LELong512VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4302,7 +4633,7 @@ static void UNSIGNED_LELong512VectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_GELong512VectorTests(IntFunction fa, IntFunction fb) { + static void UGELong512VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4310,7 +4641,7 @@ static void UNSIGNED_GELong512VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4321,7 +4652,7 @@ static void UNSIGNED_GELong512VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGELong512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4333,7 +4664,7 @@ static void UNSIGNED_GELong512VectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5665,6 +5996,24 @@ static void SelectFromLong512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "longSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorLong512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] idx = fc.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + LongVector idxv = LongVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "longUnaryOpSelectFromMaskProvider") static void SelectFromLong512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index fe886bf93d870..1d85fc510d91c 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.LongVector; @@ -259,6 +260,25 @@ static void assertexpandArraysEquals(long[] r, long[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(long[] r, long[] order, long[] a, long[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(long[] r, long[] a, long[] order, int vector_len) { int i = 0, j = 0; try { @@ -923,6 +943,33 @@ static long bits(long e) { }) ); + static final List> LONG_SATURATING_GENERATORS = List.of( + withToString("long[Long.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MIN_VALUE)); + }), + withToString("long[Long.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MAX_VALUE)); + }), + withToString("long[Long.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MAX_VALUE - 100)); + }), + withToString("long[Long.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MIN_VALUE + 100)); + }), + withToString("long[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(-i * 5)); + }), + withToString("long[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> LONG_GENERATOR_PAIRS = @@ -930,6 +977,11 @@ static long bits(long e) { flatMap(fa -> LONG_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> LONG_SATURATING_GENERATOR_PAIRS = + Stream.of(LONG_GENERATORS.get(0)). + flatMap(fa -> LONG_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -942,18 +994,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> LONG_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("long[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(RAND.nextInt())); + }) + ); + + static final List>> LONG_GENERATOR_SELECT_FROM_TRIPLES = + LONG_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] longBinaryOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] longSaturatingBinaryOpProvider() { + return LONG_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longIndexedOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] longSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> LONG_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -969,6 +1048,12 @@ public Object[][] longTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] longSelectFromTwoVectorOpProvider() { + return LONG_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2968,6 +3053,252 @@ static void maxLong64VectorTests(IntFunction fa, IntFunction fb) assertArraysEquals(r, a, b, Long64VectorTests::max); } + static long UMIN(long a, long b) { + return (long)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "longBinaryOpProvider") + static void UMINLong64VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::UMIN); + } + + @Test(dataProvider = "longBinaryOpMaskProvider") + static void UMINLong64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long64VectorTests::UMIN); + } + + static long UMAX(long a, long b) { + return (long)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "longBinaryOpProvider") + static void UMAXLong64VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::UMAX); + } + + @Test(dataProvider = "longBinaryOpMaskProvider") + static void UMAXLong64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long64VectorTests::UMAX); + } + + static long SADD(long a, long b) { + return (long)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SADDLong64VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::SADD); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SADDLong64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long64VectorTests::SADD); + } + + static long SSUB(long a, long b) { + return (long)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SSUBLong64VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::SSUB); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SSUBLong64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long64VectorTests::SSUB); + } + + static long SUADD(long a, long b) { + return (long)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SUADDLong64VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::SUADD); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SUADDLong64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long64VectorTests::SUADD); + } + + static long SUSUB(long a, long b) { + return (long)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SUSUBLong64VectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::SUSUB); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SUSUBLong64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Long64VectorTests::SUSUB); + } + @Test(dataProvider = "longBinaryOpProvider") static void MINLong64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -4176,7 +4507,7 @@ static void GELong64VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTLong64VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4184,7 +4515,7 @@ static void UNSIGNED_LTLong64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4195,7 +4526,7 @@ static void UNSIGNED_LTLong64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTLong64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4207,7 +4538,7 @@ static void UNSIGNED_LTLong64VectorTestsMasked(IntFunction fa, IntFuncti for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4218,7 +4549,7 @@ static void UNSIGNED_LTLong64VectorTestsMasked(IntFunction fa, IntFuncti } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_GTLong64VectorTests(IntFunction fa, IntFunction fb) { + static void UGTLong64VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4226,7 +4557,7 @@ static void UNSIGNED_GTLong64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4237,7 +4568,7 @@ static void UNSIGNED_GTLong64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTLong64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4249,7 +4580,7 @@ static void UNSIGNED_GTLong64VectorTestsMasked(IntFunction fa, IntFuncti for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4260,7 +4591,7 @@ static void UNSIGNED_GTLong64VectorTestsMasked(IntFunction fa, IntFuncti } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_LELong64VectorTests(IntFunction fa, IntFunction fb) { + static void ULELong64VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4268,7 +4599,7 @@ static void UNSIGNED_LELong64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4279,7 +4610,7 @@ static void UNSIGNED_LELong64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULELong64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4291,7 +4622,7 @@ static void UNSIGNED_LELong64VectorTestsMasked(IntFunction fa, IntFuncti for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4302,7 +4633,7 @@ static void UNSIGNED_LELong64VectorTestsMasked(IntFunction fa, IntFuncti } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_GELong64VectorTests(IntFunction fa, IntFunction fb) { + static void UGELong64VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4310,7 +4641,7 @@ static void UNSIGNED_GELong64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4321,7 +4652,7 @@ static void UNSIGNED_GELong64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGELong64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4333,7 +4664,7 @@ static void UNSIGNED_GELong64VectorTestsMasked(IntFunction fa, IntFuncti for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5665,6 +5996,24 @@ static void SelectFromLong64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "longSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorLong64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] idx = fc.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + LongVector idxv = LongVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "longUnaryOpSelectFromMaskProvider") static void SelectFromLong64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index b77d6eeb118a8..bae5b968d79a6 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.LongVector; @@ -264,6 +265,25 @@ static void assertexpandArraysEquals(long[] r, long[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(long[] r, long[] order, long[] a, long[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(long[] r, long[] a, long[] order, int vector_len) { int i = 0, j = 0; try { @@ -928,6 +948,33 @@ static long bits(long e) { }) ); + static final List> LONG_SATURATING_GENERATORS = List.of( + withToString("long[Long.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MIN_VALUE)); + }), + withToString("long[Long.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MAX_VALUE)); + }), + withToString("long[Long.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MAX_VALUE - 100)); + }), + withToString("long[Long.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(Long.MIN_VALUE + 100)); + }), + withToString("long[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(-i * 5)); + }), + withToString("long[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> LONG_GENERATOR_PAIRS = @@ -935,6 +982,11 @@ static long bits(long e) { flatMap(fa -> LONG_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> LONG_SATURATING_GENERATOR_PAIRS = + Stream.of(LONG_GENERATORS.get(0)). + flatMap(fa -> LONG_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -947,18 +999,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> LONG_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("long[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(RAND.nextInt())); + }) + ); + + static final List>> LONG_GENERATOR_SELECT_FROM_TRIPLES = + LONG_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] longBinaryOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] longSaturatingBinaryOpProvider() { + return LONG_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longIndexedOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] longSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> LONG_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -974,6 +1053,12 @@ public Object[][] longTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] longSelectFromTwoVectorOpProvider() { + return LONG_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2973,6 +3058,252 @@ static void maxLongMaxVectorTests(IntFunction fa, IntFunction fb assertArraysEquals(r, a, b, LongMaxVectorTests::max); } + static long UMIN(long a, long b) { + return (long)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "longBinaryOpProvider") + static void UMINLongMaxVectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::UMIN); + } + + @Test(dataProvider = "longBinaryOpMaskProvider") + static void UMINLongMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, LongMaxVectorTests::UMIN); + } + + static long UMAX(long a, long b) { + return (long)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "longBinaryOpProvider") + static void UMAXLongMaxVectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::UMAX); + } + + @Test(dataProvider = "longBinaryOpMaskProvider") + static void UMAXLongMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, LongMaxVectorTests::UMAX); + } + + static long SADD(long a, long b) { + return (long)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SADDLongMaxVectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::SADD); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SADDLongMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, LongMaxVectorTests::SADD); + } + + static long SSUB(long a, long b) { + return (long)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SSUBLongMaxVectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::SSUB); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SSUBLongMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, LongMaxVectorTests::SSUB); + } + + static long SUADD(long a, long b) { + return (long)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SUADDLongMaxVectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::SUADD); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SUADDLongMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, LongMaxVectorTests::SUADD); + } + + static long SUSUB(long a, long b) { + return (long)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "longSaturatingBinaryOpProvider") + static void SUSUBLongMaxVectorTests(IntFunction fa, IntFunction fb) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::SUSUB); + } + + @Test(dataProvider = "longSaturatingBinaryOpMaskProvider") + static void SUSUBLongMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, LongMaxVectorTests::SUSUB); + } + @Test(dataProvider = "longBinaryOpProvider") static void MINLongMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -4181,7 +4512,7 @@ static void GELongMaxVectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTLongMaxVectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4189,7 +4520,7 @@ static void UNSIGNED_LTLongMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4200,7 +4531,7 @@ static void UNSIGNED_LTLongMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTLongMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4212,7 +4543,7 @@ static void UNSIGNED_LTLongMaxVectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4223,7 +4554,7 @@ static void UNSIGNED_LTLongMaxVectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_GTLongMaxVectorTests(IntFunction fa, IntFunction fb) { + static void UGTLongMaxVectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4231,7 +4562,7 @@ static void UNSIGNED_GTLongMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4242,7 +4573,7 @@ static void UNSIGNED_GTLongMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTLongMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4254,7 +4585,7 @@ static void UNSIGNED_GTLongMaxVectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4265,7 +4596,7 @@ static void UNSIGNED_GTLongMaxVectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_LELongMaxVectorTests(IntFunction fa, IntFunction fb) { + static void ULELongMaxVectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4273,7 +4604,7 @@ static void UNSIGNED_LELongMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4284,7 +4615,7 @@ static void UNSIGNED_LELongMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULELongMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4296,7 +4627,7 @@ static void UNSIGNED_LELongMaxVectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4307,7 +4638,7 @@ static void UNSIGNED_LELongMaxVectorTestsMasked(IntFunction fa, IntFunct } @Test(dataProvider = "longCompareOpProvider") - static void UNSIGNED_GELongMaxVectorTests(IntFunction fa, IntFunction fb) { + static void UGELongMaxVectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4315,7 +4646,7 @@ static void UNSIGNED_GELongMaxVectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4326,7 +4657,7 @@ static void UNSIGNED_GELongMaxVectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGELongMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); @@ -4338,7 +4669,7 @@ static void UNSIGNED_GELongMaxVectorTestsMasked(IntFunction fa, IntFunct for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); LongVector bv = LongVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5670,6 +6001,24 @@ static void SelectFromLongMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "longSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorLongMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] idx = fc.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + LongVector idxv = LongVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "longUnaryOpSelectFromMaskProvider") static void SelectFromLongMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index 2a82ada044e31..2d6a1fd0a5fdb 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.ShortVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(short[] r, short[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(short[] r, short[] order, short[] a, short[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(short[] r, short[] a, short[] order, int vector_len) { int i = 0, j = 0; try { @@ -933,6 +953,33 @@ static short bits(short e) { }) ); + static final List> SHORT_SATURATING_GENERATORS = List.of( + withToString("short[Short.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MIN_VALUE)); + }), + withToString("short[Short.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MAX_VALUE)); + }), + withToString("short[Short.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MAX_VALUE - 100)); + }), + withToString("short[Short.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MIN_VALUE + 100)); + }), + withToString("short[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(-i * 5)); + }), + withToString("short[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> SHORT_GENERATOR_PAIRS = @@ -940,6 +987,11 @@ static short bits(short e) { flatMap(fa -> SHORT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> SHORT_SATURATING_GENERATOR_PAIRS = + Stream.of(SHORT_GENERATORS.get(0)). + flatMap(fa -> SHORT_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -952,18 +1004,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> SHORT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("short[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(RAND.nextInt())); + }) + ); + + static final List>> SHORT_GENERATOR_SELECT_FROM_TRIPLES = + SHORT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] shortBinaryOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSaturatingBinaryOpProvider() { + return SHORT_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortIndexedOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> SHORT_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -979,6 +1058,12 @@ public Object[][] shortTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSelectFromTwoVectorOpProvider() { + return SHORT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2893,6 +2978,252 @@ static void maxShort128VectorTests(IntFunction fa, IntFunction assertArraysEquals(r, a, b, Short128VectorTests::max); } + static short UMIN(short a, short b) { + return (short)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "shortBinaryOpProvider") + static void UMINShort128VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::UMIN); + } + + @Test(dataProvider = "shortBinaryOpMaskProvider") + static void UMINShort128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short128VectorTests::UMIN); + } + + static short UMAX(short a, short b) { + return (short)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "shortBinaryOpProvider") + static void UMAXShort128VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::UMAX); + } + + @Test(dataProvider = "shortBinaryOpMaskProvider") + static void UMAXShort128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short128VectorTests::UMAX); + } + + static short SADD(short a, short b) { + return (short)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SADDShort128VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::SADD); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SADDShort128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short128VectorTests::SADD); + } + + static short SSUB(short a, short b) { + return (short)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SSUBShort128VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::SSUB); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SSUBShort128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short128VectorTests::SSUB); + } + + static short SUADD(short a, short b) { + return (short)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SUADDShort128VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::SUADD); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SUADDShort128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short128VectorTests::SUADD); + } + + static short SUSUB(short a, short b) { + return (short)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SUSUBShort128VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::SUSUB); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SUSUBShort128VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short128VectorTests::SUSUB); + } + @Test(dataProvider = "shortBinaryOpProvider") static void MINShort128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -4101,7 +4432,7 @@ static void GEShort128VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTShort128VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4109,7 +4440,7 @@ static void UNSIGNED_LTShort128VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4120,7 +4451,7 @@ static void UNSIGNED_LTShort128VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_LTShort128VectorTestsMasked(IntFunction fa, IntFunction fb, + static void ULTShort128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4132,7 +4463,7 @@ static void UNSIGNED_LTShort128VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4143,7 +4474,7 @@ static void UNSIGNED_LTShort128VectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_GTShort128VectorTests(IntFunction fa, IntFunction fb) { + static void UGTShort128VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4151,7 +4482,7 @@ static void UNSIGNED_GTShort128VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4162,7 +4493,7 @@ static void UNSIGNED_GTShort128VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_GTShort128VectorTestsMasked(IntFunction fa, IntFunction fb, + static void UGTShort128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4174,7 +4505,7 @@ static void UNSIGNED_GTShort128VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4185,7 +4516,7 @@ static void UNSIGNED_GTShort128VectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_LEShort128VectorTests(IntFunction fa, IntFunction fb) { + static void ULEShort128VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4193,7 +4524,7 @@ static void UNSIGNED_LEShort128VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4204,7 +4535,7 @@ static void UNSIGNED_LEShort128VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_LEShort128VectorTestsMasked(IntFunction fa, IntFunction fb, + static void ULEShort128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4216,7 +4547,7 @@ static void UNSIGNED_LEShort128VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4227,7 +4558,7 @@ static void UNSIGNED_LEShort128VectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_GEShort128VectorTests(IntFunction fa, IntFunction fb) { + static void UGEShort128VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4235,7 +4566,7 @@ static void UNSIGNED_GEShort128VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4246,7 +4577,7 @@ static void UNSIGNED_GEShort128VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_GEShort128VectorTestsMasked(IntFunction fa, IntFunction fb, + static void UGEShort128VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4258,7 +4589,7 @@ static void UNSIGNED_GEShort128VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5726,6 +6057,24 @@ static void SelectFromShort128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "shortSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorShort128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] idx = fc.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + ShortVector idxv = ShortVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "shortUnaryOpSelectFromMaskProvider") static void SelectFromShort128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index 69a8432acef3c..fa8ec1f31b6bc 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.ShortVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(short[] r, short[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(short[] r, short[] order, short[] a, short[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(short[] r, short[] a, short[] order, int vector_len) { int i = 0, j = 0; try { @@ -933,6 +953,33 @@ static short bits(short e) { }) ); + static final List> SHORT_SATURATING_GENERATORS = List.of( + withToString("short[Short.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MIN_VALUE)); + }), + withToString("short[Short.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MAX_VALUE)); + }), + withToString("short[Short.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MAX_VALUE - 100)); + }), + withToString("short[Short.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MIN_VALUE + 100)); + }), + withToString("short[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(-i * 5)); + }), + withToString("short[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> SHORT_GENERATOR_PAIRS = @@ -940,6 +987,11 @@ static short bits(short e) { flatMap(fa -> SHORT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> SHORT_SATURATING_GENERATOR_PAIRS = + Stream.of(SHORT_GENERATORS.get(0)). + flatMap(fa -> SHORT_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -952,18 +1004,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> SHORT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("short[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(RAND.nextInt())); + }) + ); + + static final List>> SHORT_GENERATOR_SELECT_FROM_TRIPLES = + SHORT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] shortBinaryOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSaturatingBinaryOpProvider() { + return SHORT_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortIndexedOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> SHORT_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -979,6 +1058,12 @@ public Object[][] shortTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSelectFromTwoVectorOpProvider() { + return SHORT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2893,6 +2978,252 @@ static void maxShort256VectorTests(IntFunction fa, IntFunction assertArraysEquals(r, a, b, Short256VectorTests::max); } + static short UMIN(short a, short b) { + return (short)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "shortBinaryOpProvider") + static void UMINShort256VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::UMIN); + } + + @Test(dataProvider = "shortBinaryOpMaskProvider") + static void UMINShort256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short256VectorTests::UMIN); + } + + static short UMAX(short a, short b) { + return (short)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "shortBinaryOpProvider") + static void UMAXShort256VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::UMAX); + } + + @Test(dataProvider = "shortBinaryOpMaskProvider") + static void UMAXShort256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short256VectorTests::UMAX); + } + + static short SADD(short a, short b) { + return (short)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SADDShort256VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::SADD); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SADDShort256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short256VectorTests::SADD); + } + + static short SSUB(short a, short b) { + return (short)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SSUBShort256VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::SSUB); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SSUBShort256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short256VectorTests::SSUB); + } + + static short SUADD(short a, short b) { + return (short)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SUADDShort256VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::SUADD); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SUADDShort256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short256VectorTests::SUADD); + } + + static short SUSUB(short a, short b) { + return (short)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SUSUBShort256VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::SUSUB); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SUSUBShort256VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short256VectorTests::SUSUB); + } + @Test(dataProvider = "shortBinaryOpProvider") static void MINShort256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -4101,7 +4432,7 @@ static void GEShort256VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTShort256VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4109,7 +4440,7 @@ static void UNSIGNED_LTShort256VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4120,7 +4451,7 @@ static void UNSIGNED_LTShort256VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_LTShort256VectorTestsMasked(IntFunction fa, IntFunction fb, + static void ULTShort256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4132,7 +4463,7 @@ static void UNSIGNED_LTShort256VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4143,7 +4474,7 @@ static void UNSIGNED_LTShort256VectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_GTShort256VectorTests(IntFunction fa, IntFunction fb) { + static void UGTShort256VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4151,7 +4482,7 @@ static void UNSIGNED_GTShort256VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4162,7 +4493,7 @@ static void UNSIGNED_GTShort256VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_GTShort256VectorTestsMasked(IntFunction fa, IntFunction fb, + static void UGTShort256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4174,7 +4505,7 @@ static void UNSIGNED_GTShort256VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4185,7 +4516,7 @@ static void UNSIGNED_GTShort256VectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_LEShort256VectorTests(IntFunction fa, IntFunction fb) { + static void ULEShort256VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4193,7 +4524,7 @@ static void UNSIGNED_LEShort256VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4204,7 +4535,7 @@ static void UNSIGNED_LEShort256VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_LEShort256VectorTestsMasked(IntFunction fa, IntFunction fb, + static void ULEShort256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4216,7 +4547,7 @@ static void UNSIGNED_LEShort256VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4227,7 +4558,7 @@ static void UNSIGNED_LEShort256VectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_GEShort256VectorTests(IntFunction fa, IntFunction fb) { + static void UGEShort256VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4235,7 +4566,7 @@ static void UNSIGNED_GEShort256VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4246,7 +4577,7 @@ static void UNSIGNED_GEShort256VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_GEShort256VectorTestsMasked(IntFunction fa, IntFunction fb, + static void UGEShort256VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4258,7 +4589,7 @@ static void UNSIGNED_GEShort256VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5726,6 +6057,24 @@ static void SelectFromShort256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "shortSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorShort256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] idx = fc.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + ShortVector idxv = ShortVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "shortUnaryOpSelectFromMaskProvider") static void SelectFromShort256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index 8e892a8a48e69..ba6a7dadebd08 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.ShortVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(short[] r, short[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(short[] r, short[] order, short[] a, short[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(short[] r, short[] a, short[] order, int vector_len) { int i = 0, j = 0; try { @@ -933,6 +953,33 @@ static short bits(short e) { }) ); + static final List> SHORT_SATURATING_GENERATORS = List.of( + withToString("short[Short.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MIN_VALUE)); + }), + withToString("short[Short.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MAX_VALUE)); + }), + withToString("short[Short.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MAX_VALUE - 100)); + }), + withToString("short[Short.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MIN_VALUE + 100)); + }), + withToString("short[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(-i * 5)); + }), + withToString("short[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> SHORT_GENERATOR_PAIRS = @@ -940,6 +987,11 @@ static short bits(short e) { flatMap(fa -> SHORT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> SHORT_SATURATING_GENERATOR_PAIRS = + Stream.of(SHORT_GENERATORS.get(0)). + flatMap(fa -> SHORT_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -952,18 +1004,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> SHORT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("short[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(RAND.nextInt())); + }) + ); + + static final List>> SHORT_GENERATOR_SELECT_FROM_TRIPLES = + SHORT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] shortBinaryOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSaturatingBinaryOpProvider() { + return SHORT_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortIndexedOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> SHORT_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -979,6 +1058,12 @@ public Object[][] shortTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSelectFromTwoVectorOpProvider() { + return SHORT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2893,6 +2978,252 @@ static void maxShort512VectorTests(IntFunction fa, IntFunction assertArraysEquals(r, a, b, Short512VectorTests::max); } + static short UMIN(short a, short b) { + return (short)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "shortBinaryOpProvider") + static void UMINShort512VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::UMIN); + } + + @Test(dataProvider = "shortBinaryOpMaskProvider") + static void UMINShort512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short512VectorTests::UMIN); + } + + static short UMAX(short a, short b) { + return (short)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "shortBinaryOpProvider") + static void UMAXShort512VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::UMAX); + } + + @Test(dataProvider = "shortBinaryOpMaskProvider") + static void UMAXShort512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short512VectorTests::UMAX); + } + + static short SADD(short a, short b) { + return (short)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SADDShort512VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::SADD); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SADDShort512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short512VectorTests::SADD); + } + + static short SSUB(short a, short b) { + return (short)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SSUBShort512VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::SSUB); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SSUBShort512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short512VectorTests::SSUB); + } + + static short SUADD(short a, short b) { + return (short)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SUADDShort512VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::SUADD); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SUADDShort512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short512VectorTests::SUADD); + } + + static short SUSUB(short a, short b) { + return (short)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SUSUBShort512VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::SUSUB); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SUSUBShort512VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short512VectorTests::SUSUB); + } + @Test(dataProvider = "shortBinaryOpProvider") static void MINShort512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -4101,7 +4432,7 @@ static void GEShort512VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTShort512VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4109,7 +4440,7 @@ static void UNSIGNED_LTShort512VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4120,7 +4451,7 @@ static void UNSIGNED_LTShort512VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_LTShort512VectorTestsMasked(IntFunction fa, IntFunction fb, + static void ULTShort512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4132,7 +4463,7 @@ static void UNSIGNED_LTShort512VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4143,7 +4474,7 @@ static void UNSIGNED_LTShort512VectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_GTShort512VectorTests(IntFunction fa, IntFunction fb) { + static void UGTShort512VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4151,7 +4482,7 @@ static void UNSIGNED_GTShort512VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4162,7 +4493,7 @@ static void UNSIGNED_GTShort512VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_GTShort512VectorTestsMasked(IntFunction fa, IntFunction fb, + static void UGTShort512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4174,7 +4505,7 @@ static void UNSIGNED_GTShort512VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4185,7 +4516,7 @@ static void UNSIGNED_GTShort512VectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_LEShort512VectorTests(IntFunction fa, IntFunction fb) { + static void ULEShort512VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4193,7 +4524,7 @@ static void UNSIGNED_LEShort512VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4204,7 +4535,7 @@ static void UNSIGNED_LEShort512VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_LEShort512VectorTestsMasked(IntFunction fa, IntFunction fb, + static void ULEShort512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4216,7 +4547,7 @@ static void UNSIGNED_LEShort512VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4227,7 +4558,7 @@ static void UNSIGNED_LEShort512VectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_GEShort512VectorTests(IntFunction fa, IntFunction fb) { + static void UGEShort512VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4235,7 +4566,7 @@ static void UNSIGNED_GEShort512VectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4246,7 +4577,7 @@ static void UNSIGNED_GEShort512VectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_GEShort512VectorTestsMasked(IntFunction fa, IntFunction fb, + static void UGEShort512VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4258,7 +4589,7 @@ static void UNSIGNED_GEShort512VectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5726,6 +6057,24 @@ static void SelectFromShort512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "shortSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorShort512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] idx = fc.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + ShortVector idxv = ShortVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "shortUnaryOpSelectFromMaskProvider") static void SelectFromShort512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index 97658d4257dfd..939da11d53a48 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.ShortVector; @@ -302,6 +303,25 @@ static void assertexpandArraysEquals(short[] r, short[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(short[] r, short[] order, short[] a, short[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(short[] r, short[] a, short[] order, int vector_len) { int i = 0, j = 0; try { @@ -933,6 +953,33 @@ static short bits(short e) { }) ); + static final List> SHORT_SATURATING_GENERATORS = List.of( + withToString("short[Short.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MIN_VALUE)); + }), + withToString("short[Short.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MAX_VALUE)); + }), + withToString("short[Short.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MAX_VALUE - 100)); + }), + withToString("short[Short.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MIN_VALUE + 100)); + }), + withToString("short[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(-i * 5)); + }), + withToString("short[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> SHORT_GENERATOR_PAIRS = @@ -940,6 +987,11 @@ static short bits(short e) { flatMap(fa -> SHORT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> SHORT_SATURATING_GENERATOR_PAIRS = + Stream.of(SHORT_GENERATORS.get(0)). + flatMap(fa -> SHORT_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -952,18 +1004,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> SHORT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("short[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(RAND.nextInt())); + }) + ); + + static final List>> SHORT_GENERATOR_SELECT_FROM_TRIPLES = + SHORT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] shortBinaryOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSaturatingBinaryOpProvider() { + return SHORT_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortIndexedOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> SHORT_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -979,6 +1058,12 @@ public Object[][] shortTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSelectFromTwoVectorOpProvider() { + return SHORT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2893,6 +2978,252 @@ static void maxShort64VectorTests(IntFunction fa, IntFunction assertArraysEquals(r, a, b, Short64VectorTests::max); } + static short UMIN(short a, short b) { + return (short)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "shortBinaryOpProvider") + static void UMINShort64VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::UMIN); + } + + @Test(dataProvider = "shortBinaryOpMaskProvider") + static void UMINShort64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short64VectorTests::UMIN); + } + + static short UMAX(short a, short b) { + return (short)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "shortBinaryOpProvider") + static void UMAXShort64VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::UMAX); + } + + @Test(dataProvider = "shortBinaryOpMaskProvider") + static void UMAXShort64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short64VectorTests::UMAX); + } + + static short SADD(short a, short b) { + return (short)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SADDShort64VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::SADD); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SADDShort64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short64VectorTests::SADD); + } + + static short SSUB(short a, short b) { + return (short)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SSUBShort64VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::SSUB); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SSUBShort64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short64VectorTests::SSUB); + } + + static short SUADD(short a, short b) { + return (short)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SUADDShort64VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::SUADD); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SUADDShort64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short64VectorTests::SUADD); + } + + static short SUSUB(short a, short b) { + return (short)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SUSUBShort64VectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::SUSUB); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SUSUBShort64VectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, Short64VectorTests::SUSUB); + } + @Test(dataProvider = "shortBinaryOpProvider") static void MINShort64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -4101,7 +4432,7 @@ static void GEShort64VectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTShort64VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4109,7 +4440,7 @@ static void UNSIGNED_LTShort64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4120,7 +4451,7 @@ static void UNSIGNED_LTShort64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULTShort64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4132,7 +4463,7 @@ static void UNSIGNED_LTShort64VectorTestsMasked(IntFunction fa, IntFunc for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4143,7 +4474,7 @@ static void UNSIGNED_LTShort64VectorTestsMasked(IntFunction fa, IntFunc } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_GTShort64VectorTests(IntFunction fa, IntFunction fb) { + static void UGTShort64VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4151,7 +4482,7 @@ static void UNSIGNED_GTShort64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4162,7 +4493,7 @@ static void UNSIGNED_GTShort64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGTShort64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4174,7 +4505,7 @@ static void UNSIGNED_GTShort64VectorTestsMasked(IntFunction fa, IntFunc for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4185,7 +4516,7 @@ static void UNSIGNED_GTShort64VectorTestsMasked(IntFunction fa, IntFunc } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_LEShort64VectorTests(IntFunction fa, IntFunction fb) { + static void ULEShort64VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4193,7 +4524,7 @@ static void UNSIGNED_LEShort64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4204,7 +4535,7 @@ static void UNSIGNED_LEShort64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void ULEShort64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4216,7 +4547,7 @@ static void UNSIGNED_LEShort64VectorTestsMasked(IntFunction fa, IntFunc for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4227,7 +4558,7 @@ static void UNSIGNED_LEShort64VectorTestsMasked(IntFunction fa, IntFunc } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_GEShort64VectorTests(IntFunction fa, IntFunction fb) { + static void UGEShort64VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4235,7 +4566,7 @@ static void UNSIGNED_GEShort64VectorTests(IntFunction fa, IntFunction mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4246,7 +4577,7 @@ static void UNSIGNED_GEShort64VectorTests(IntFunction fa, IntFunction fa, IntFunction fb, + static void UGEShort64VectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4258,7 +4589,7 @@ static void UNSIGNED_GEShort64VectorTestsMasked(IntFunction fa, IntFunc for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5726,6 +6057,24 @@ static void SelectFromShort64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "shortSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorShort64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] idx = fc.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + ShortVector idxv = ShortVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "shortUnaryOpSelectFromMaskProvider") static void SelectFromShort64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index 0857c13ef3c43..ade78e1f3f5ba 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -38,6 +38,7 @@ import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMath; import jdk.incubator.vector.ShortVector; @@ -307,6 +308,25 @@ static void assertexpandArraysEquals(short[] r, short[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(short[] r, short[] order, short[] a, short[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(short[] r, short[] a, short[] order, int vector_len) { int i = 0, j = 0; try { @@ -938,6 +958,33 @@ static short bits(short e) { }) ); + static final List> SHORT_SATURATING_GENERATORS = List.of( + withToString("short[Short.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MIN_VALUE)); + }), + withToString("short[Short.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MAX_VALUE)); + }), + withToString("short[Short.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MAX_VALUE - 100)); + }), + withToString("short[Short.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(Short.MIN_VALUE + 100)); + }), + withToString("short[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(-i * 5)); + }), + withToString("short[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(i * 5)); + }) + ); + // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> SHORT_GENERATOR_PAIRS = @@ -945,6 +992,11 @@ static short bits(short e) { flatMap(fa -> SHORT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + static final List>> SHORT_SATURATING_GENERATOR_PAIRS = + Stream.of(SHORT_GENERATORS.get(0)). + flatMap(fa -> SHORT_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -957,18 +1009,45 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> SHORT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("short[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(RAND.nextInt())); + }) + ); + + static final List>> SHORT_GENERATOR_SELECT_FROM_TRIPLES = + SHORT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] shortBinaryOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSaturatingBinaryOpProvider() { + return SHORT_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortIndexedOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> SHORT_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortBinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -984,6 +1063,12 @@ public Object[][] shortTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSelectFromTwoVectorOpProvider() { + return SHORT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -2898,6 +2983,252 @@ static void maxShortMaxVectorTests(IntFunction fa, IntFunction assertArraysEquals(r, a, b, ShortMaxVectorTests::max); } + static short UMIN(short a, short b) { + return (short)(VectorMath.minUnsigned(a, b)); + } + + @Test(dataProvider = "shortBinaryOpProvider") + static void UMINShortMaxVectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::UMIN); + } + + @Test(dataProvider = "shortBinaryOpMaskProvider") + static void UMINShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMIN, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ShortMaxVectorTests::UMIN); + } + + static short UMAX(short a, short b) { + return (short)(VectorMath.maxUnsigned(a, b)); + } + + @Test(dataProvider = "shortBinaryOpProvider") + static void UMAXShortMaxVectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::UMAX); + } + + @Test(dataProvider = "shortBinaryOpMaskProvider") + static void UMAXShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.UMAX, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ShortMaxVectorTests::UMAX); + } + + static short SADD(short a, short b) { + return (short)(VectorMath.addSaturating(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SADDShortMaxVectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::SADD); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SADDShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ShortMaxVectorTests::SADD); + } + + static short SSUB(short a, short b) { + return (short)(VectorMath.subSaturating(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SSUBShortMaxVectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::SSUB); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SSUBShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ShortMaxVectorTests::SSUB); + } + + static short SUADD(short a, short b) { + return (short)(VectorMath.addSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SUADDShortMaxVectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::SUADD); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SUADDShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUADD, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ShortMaxVectorTests::SUADD); + } + + static short SUSUB(short a, short b) { + return (short)(VectorMath.subSaturatingUnsigned(a, b)); + } + + @Test(dataProvider = "shortSaturatingBinaryOpProvider") + static void SUSUBShortMaxVectorTests(IntFunction fa, IntFunction fb) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::SUSUB); + } + + @Test(dataProvider = "shortSaturatingBinaryOpMaskProvider") + static void SUSUBShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.SUSUB, bv, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, mask, ShortMaxVectorTests::SUSUB); + } + @Test(dataProvider = "shortBinaryOpProvider") static void MINShortMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -4106,7 +4437,7 @@ static void GEShortMaxVectorTestsMasked(IntFunction fa, IntFunction fa, IntFunction fb) { + static void ULTShortMaxVectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4114,7 +4445,7 @@ static void UNSIGNED_LTShortMaxVectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv); + VectorMask mv = av.compare(VectorOperators.ULT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4125,7 +4456,7 @@ static void UNSIGNED_LTShortMaxVectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_LTShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + static void ULTShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4137,7 +4468,7 @@ static void UNSIGNED_LTShortMaxVectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4148,7 +4479,7 @@ static void UNSIGNED_LTShortMaxVectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_GTShortMaxVectorTests(IntFunction fa, IntFunction fb) { + static void UGTShortMaxVectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4156,7 +4487,7 @@ static void UNSIGNED_GTShortMaxVectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv); + VectorMask mv = av.compare(VectorOperators.UGT, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4167,7 +4498,7 @@ static void UNSIGNED_GTShortMaxVectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_GTShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + static void UGTShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4179,7 +4510,7 @@ static void UNSIGNED_GTShortMaxVectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GT, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGT, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4190,7 +4521,7 @@ static void UNSIGNED_GTShortMaxVectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_LEShortMaxVectorTests(IntFunction fa, IntFunction fb) { + static void ULEShortMaxVectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4198,7 +4529,7 @@ static void UNSIGNED_LEShortMaxVectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv); + VectorMask mv = av.compare(VectorOperators.ULE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4209,7 +4540,7 @@ static void UNSIGNED_LEShortMaxVectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_LEShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + static void ULEShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4221,7 +4552,7 @@ static void UNSIGNED_LEShortMaxVectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_LE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.ULE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4232,7 +4563,7 @@ static void UNSIGNED_LEShortMaxVectorTestsMasked(IntFunction fa, IntFun } @Test(dataProvider = "shortCompareOpProvider") - static void UNSIGNED_GEShortMaxVectorTests(IntFunction fa, IntFunction fb) { + static void UGEShortMaxVectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4240,7 +4571,7 @@ static void UNSIGNED_GEShortMaxVectorTests(IntFunction fa, IntFunction< for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv); + VectorMask mv = av.compare(VectorOperators.UGE, bv); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -4251,7 +4582,7 @@ static void UNSIGNED_GEShortMaxVectorTests(IntFunction fa, IntFunction< } @Test(dataProvider = "shortCompareOpMaskProvider") - static void UNSIGNED_GEShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, + static void UGEShortMaxVectorTestsMasked(IntFunction fa, IntFunction fb, IntFunction fm) { short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); @@ -4263,7 +4594,7 @@ static void UNSIGNED_GEShortMaxVectorTestsMasked(IntFunction fa, IntFun for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); ShortVector bv = ShortVector.fromArray(SPECIES, b, i); - VectorMask mv = av.compare(VectorOperators.UNSIGNED_GE, bv, vmask); + VectorMask mv = av.compare(VectorOperators.UGE, bv, vmask); // Check results as part of computation. for (int j = 0; j < SPECIES.length(); j++) { @@ -5731,6 +6062,24 @@ static void SelectFromShortMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "shortSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorShortMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] idx = fc.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + ShortVector idxv = ShortVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "shortUnaryOpSelectFromMaskProvider") static void SelectFromShortMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/VectorMathTest.java b/test/jdk/jdk/incubator/vector/VectorMathTest.java new file mode 100644 index 0000000000000..366b9acde5908 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/VectorMathTest.java @@ -0,0 +1,245 @@ +/* + * 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 8338021 + * @summary Test unsigned and saturating scalar operators for use with Vector API + * @modules jdk.incubator.vector + * @run testng VectorMathTest + */ + +import jdk.incubator.vector.VectorMath; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.lang.reflect.Array; +import java.util.function.BinaryOperator; + +public class VectorMathTest { + // @formatter:off + public static final byte ZERO_B = (byte)0; + public static final short ZERO_S = (short)0; + public static final int ZERO_I = 0; + public static final long ZERO_L = 0L; + + public static final byte TEN_B = (byte)10; + public static final int TEN_S = (short)10; + public static final short TEN_I = 10; + public static final long TEN_L = 10L; + + public static final byte FIFTY_B = (byte)50; + public static final int FIFTY_S = (short)50; + public static final short FIFTY_I = 50; + public static final long FIFTY_L = 50L; + + public static final byte SIXTY_B = (byte)60; + public static final int SIXTY_S = (short)60; + public static final short SIXTY_I = 60; + public static final long SIXTY_L = 60L; + + public static final byte UMAX_B = (byte)-1; + public static final short UMAX_S = (short)-1; + public static final int UMAX_I = -1; + public static final long UMAX_L = -1L; + + public static byte[] INPUT_SB = {Byte.MIN_VALUE, (byte)(Byte.MIN_VALUE + TEN_B), ZERO_B, (byte)(Byte.MAX_VALUE - TEN_B), Byte.MAX_VALUE}; + public static short[] INPUT_SS = {Short.MIN_VALUE, (short)(Short.MIN_VALUE + TEN_S), ZERO_S, (short)(Short.MAX_VALUE - TEN_S), Short.MAX_VALUE}; + public static int[] INPUT_SI = {Integer.MIN_VALUE, (Integer.MIN_VALUE + TEN_I), ZERO_I, Integer.MAX_VALUE - TEN_I, Integer.MAX_VALUE}; + public static long[] INPUT_SL = {Long.MIN_VALUE, Long.MIN_VALUE + TEN_L, ZERO_L, Long.MAX_VALUE - TEN_L, Long.MAX_VALUE}; + + public static int[] INPUT_SADD_I = {-FIFTY_I, -FIFTY_I, -FIFTY_I, FIFTY_I, FIFTY_I}; + public static byte[] EXPECTED_SADD_B = {Byte.MIN_VALUE, Byte.MIN_VALUE, -FIFTY_B, Byte.MAX_VALUE, Byte.MAX_VALUE}; + public static short[] EXPECTED_SADD_S = {Short.MIN_VALUE, Short.MIN_VALUE, -FIFTY_S, Short.MAX_VALUE, Short.MAX_VALUE}; + public static int[] EXPECTED_SADD_I = {Integer.MIN_VALUE, Integer.MIN_VALUE, -FIFTY_I, Integer.MAX_VALUE, Integer.MAX_VALUE}; + public static long[] EXPECTED_SADD_L = {Long.MIN_VALUE, Long.MIN_VALUE, -FIFTY_L, Long.MAX_VALUE, Long.MAX_VALUE}; + + public static int[] INPUT_SSUB_I = {FIFTY_I, FIFTY_I, FIFTY_I, -FIFTY_I, -FIFTY_I}; + public static byte[] EXPECTED_SSUB_B = {Byte.MIN_VALUE, Byte.MIN_VALUE, -FIFTY_B, Byte.MAX_VALUE, Byte.MAX_VALUE}; + public static short[] EXPECTED_SSUB_S = {Short.MIN_VALUE, Short.MIN_VALUE, -FIFTY_S, Short.MAX_VALUE, Short.MAX_VALUE}; + public static int[] EXPECTED_SSUB_I = {Integer.MIN_VALUE, Integer.MIN_VALUE, -FIFTY_I, Integer.MAX_VALUE, Integer.MAX_VALUE}; + public static long[] EXPECTED_SSUB_L = {Long.MIN_VALUE, Long.MIN_VALUE, -FIFTY_L, Long.MAX_VALUE, Long.MAX_VALUE}; + + public static byte[] INPUT_UB = {ZERO_B, (byte)(ZERO_B + TEN_B), (byte)(UMAX_B - TEN_B), UMAX_B}; + public static short[] INPUT_US = {ZERO_S, (short)(ZERO_S + TEN_S), (short)(UMAX_S - TEN_S), UMAX_S}; + public static int[] INPUT_UI = {ZERO_I, ZERO_I + TEN_I, UMAX_I - TEN_I, UMAX_I}; + public static long[] INPUT_UL = {ZERO_L, ZERO_L + TEN_L, UMAX_L - TEN_L, UMAX_L}; + + public static int[] INPUT_SUADD_I = {FIFTY_I, FIFTY_I, FIFTY_I, FIFTY_I}; + public static byte[] EXPECTED_SUADD_B = {FIFTY_B, SIXTY_B, UMAX_B, UMAX_B}; + public static short[] EXPECTED_SUADD_S = {FIFTY_S, SIXTY_S, UMAX_S, UMAX_S}; + public static int[] EXPECTED_SUADD_I = {FIFTY_I, SIXTY_I, UMAX_I, UMAX_I}; + public static long[] EXPECTED_SUADD_L = {FIFTY_L, SIXTY_L, UMAX_L, UMAX_L}; + + public static int[] INPUT_SUSUB_I = {FIFTY_I, FIFTY_I, FIFTY_I, FIFTY_I}; + public static byte[] EXPECTED_SUSUB_B = {ZERO_B, ZERO_B, UMAX_B - SIXTY_B, UMAX_B - FIFTY_B}; + public static short[] EXPECTED_SUSUB_S = {ZERO_S, ZERO_S, UMAX_S - SIXTY_S, UMAX_S - FIFTY_S}; + public static int[] EXPECTED_SUSUB_I = {ZERO_I, ZERO_I, UMAX_I - SIXTY_I, UMAX_I - FIFTY_I}; + public static long[] EXPECTED_SUSUB_L = {ZERO_L, ZERO_L, UMAX_L - SIXTY_L, UMAX_L - FIFTY_L}; + + public static byte[] EXPECTED_UMIN_B = {ZERO_B, TEN_B, ZERO_B, Byte.MAX_VALUE - TEN_B}; + public static short[] EXPECTED_UMIN_S = {ZERO_S, TEN_S, ZERO_S, Short.MAX_VALUE - TEN_S}; + public static int[] EXPECTED_UMIN_I = {ZERO_I, TEN_I, ZERO_I, Integer.MAX_VALUE - TEN_I}; + public static long[] EXPECTED_UMIN_L = {ZERO_L, TEN_L, ZERO_L, Long.MAX_VALUE - TEN_L}; + + public static byte[] EXPECTED_UMAX_B = {Byte.MIN_VALUE, (byte)(Byte.MIN_VALUE + TEN_B), (byte)(UMAX_B - TEN_B), UMAX_B}; + public static short[] EXPECTED_UMAX_S = {Short.MIN_VALUE, (short)(Short.MIN_VALUE + TEN_S), (short)(UMAX_S - TEN_S), UMAX_S}; + public static int[] EXPECTED_UMAX_I = {Integer.MIN_VALUE, Integer.MIN_VALUE + TEN_I, (UMAX_I - TEN_I), UMAX_I}; + public static long[] EXPECTED_UMAX_L = {Long.MIN_VALUE, Long.MIN_VALUE + TEN_L, (UMAX_L - TEN_L), UMAX_L}; + // @formatter:on + + static Object conv(Object a, Class ct) { + Object na = Array.newInstance(ct, Array.getLength(a)); + for (int i = 0; i < Array.getLength(a); i++) { + Number number = (Number) Array.get(a, i); + if (ct == byte.class) { + number = number.byteValue(); + } else if (ct == short.class) { + number = number.shortValue(); + } else if (ct == int.class) { + number = number.intValue(); + } else if (ct == long.class) { + number = number.longValue(); + } else { + assert false : "should not reach here"; + } + Array.set(na, i, number); + } + return na; + } + + static BinaryOperator named(String name, BinaryOperator op) { + return new BinaryOperator() { + @Override + public T apply(T a, T b) { + return op.apply(a, b); + } + + public String toString() { + return name; + } + }; + } + + static final BinaryOperator OP_UMIN = named("minUnsigned", + (a, b) -> switch (a) { + case Byte _ -> VectorMath.minUnsigned((byte) a, (byte) b); + case Short _ -> VectorMath.minUnsigned((short) a, (short) b); + case Integer _ -> VectorMath.minUnsigned((int) a, (int) b); + case Long _ -> VectorMath.minUnsigned((long) a, (long) b); + default -> throw new UnsupportedOperationException("should not reach here"); + }); + + static final BinaryOperator OP_UMAX = named("maxUnsigned", + (a, b) -> switch (a) { + case Byte _ -> VectorMath.maxUnsigned((byte) a, (byte) b); + case Short _ -> VectorMath.maxUnsigned((short) a, (short) b); + case Integer _ -> VectorMath.maxUnsigned((int) a, (int) b); + case Long _ -> VectorMath.maxUnsigned((long) a, (long) b); + default -> throw new UnsupportedOperationException("should not reach here"); + }); + + static final BinaryOperator OP_SADD = named("addSaturating", + (a, b) -> switch (a) { + case Byte _ -> VectorMath.addSaturating((byte) a, (byte) b); + case Short _ -> VectorMath.addSaturating((short) a, (short) b); + case Integer _ -> VectorMath.addSaturating((int) a, (int) b); + case Long _ -> VectorMath.addSaturating((long) a, (long) b); + default -> throw new UnsupportedOperationException("should not reach here"); + }); + + static final BinaryOperator OP_SSUB = named("subSaturating", + (a, b) -> switch (a) { + case Byte _ -> VectorMath.subSaturating((byte) a, (byte) b); + case Short _ -> VectorMath.subSaturating((short) a, (short) b); + case Integer _ -> VectorMath.subSaturating((int) a, (int) b); + case Long _ -> VectorMath.subSaturating((long) a, (long) b); + default -> throw new UnsupportedOperationException("should not reach here"); + }); + + static final BinaryOperator OP_SUADD = named("addSaturatingUnsigned", + (a, b) -> switch (a) { + case Byte _ -> VectorMath.addSaturatingUnsigned((byte) a, (byte) b); + case Short _ -> VectorMath.addSaturatingUnsigned((short) a, (short) b); + case Integer _ -> VectorMath.addSaturatingUnsigned((int) a, (int) b); + case Long _ -> VectorMath.addSaturatingUnsigned((long) a, (long) b); + default -> throw new UnsupportedOperationException("should not reach here"); + }); + + static final BinaryOperator OP_SUSUB = named("subSaturatingUnsigned", + (a, b) -> switch (a) { + case Byte _ -> VectorMath.subSaturatingUnsigned((byte) a, (byte) b); + case Short _ -> VectorMath.subSaturatingUnsigned((short) a, (short) b); + case Integer _ -> VectorMath.subSaturatingUnsigned((int) a, (int) b); + case Long _ -> VectorMath.subSaturatingUnsigned((long) a, (long) b); + default -> throw new UnsupportedOperationException("should not reach here"); + }); + + @DataProvider + public static Object[][] opProvider() { + return new Object[][] { + {OP_UMIN, byte.class, INPUT_UB, INPUT_SB, EXPECTED_UMIN_B, }, + {OP_UMIN, short.class, INPUT_US, INPUT_SS, EXPECTED_UMIN_S, }, + {OP_UMIN, int.class, INPUT_UI, INPUT_SI, EXPECTED_UMIN_I, }, + {OP_UMIN, long.class, INPUT_UL, INPUT_SL, EXPECTED_UMIN_L, }, + + {OP_UMAX, byte.class, INPUT_UB, INPUT_SB, EXPECTED_UMAX_B, }, + {OP_UMAX, short.class, INPUT_US, INPUT_SS, EXPECTED_UMAX_S, }, + {OP_UMAX, int.class, INPUT_UI, INPUT_SI, EXPECTED_UMAX_I, }, + {OP_UMAX, long.class, INPUT_UL, INPUT_SL, EXPECTED_UMAX_L, }, + + {OP_SADD, byte.class, INPUT_SB, conv(INPUT_SADD_I, byte.class), EXPECTED_SADD_B, }, + {OP_SADD, short.class, INPUT_SS, conv(INPUT_SADD_I, short.class), EXPECTED_SADD_S, }, + {OP_SADD, int.class, INPUT_SI, INPUT_SADD_I, EXPECTED_SADD_I, }, + {OP_SADD, long.class, INPUT_SL, conv(INPUT_SADD_I, long.class), EXPECTED_SADD_L, }, + + {OP_SSUB, byte.class, INPUT_SB, conv(INPUT_SSUB_I, byte.class), EXPECTED_SSUB_B, }, + {OP_SSUB, short.class, INPUT_SS, conv(INPUT_SSUB_I, short.class), EXPECTED_SSUB_S, }, + {OP_SSUB, int.class, INPUT_SI, INPUT_SSUB_I, EXPECTED_SSUB_I, }, + {OP_SSUB, long.class, INPUT_SL, conv(INPUT_SSUB_I, long.class), EXPECTED_SSUB_L, }, + + {OP_SUADD, byte.class, INPUT_UB, conv(INPUT_SUADD_I, byte.class), EXPECTED_SUADD_B, }, + {OP_SUADD, short.class, INPUT_US, conv(INPUT_SUADD_I, short.class), EXPECTED_SUADD_S, }, + {OP_SUADD, int.class, INPUT_UI, INPUT_SUADD_I, EXPECTED_SUADD_I, }, + {OP_SUADD, long.class, INPUT_UL, conv(INPUT_SUADD_I, long.class), EXPECTED_SUADD_L, }, + + {OP_SUSUB, byte.class, INPUT_UB, conv(INPUT_SUSUB_I, byte.class), EXPECTED_SUSUB_B, }, + {OP_SUSUB, short.class, INPUT_US, conv(INPUT_SUSUB_I, short.class), EXPECTED_SUSUB_S, }, + {OP_SUSUB, int.class, INPUT_UI, INPUT_SUSUB_I, EXPECTED_SUSUB_I, }, + {OP_SUSUB, long.class, INPUT_UL, conv(INPUT_SUSUB_I, long.class), EXPECTED_SUSUB_L, }, + }; + } + + @Test(dataProvider = "opProvider") + public void test(BinaryOperator op, Class type, Object a, Object b, Object expected) { + assert Array.getLength(a) <= Array.getLength(b) && Array.getLength(a) <= Array.getLength(expected); + + Object actual = Array.newInstance(type, Array.getLength(a)); + for (int i = 0; i < Array.getLength(a); i++) { + Object e = op.apply(Array.get(a, i), Array.get(b, i)); + Array.set(actual, i, e); + } + Assert.assertEquals(actual, expected); + } +} diff --git a/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java b/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java index 28c5348100afa..a8f89f9d705ea 100644 --- a/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java +++ b/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java @@ -41,26 +41,14 @@ */ /* - * @test id=ZSinglegen + * @test id=Z * @bug 8281544 * @summary Test that ZGC and vectorapi with KNL work together. - * @requires vm.gc.ZSinglegen + * @requires vm.gc.Z * @modules jdk.incubator.vector * @modules java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED - * -XX:+UnlockDiagnosticVMOptions -XX:+UseKNLSetting -XX:+UseZGC -XX:-ZGenerational -XX:+IgnoreUnrecognizedVMOptions - * VectorMaxConversionTests - */ - -/* - * @test id=ZGenerational - * @bug 8281544 - * @summary Test that ZGC and vectorapi with KNL work together. - * @requires vm.gc.ZGenerational - * @modules jdk.incubator.vector - * @modules java.base/jdk.internal.vm.annotation - * @run testng/othervm -XX:-TieredCompilation --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED - * -XX:+UnlockDiagnosticVMOptions -XX:+UseKNLSetting -XX:+UseZGC -XX:+ZGenerational -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+UseKNLSetting -XX:+UseZGC -XX:+IgnoreUnrecognizedVMOptions * VectorMaxConversionTests */ diff --git a/test/jdk/jdk/incubator/vector/gen-template.sh b/test/jdk/jdk/incubator/vector/gen-template.sh index 375287bef2d44..232de04ba7c86 100644 --- a/test/jdk/jdk/incubator/vector/gen-template.sh +++ b/test/jdk/jdk/incubator/vector/gen-template.sh @@ -42,6 +42,8 @@ ternary_double_broadcast_masked="Ternary-Double-Broadcast-Masked-op" ternary_scalar="Ternary-Scalar-op" binary="Binary-op" binary_masked="Binary-Masked-op" +saturating_binary="SaturatingBinary-op" +saturating_binary_masked="SaturatingBinary-Masked-op" binary_broadcast="Binary-Broadcast-op" binary_broadcast_masked="Binary-Broadcast-Masked-op" binary_broadcast_long="Binary-Broadcast-Long-op" @@ -310,6 +312,12 @@ function gen_binary_op { gen_op_tmpl $binary_masked "$@" } +function gen_saturating_binary_op { + echo "Generating binary op $1 ($2)..." + gen_op_tmpl $saturating_binary "$@" + gen_op_tmpl $saturating_binary_masked "$@" +} + function gen_binary_op_no_masked { echo "Generating binary op $1 ($2)..." # gen_op_tmpl $binary_scalar "$@" @@ -459,6 +467,12 @@ gen_shift_cst_op "ROL" "ROL_scalar(a, CONST_SHIFT)" "BITWISE" # Masked reductions. gen_binary_op_no_masked "MIN+min" "Math.min(a, b)" gen_binary_op_no_masked "MAX+max" "Math.max(a, b)" +gen_binary_op "UMIN" "VectorMath.minUnsigned(a, b)" "BITWISE" +gen_binary_op "UMAX" "VectorMath.maxUnsigned(a, b)" "BITWISE" +gen_saturating_binary_op "SADD" "VectorMath.addSaturating(a, b)" "BITWISE" +gen_saturating_binary_op "SSUB" "VectorMath.subSaturating(a, b)" "BITWISE" +gen_saturating_binary_op "SUADD" "VectorMath.addSaturatingUnsigned(a, b)" "BITWISE" +gen_saturating_binary_op "SUSUB" "VectorMath.subSaturatingUnsigned(a, b)" "BITWISE" gen_binary_bcst_op_no_masked "MIN+min" "Math.min(a, b)" gen_binary_bcst_op_no_masked "MAX+max" "Math.max(a, b)" @@ -494,10 +508,10 @@ gen_compare_op "NE" "neq" gen_compare_op "LE" "le" gen_compare_op "GE" "ge" -gen_compare_op "UNSIGNED_LT" "ult" "BITWISE" -gen_compare_op "UNSIGNED_GT" "ugt" "BITWISE" -gen_compare_op "UNSIGNED_LE" "ule" "BITWISE" -gen_compare_op "UNSIGNED_GE" "uge" "BITWISE" +gen_compare_op "ULT" "ult" "BITWISE" +gen_compare_op "UGT" "ugt" "BITWISE" +gen_compare_op "ULE" "ule" "BITWISE" +gen_compare_op "UGE" "uge" "BITWISE" gen_compare_bcst_op "LT" "<" diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingBinary-Masked-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingBinary-Masked-op.template new file mode 100644 index 0000000000000..495b27b967c7d --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingBinary-Masked-op.template @@ -0,0 +1,13 @@ + $type$[] a = fa.apply(SPECIES.length()); + $type$[] b = fb.apply(SPECIES.length()); + $type$[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); + $abstractvectortype$ bv = $abstractvectortype$.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.[[TEST]], bv, vmask).intoArray(r, i); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingBinary-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingBinary-op.template new file mode 100644 index 0000000000000..0870991268f39 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingBinary-op.template @@ -0,0 +1,11 @@ + $type$[] a = fa.apply(SPECIES.length()); + $type$[] b = fb.apply(SPECIES.length()); + $type$[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); + $abstractvectortype$ bv = $abstractvectortype$.fromArray(SPECIES, b, i); + av.lanewise(VectorOperators.[[TEST]], bv).intoArray(r, i); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template b/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template index 0d3b310f60f04..9a020c66d52f8 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template @@ -297,6 +297,24 @@ assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "$type$SelectFromTwoVectorOpProvider") + static void SelectFromTwoVector$vectorteststype$(IntFunction<$type$[]> fa, IntFunction<$type$[]> fb, IntFunction<$type$[]> fc) { + $type$[] a = fa.apply(SPECIES.length()); + $type$[] b = fb.apply(SPECIES.length()); + $type$[] idx = fc.apply(SPECIES.length()); + $type$[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); + $abstractvectortype$ bv = $abstractvectortype$.fromArray(SPECIES, b, i); + $abstractvectortype$ idxv = $abstractvectortype$.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + #if[Int] @Test(dataProvider = "$type$UnaryOpShuffleMaskProvider") #else[Int] diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingBinary-Masked-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingBinary-Masked-op.template new file mode 100644 index 0000000000000..5597d706b05a5 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingBinary-Masked-op.template @@ -0,0 +1,7 @@ + + @Test(dataProvider = "$type$SaturatingBinaryOpMaskProvider") + static void [[TEST]]$vectorteststype$Masked(IntFunction<$type$[]> fa, IntFunction<$type$[]> fb, + IntFunction fm) { +[[KERNEL]] + assertArraysEquals(r, a, b, mask, $vectorteststype$::[[TEST]]); + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingBinary-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingBinary-op.template new file mode 100644 index 0000000000000..69c53fa69138d --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingBinary-op.template @@ -0,0 +1,10 @@ + + static $type$ [[TEST]]($type$ a, $type$ b) { + return ($type$)([[TEST_OP]]); + } + + @Test(dataProvider = "$type$SaturatingBinaryOpProvider") + static void [[TEST]]$vectorteststype$(IntFunction<$type$[]> fa, IntFunction<$type$[]> fb) { +[[KERNEL]] + assertArraysEquals(r, a, b, $vectorteststype$::[[TEST]]); + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 42440881771a3..991f82cc7cf19 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -38,6 +38,9 @@ import jdk.incubator.vector.VectorShuffle; import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.Vector; +#if[!FP] +import jdk.incubator.vector.VectorMath; +#end[!FP] #if[Byte] import jdk.incubator.vector.ByteVector; @@ -397,6 +400,25 @@ relativeError)); } } + static void assertSelectFromTwoVectorEquals($type$[] r, $type$[] order, $type$[] a, $type$[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals($type$[] r, $type$[] a, $type$[] order, int vector_len) { int i = 0, j = 0; try { @@ -1202,6 +1224,35 @@ relativeError)); }) ); +#if[!FP] + static final List> $TYPE$_SATURATING_GENERATORS = List.of( + withToString("$type$[$Boxtype$.MIN_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)($Boxtype$.MIN_VALUE)); + }), + withToString("$type$[$Boxtype$.MAX_VALUE]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)($Boxtype$.MAX_VALUE)); + }), + withToString("$type$[$Boxtype$.MAX_VALUE - 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)($Boxtype$.MAX_VALUE - 100)); + }), + withToString("$type$[$Boxtype$.MIN_VALUE + 100]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)($Boxtype$.MIN_VALUE + 100)); + }), + withToString("$type$[-i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)(-i * 5)); + }), + withToString("$type$[i * 5]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)(i * 5)); + }) + ); + +#end[!FP] // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> $TYPE$_GENERATOR_PAIRS = @@ -1209,6 +1260,13 @@ relativeError)); flatMap(fa -> $TYPE$_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); +#if[!FP] + static final List>> $TYPE$_SATURATING_GENERATOR_PAIRS = + Stream.of($TYPE$_GENERATORS.get(0)). + flatMap(fa -> $TYPE$_SATURATING_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). + collect(Collectors.toList()); + +#end[!FP] @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). @@ -1221,18 +1279,49 @@ relativeError)); flatMap(pair -> $TYPE$_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("$type$[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)(RAND.nextInt())); + }) + ); + + static final List>> $TYPE$_GENERATOR_SELECT_FROM_TRIPLES = + $TYPE$_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] $type$BinaryOpProvider() { return $TYPE$_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } +#if[!FP] + @DataProvider + public Object[][] $type$SaturatingBinaryOpProvider() { + return $TYPE$_SATURATING_GENERATOR_PAIRS.stream().map(List::toArray). + toArray(Object[][]::new); + } + +#end[!FP] @DataProvider public Object[][] $type$IndexedOpProvider() { return $TYPE$_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } +#if[!FP] + @DataProvider + public Object[][] $type$SaturatingBinaryOpMaskProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + flatMap(fm -> $TYPE$_SATURATING_GENERATOR_PAIRS.stream().map(lfa -> { + return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); + })). + toArray(Object[][]::new); + } + +#end[!FP] @DataProvider public Object[][] $type$BinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -1248,6 +1337,12 @@ relativeError)); toArray(Object[][]::new); } + @DataProvider + public Object[][] $type$SelectFromTwoVectorOpProvider() { + return $TYPE$_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] $type$TernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). diff --git a/test/jdk/jdk/internal/loader/URLClassPath/ClassnameCharTest.java b/test/jdk/jdk/internal/loader/URLClassPath/ClassnameCharTest.java index 9e14957ef6229..85987ef6f5e1c 100644 --- a/test/jdk/jdk/internal/loader/URLClassPath/ClassnameCharTest.java +++ b/test/jdk/jdk/internal/loader/URLClassPath/ClassnameCharTest.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 @@ -95,9 +95,9 @@ public void handle(HttpExchange exchange) { server.stop(0); } } - // the class loader code was copied from the now deleted AppletClassLoader + static class MyURLClassLoader extends URLClassLoader { - private URL base; /* applet code base URL */ + private URL base; /* code base URL */ private CodeSource codesource; /* codesource for the base URL */ private AccessControlContext acc; MyURLClassLoader(URL base) { diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java b/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java index 5518943a6e666..e236292de984a 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Red Hat, Inc. + * 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 @@ -26,7 +27,7 @@ * @bug 8293540 * @summary Verify that -XshowSettings:system works * @key cgroups - * @requires docker.support + * @requires container.support * @library /test/lib * @run main/timeout=360 TestDockerBasic */ diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java index f08e80c76f422..4d452f20eefe1 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ * @test * @key cgroups * @summary Test JDK Metrics class when running inside docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.platform * @build MetricsCpuTester diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java index 416e91bec5ca2..e8dc616b5e79a 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java @@ -32,7 +32,7 @@ * @test * @key cgroups * @summary Test JDK Metrics class when running inside docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.platform * @build MetricsMemoryTester diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index 92f3364da10b0..204d7a215d89f 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2020, 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 @@ -25,7 +26,7 @@ * @test * @key cgroups * @bug 8242480 - * @requires docker.support + * @requires container.support * @library /test/lib * @build GetFreeSwapSpaceSize * @run driver TestGetFreeSwapSpaceSize diff --git a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java index 22e03293c486e..1544088f68858 100644 --- a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java +++ b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,7 +29,7 @@ * @bug 8308090 * @key cgroups * @summary Test container limits updating as they get updated at runtime without restart - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.platform * @build LimitUpdateChecker diff --git a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java index 6c6ff76fa9998..9fedeb55234ca 100644 --- a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java +++ b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,7 +27,7 @@ * @key cgroups * @summary Test JDK Metrics class when running inside a docker container with limited pids * @bug 8266490 - * @requires docker.support + * @requires container.support * @library /test/lib * @build TestPidsLimit * @run driver TestPidsLimit diff --git a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java index 854d24b2279f8..93efff64cc428 100644 --- a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.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 @@ -25,7 +25,7 @@ * @test * @key cgroups * @summary Test JDK Metrics class when running inside docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.platform * @run main TestSystemMetrics diff --git a/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java b/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java index 7a2f77b3ce41a..6a96514771ce4 100644 --- a/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java +++ b/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Red Hat, Inc. + * 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 @@ -24,7 +25,7 @@ /* * @test * @summary UseContainerSupport flag should reflect Metrics being available - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.platform * @build CheckUseContainerSupport diff --git a/test/jdk/jdk/jfr/event/compiler/TestCompilerCompile.java b/test/jdk/jdk/jfr/event/compiler/TestCompilerCompile.java index 8d070db8262a7..e13bcaa80b5cc 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCompilerCompile.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerCompile.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 @@ -41,7 +41,7 @@ * @test * @key jfr * @requires vm.hasJFR - * @requires vm.compMode!="Xint" + * @requires vm.compMode == "Xmixed" * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox diff --git a/test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java b/test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java index 56005fa745832..b13fa71410926 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java @@ -57,7 +57,7 @@ * @key jfr * @summary Verifies that corresponding JFR events are emitted in case of inlining. * @requires vm.hasJFR - * + * @requires vm.compMode == "Xmixed" * @requires vm.opt.Inline == true | vm.opt.Inline == null * @library /test/lib * @modules jdk.jfr diff --git a/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java b/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java index daf562a765fbe..bd6d57b31762d 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java +++ b/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.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 @@ -51,7 +51,7 @@ public static void dummyMethod(boolean b) { * @key jfr * @summary sanity test for Deoptimization event, depends on Compilation event * @requires vm.hasJFR - * @requires vm.compMode != "Xint" + * @requires vm.compMode == "Xmixed" * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == 4 | vm.opt.TieredStopAtLevel == null) * @requires vm.opt.StressUnstableIfTraps == null | !vm.opt.StressUnstableIfTraps * @library /test/lib diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMajor.java b/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMajor.java index 81e18439b5788..3766d9d0d32b0 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMajor.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMajor.java @@ -35,10 +35,10 @@ /** * @test - * @requires vm.hasJFR & vm.gc.ZGenerational + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @library /test/lib /test/jdk - * @run main/othervm -Xmx50m -XX:+UseZGC -XX:+ZGenerational -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc* jdk.jfr.event.gc.collection.TestGarbageCollectionEventWithZMajor + * @run main/othervm -Xmx50m -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc* jdk.jfr.event.gc.collection.TestGarbageCollectionEventWithZMajor */ public class TestGarbageCollectionEventWithZMajor { diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java b/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java index e7e94cf9ff040..c8d681594dd74 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java @@ -40,12 +40,12 @@ /** * @test * @key jfr - * @requires vm.hasJFR & vm.gc.ZGenerational + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @library /test/lib /test/jdk * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UseZGC -XX:+ZGenerational -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc* jdk.jfr.event.gc.collection.TestGarbageCollectionEventWithZMinor + * @run main/othervm -Xbootclasspath/a:. -XX:+UseZGC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc* jdk.jfr.event.gc.collection.TestGarbageCollectionEventWithZMinor */ public class TestGarbageCollectionEventWithZMinor { diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestZOldGarbageCollectionEvent.java b/test/jdk/jdk/jfr/event/gc/collection/TestZOldGarbageCollectionEvent.java index 0f807f4f6e4ba..50177ffd16b77 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestZOldGarbageCollectionEvent.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestZOldGarbageCollectionEvent.java @@ -35,10 +35,10 @@ /** * @test - * @requires vm.hasJFR & vm.gc.ZGenerational + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @library /test/lib /test/jdk - * @run main/othervm -Xmx50m -XX:+UseZGC -XX:+ZGenerational -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc* jdk.jfr.event.gc.collection.TestZOldGarbageCollectionEvent + * @run main/othervm -Xmx50m -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc* jdk.jfr.event.gc.collection.TestZOldGarbageCollectionEvent */ public class TestZOldGarbageCollectionEvent { diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestZYoungGarbageCollectionEvent.java b/test/jdk/jdk/jfr/event/gc/collection/TestZYoungGarbageCollectionEvent.java index c16bdaa5d642f..f8e4e8b344bda 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestZYoungGarbageCollectionEvent.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestZYoungGarbageCollectionEvent.java @@ -35,10 +35,10 @@ /** * @test - * @requires vm.hasJFR & vm.gc.ZGenerational + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @library /test/lib /test/jdk - * @run main/othervm -Xmx50m -XX:+UseZGC -XX:+ZGenerational -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc* jdk.jfr.event.gc.collection.TestZYoungGarbageCollectionEvent + * @run main/othervm -Xmx50m -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc* jdk.jfr.event.gc.collection.TestZYoungGarbageCollectionEvent */ public class TestZYoungGarbageCollectionEvent { diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestGCPhaseConcurrent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestGCPhaseConcurrent.java index fb048ee6bd7c5..48e188346f871 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestGCPhaseConcurrent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestGCPhaseConcurrent.java @@ -31,19 +31,11 @@ import jdk.test.lib.jfr.Events; /** - * @test id=ZGenerational + * @test id=Z * @key jfr * @library /test/lib /test/jdk /test/hotspot/jtreg - * @requires vm.hasJFR & vm.gc.ZGenerational - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xmx32M jdk.jfr.event.gc.detailed.TestGCPhaseConcurrent Z - */ - -/** - * @test id=ZSinglegen - * @key jfr - * @library /test/lib /test/jdk /test/hotspot/jtreg - * @requires vm.hasJFR & vm.gc.ZSinglegen - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xmx32M jdk.jfr.event.gc.detailed.TestGCPhaseConcurrent X + * @requires vm.hasJFR & vm.gc.Z + * @run main/othervm -XX:+UseZGC -Xmx32M jdk.jfr.event.gc.detailed.TestGCPhaseConcurrent Z */ /** diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestZAllocationStallEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestZAllocationStallEvent.java index 8977a574a627b..1b4ce2597847c 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestZAllocationStallEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestZAllocationStallEvent.java @@ -32,19 +32,11 @@ import jdk.test.lib.jfr.Events; /** - * @test id=ZSinglegen - * @requires vm.hasJFR & vm.gc.ZSinglegen + * @test + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xmx32M -Xlog:gc*:gc.log::filecount=0 jdk.jfr.event.gc.detailed.TestZAllocationStallEvent - */ - -/** - * @test id=ZGenerational - * @requires vm.hasJFR & vm.gc.ZGenerational - * @key jfr - * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xmx32M -Xlog:gc*:gc.log::filecount=0 jdk.jfr.event.gc.detailed.TestZAllocationStallEvent + * @run main/othervm -XX:+UseZGC -Xmx32M -Xlog:gc*:gc.log::filecount=0 jdk.jfr.event.gc.detailed.TestZAllocationStallEvent */ public class TestZAllocationStallEvent { diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestZPageAllocationEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestZPageAllocationEvent.java index 182f7b3d509f3..d672a2654b814 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestZPageAllocationEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestZPageAllocationEvent.java @@ -32,19 +32,11 @@ import jdk.test.lib.jfr.Events; /** - * @test id=ZSinglegen - * @requires vm.hasJFR & vm.gc.ZSinglegen + * @test + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xmx32M jdk.jfr.event.gc.detailed.TestZPageAllocationEvent - */ - -/** - * @test id=ZGenerational - * @requires vm.hasJFR & vm.gc.ZGenerational - * @key jfr - * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xmx32M jdk.jfr.event.gc.detailed.TestZPageAllocationEvent + * @run main/othervm -XX:+UseZGC -Xmx32M jdk.jfr.event.gc.detailed.TestZPageAllocationEvent */ public class TestZPageAllocationEvent { diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestZRelocationSetEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestZRelocationSetEvent.java index 8f07abeaaefd4..f14eec9754828 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestZRelocationSetEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestZRelocationSetEvent.java @@ -32,19 +32,11 @@ import jdk.test.lib.jfr.Events; /** - * @test id=ZSinglegen - * @requires vm.hasJFR & vm.gc.ZSinglegen + * @test + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xmx32M jdk.jfr.event.gc.detailed.TestZRelocationSetEvent - */ - -/** - * @test id=ZGenerational - * @requires vm.hasJFR & vm.gc.ZGenerational - * @key jfr - * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xmx32M jdk.jfr.event.gc.detailed.TestZRelocationSetEvent + * @run main/othervm -XX:+UseZGC -Xmx32M jdk.jfr.event.gc.detailed.TestZRelocationSetEvent */ public class TestZRelocationSetEvent { diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestZRelocationSetGroupEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestZRelocationSetGroupEvent.java index b997d173ffb13..f00655cf94276 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestZRelocationSetGroupEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestZRelocationSetGroupEvent.java @@ -32,19 +32,11 @@ import jdk.test.lib.jfr.Events; /** - * @test id=ZSinglegen - * @requires vm.hasJFR & vm.gc.ZSinglegen + * @test + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xmx32M jdk.jfr.event.gc.detailed.TestZRelocationSetGroupEvent - */ - -/** - * @test id=ZGenerational - * @requires vm.hasJFR & vm.gc.ZGenerational - * @key jfr - * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xmx32M jdk.jfr.event.gc.detailed.TestZRelocationSetGroupEvent + * @run main/othervm -XX:+UseZGC -Xmx32M jdk.jfr.event.gc.detailed.TestZRelocationSetGroupEvent */ public class TestZRelocationSetGroupEvent { diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestZUncommitEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestZUncommitEvent.java index 06fd9b5a1b868..e7a37e2de554d 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestZUncommitEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestZUncommitEvent.java @@ -34,19 +34,11 @@ import jdk.test.lib.jfr.Events; /** - * @test id=ZSinglegen - * @requires vm.hasJFR & vm.gc.ZSinglegen + * @test id=Z + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xms32M -Xmx128M -Xlog:gc,gc+heap -XX:+ZUncommit -XX:ZUncommitDelay=1 jdk.jfr.event.gc.detailed.TestZUncommitEvent - */ - -/** - * @test id=ZGenerational - * @requires vm.hasJFR & vm.gc.ZGenerational - * @key jfr - * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xms32M -Xmx128M -Xlog:gc,gc+heap -XX:+ZUncommit -XX:ZUncommitDelay=1 jdk.jfr.event.gc.detailed.TestZUncommitEvent + * @run main/othervm -XX:+UseZGC -Xms32M -Xmx128M -Xlog:gc,gc+heap -XX:+ZUncommit -XX:ZUncommitDelay=1 jdk.jfr.event.gc.detailed.TestZUncommitEvent */ public class TestZUncommitEvent { diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestZUnmapEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestZUnmapEvent.java index 94460f8f27838..a19e89771c08c 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestZUnmapEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestZUnmapEvent.java @@ -32,19 +32,11 @@ import jdk.test.lib.jfr.Events; /** - * @test id=ZSinglegen - * @requires vm.hasJFR & vm.gc.ZSinglegen + * @test id=Z + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xmx32M jdk.jfr.event.gc.detailed.TestZUnmapEvent - */ - -/** - * @test id=ZGenerational - * @requires vm.hasJFR & vm.gc.ZGenerational - * @key jfr - * @library /test/lib /test/jdk /test/hotspot/jtreg - * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xmx32M jdk.jfr.event.gc.detailed.TestZUnmapEvent + * @run main/othervm -XX:+UseZGC -Xmx32M jdk.jfr.event.gc.detailed.TestZUnmapEvent */ public class TestZUnmapEvent { diff --git a/test/jdk/jdk/jfr/event/oldobject/TestZ.java b/test/jdk/jdk/jfr/event/oldobject/TestZ.java index 224a12373240c..99605846382bf 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestZ.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestZ.java @@ -33,23 +33,13 @@ import jdk.test.lib.jfr.Events; /** - * @test id=ZSinglegen - * @requires vm.hasJFR & vm.gc.ZSinglegen + * @test + * @requires vm.hasJFR & vm.gc.Z * @key jfr * @summary Test leak profiler with ZGC * @library /test/lib /test/jdk * @modules jdk.jfr/jdk.jfr.internal.test - * @run main/othervm -XX:TLABSize=2k -XX:+UseZGC -XX:-ZGenerational jdk.jfr.event.oldobject.TestZ - */ - -/** - * @test id=ZGenerational - * @requires vm.hasJFR & vm.gc.ZGenerational - * @key jfr - * @summary Test leak profiler with ZGC - * @library /test/lib /test/jdk - * @modules jdk.jfr/jdk.jfr.internal.test - * @run main/othervm -XX:TLABSize=2k -XX:+UseZGC -XX:+ZGenerational jdk.jfr.event.oldobject.TestZ + * @run main/othervm -XX:TLABSize=2k -XX:+UseZGC jdk.jfr.event.oldobject.TestZ */ public class TestZ { diff --git a/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java b/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java index 9becd4677e1c6..240868d567077 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java @@ -65,7 +65,7 @@ * jdk.jfr.event.runtime.TestAgentEvent * testJavaDynamic * - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -agentlib:jdwp=transport=dt_socket,server=y,address=any,onjcmd=y + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0 * jdk.jfr.event.runtime.TestAgentEvent * testNativeStatic */ @@ -122,7 +122,7 @@ private static void testNativeStatic() throws Throwable { RecordedEvent e = events.get(1); System.out.println(e); Events.assertField(e, "name").equal("jdwp"); - Events.assertField(e, "options").equal("transport=dt_socket,server=y,address=any,onjcmd=y"); + Events.assertField(e, "options").equal("transport=dt_socket,server=y,suspend=n,address=0"); Events.assertField(e, "dynamic").equal(false); Instant initializationTime = e.getInstant("initializationTime"); if (initializationTime.isAfter(interval.getStartTime())) { diff --git a/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java b/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java index 891f6e62e6fc7..b256d2b89ab0b 100644 --- a/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java +++ b/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java @@ -34,6 +34,8 @@ import java.lang.management.ManagementFactory; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.IntPredicate; +import java.util.function.LongPredicate; import java.util.stream.Stream; import java.util.stream.IntStream; import javax.management.MBeanServer; @@ -140,23 +142,37 @@ void testReduceParallelism(VirtualThreadSchedulerMXBean bean) throws Exception { try { // increase parallelism + saturate - int newParallelism = parallelism + 4; - bean.setParallelism(newParallelism); - IntStream.range(0, newParallelism).forEach(_ -> executor.submit(busyTask)); - awaitMountedVirtualThreadCountGte(bean, newParallelism); + int highParallelism = parallelism + 4; + bean.setParallelism(highParallelism); + IntStream.range(0, highParallelism).forEach(_ -> executor.submit(busyTask)); + + // mounted virtual thread count should increase to highParallelism. + // Sample the count at highParallelism a few times. + for (int i = 0; i < 5; i++) { + Thread.sleep(100); + awaitMountedVirtualThreadCountEq(bean, highParallelism); + } // reduce parallelism and workload - newParallelism = Math.clamp(parallelism / 2, 1, parallelism); - bean.setParallelism(newParallelism); + int lowParallelism = Math.clamp(parallelism / 2, 1, parallelism); + bean.setParallelism(lowParallelism); sleep.set(true); - // mounted virtual thread count should reduce - awaitMountedVirtualThreadCountLte(bean, newParallelism); - // increase workload, the mounted virtual thread count should not increase + // mounted virtual thread count should reduce to lowParallelism or less. + // Sample the count at lowParallelism or less a few times. + for (int i = 0; i < 5; i++) { + Thread.sleep(100); + awaitMountedVirtualThreadCountLte(bean, lowParallelism); + } + + // increase workload sleep.set(false); + + // mounted virtual thread count should not exceed lowParallelism. + // Sample the count at lowParallelism a few times. for (int i = 0; i < 5; i++) { Thread.sleep(100); - assertTrue(bean.getMountedVirtualThreadCount() <= newParallelism); + awaitMountedVirtualThreadCountEq(bean, lowParallelism); } } finally { @@ -230,31 +246,64 @@ void testQueuedVirtualThreadCount(VirtualThreadSchedulerMXBean bean) throws Exce * Waits for pool size >= target to be true. */ void awaitPoolSizeGte(VirtualThreadSchedulerMXBean bean, int target) throws InterruptedException { - System.err.format("await pool size >= %d ...%n", target); - while (bean.getPoolSize() < target) { - Thread.sleep(10); - } + awaitPoolSize(bean, ps -> ps >= target, ">= " + target); } /** * Waits for the mounted virtual thread count >= target to be true. */ void awaitMountedVirtualThreadCountGte(VirtualThreadSchedulerMXBean bean, - int target) throws InterruptedException { - System.err.format("await mounted virtual thread count >= %d ...%n", target); - while (bean.getMountedVirtualThreadCount() < target) { - Thread.sleep(10); - } + long target) throws InterruptedException { + awaitMountedVirtualThreadCount(bean, c -> c >= target, ">= " + target); } /** * Waits for the mounted virtual thread count <= target to be true. */ void awaitMountedVirtualThreadCountLte(VirtualThreadSchedulerMXBean bean, - int target) throws InterruptedException { - System.err.format("await mounted virtual thread count <= %d ...%n", target); - while (bean.getMountedVirtualThreadCount() > target) { - Thread.sleep(10); + long target) throws InterruptedException { + awaitMountedVirtualThreadCount(bean, c -> c <= target, "<= " + target); + } + + /** + * Waits for the mounted virtual thread count == target to be true. + */ + void awaitMountedVirtualThreadCountEq(VirtualThreadSchedulerMXBean bean, + long target) throws InterruptedException { + awaitMountedVirtualThreadCount(bean, c -> c == target, "== " + target); + } + + /** + * Waits until evaluating the given predicte on the pool size is true. + */ + void awaitPoolSize(VirtualThreadSchedulerMXBean bean, + IntPredicate predicate, + String reason) throws InterruptedException { + int poolSize = bean.getPoolSize(); + if (!predicate.test(poolSize)) { + System.err.format("poolSize = %d, await %s ...%n", poolSize, reason); + while (!predicate.test(poolSize)) { + Thread.sleep(10); + poolSize = bean.getPoolSize(); + } + System.err.format("poolSize = %d%n", poolSize); + } + } + + /** + * Waits until evaluating the given predicte on the mounted thread count is true. + */ + void awaitMountedVirtualThreadCount(VirtualThreadSchedulerMXBean bean, + LongPredicate predicate, + String reason) throws InterruptedException { + long count = bean.getMountedVirtualThreadCount(); + if (!predicate.test(count)) { + System.err.format("mountedVirtualThreadCount = %d, await %s ...%n", count, reason); + while (!predicate.test(count)) { + Thread.sleep(10); + count = bean.getMountedVirtualThreadCount(); + } + System.err.format("mountedVirtualThreadCount = %d%n", count); } } } \ No newline at end of file diff --git a/test/jdk/jdk/modules/etc/UpgradeableModules.java b/test/jdk/jdk/modules/etc/UpgradeableModules.java index 3616c6b6d4d1a..8c5fbeafb28f6 100644 --- a/test/jdk/jdk/modules/etc/UpgradeableModules.java +++ b/test/jdk/jdk/modules/etc/UpgradeableModules.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 @@ -45,7 +45,8 @@ public class UpgradeableModules { private static final List UPGRADEABLE_MODULES = List.of("java.compiler", "jdk.graal.compiler", - "jdk.graal.compiler.management"); + "jdk.graal.compiler.management", + "jdk.jsobject"); public static void main(String... args) { diff --git a/test/jdk/jdk/security/jarsigner/Spec.java b/test/jdk/jdk/security/jarsigner/Spec.java index 0e189babb8bf9..5ca3b11cd96d4 100644 --- a/test/jdk/jdk/security/jarsigner/Spec.java +++ b/test/jdk/jdk/security/jarsigner/Spec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import jdk.security.jarsigner.JarSigner; import jdk.test.lib.util.JarUtils; +import jdk.test.lib.security.SecurityUtils; import sun.security.provider.certpath.X509CertPath; import java.io.File; @@ -175,14 +176,16 @@ public static void main(String[] args) throws Exception { .equals("SHA-384")); // Calculating large DSA and RSA keys are too slow. - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); - kpg.initialize(1024); + String kpgRSA = "RSA"; + String kpgDSA = "DSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgRSA); + kpg.initialize(SecurityUtils.getTestKeySize(kpgRSA)); assertTrue(JarSigner.Builder .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate()) .equals("SHA384withRSA")); - kpg = KeyPairGenerator.getInstance("DSA"); - kpg.initialize(1024); + kpg = KeyPairGenerator.getInstance(kpgDSA); + kpg.initialize(SecurityUtils.getTestKeySize(kpgDSA)); assertTrue(JarSigner.Builder .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate()) .equals("SHA256withDSA")); 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 924f58cc80f25..2bfd3ea760320 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 @@ -26,7 +26,7 @@ * @bug 8189131 * @summary Interoperability tests with Actalis CA * Before this test set to manual, the original timeout - * value if 180 + * value is 180 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop * @run main/othervm/manual -Djava.security.debug=certpath,ocsp diff --git a/test/jdk/sun/awt/font/TestDevTransform.java b/test/jdk/sun/awt/font/TestDevTransform.java index 035cb0b13d73a..2783401c0f2db 100644 --- a/test/jdk/sun/awt/font/TestDevTransform.java +++ b/test/jdk/sun/awt/font/TestDevTransform.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4269775 + * @bug 4269775 8341535 * @summary Check that different text rendering APIs agree */ @@ -46,6 +46,8 @@ import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; +import java.io.File; import java.util.HashMap; public class TestDevTransform { @@ -105,17 +107,34 @@ static void init(Graphics2D g2d) { g2d.setFont(font); } - static void compare(BufferedImage bi1, BufferedImage bi2) { + static void compare(BufferedImage bi1, String name1, BufferedImage bi2, String name2) throws Exception { + int nonWhite1 = 0; + int nonWhite2 = 0; + int differences = 0; + int whitePixel = Color.white.getRGB(); for (int x = 0; x < bi1.getWidth(); x++) { for (int y = 0; y < bi1.getHeight(); y++) { + int pix1 = bi1.getRGB(x, y); + int pix2 = bi2.getRGB(x, y); + if (pix1 != whitePixel) { nonWhite1++; } + if (pix2 != whitePixel) { nonWhite2++; } if (bi1.getRGB(x, y) != bi2.getRGB(x, y)) { - throw new RuntimeException("Different rendering"); + differences++; } } } + int nonWhite = (nonWhite1 < nonWhite2) ? nonWhite1 : nonWhite2; + if (differences > 0 && ((nonWhite / differences) < 20)) { + ImageIO.write(bi1, "png", new File(name1 + ".png")); + ImageIO.write(bi2, "png", new File(name2 + ".png")); + System.err.println("nonWhite image 1 = " + nonWhite1); + System.err.println("nonWhite image 2 = " + nonWhite2); + System.err.println("Number of non-white differing pixels=" + differences); + throw new RuntimeException("Different rendering: " + differences + " pixels differ."); + } } - public static void main(String args[]) { + public static void main(String args[]) throws Exception { BufferedImage tl_Image = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); { @@ -149,7 +168,7 @@ public static void main(String args[]) { draw(gv_g2d, gv, 10f, 36f, .33f); } - compare(tl_Image, st_Image); - compare(gv_Image, st_Image); + compare(tl_Image, "textlayout", st_Image, "string"); + compare(gv_Image, "glyphvector", st_Image, "string"); } } diff --git a/test/jdk/sun/net/www/ParseUtil_6380332.java b/test/jdk/sun/net/www/ParseUtil_6380332.java index a517742f2c4bf..bd0331d52bd53 100644 --- a/test/jdk/sun/net/www/ParseUtil_6380332.java +++ b/test/jdk/sun/net/www/ParseUtil_6380332.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 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 @@ -22,12 +22,13 @@ */ /* @test - * @summary SunTea applet fails to load under Mustang + * @summary Ensure ParseUtil.toURI does not fail when port number is -1 * @bug 6380332 * @modules java.base/sun.net.www */ import sun.net.www.ParseUtil; + import java.net.URI; import java.net.URL; diff --git a/test/jdk/sun/net/www/protocol/http/B6296310.java b/test/jdk/sun/net/www/protocol/http/B6296310.java index dbb3ead18c556..867b4edaf3280 100644 --- a/test/jdk/sun/net/www/protocol/http/B6296310.java +++ b/test/jdk/sun/net/www/protocol/http/B6296310.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,8 @@ * @library /test/lib * @run main/othervm B6296310 * @run main/othervm -Djava.net.preferIPv6Addresses=true B6296310 - * @summary REGRESSION: AppletClassLoader.getResourceAsStream() behaviour is wrong in some cases + * @summary Prevent NPE in HttpURLConnection.getInputStream0() when + * content length is 0 */ import java.io.IOException; diff --git a/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java b/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java index 841279fa76d5e..2fba6d8ab7548 100644 --- a/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java +++ b/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @bug 6262486 * @library /test/lib * @run main/othervm -Dhttp.keepAlive=false ResponseCacheStream - * @summary COMPATIBILITY: jagex_com - Monkey Puzzle applet fails to load + * @summary Ensure HttpInputStream resets properly when cache is in use */ import java.io.ByteArrayOutputStream; diff --git a/test/jdk/sun/rmi/transport/tcp/disableMultiplexing/DisableMultiplexing.java b/test/jdk/sun/rmi/transport/tcp/disableMultiplexing/DisableMultiplexing.java index 4a8748ab25320..253f166cae4dd 100644 --- a/test/jdk/sun/rmi/transport/tcp/disableMultiplexing/DisableMultiplexing.java +++ b/test/jdk/sun/rmi/transport/tcp/disableMultiplexing/DisableMultiplexing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, 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 @@ -24,7 +24,7 @@ /* @test * @bug 4183204 * @summary The RMI runtime should fail to export a remote object on a TCP - * port for an applet or application that does not have permission to listen + * port for an application that does not have permission to listen * on that port, rather than engage in the deprecated "multiplexing protocol". * @author Peter Jones * diff --git a/test/jdk/sun/security/ec/ECDSAPrimitive.java b/test/jdk/sun/security/ec/ECDSAPrimitive.java index ba9ed0dec80d3..71e2e30044b8f 100644 --- a/test/jdk/sun/security/ec/ECDSAPrimitive.java +++ b/test/jdk/sun/security/ec/ECDSAPrimitive.java @@ -93,7 +93,8 @@ public static void main(String[] args) throws Exception { digestAlg = null; } else { AlgorithmParameters params = - AlgorithmParameters.getInstance("EC", "SunEC"); + AlgorithmParameters.getInstance("EC", + System.getProperty("test.provider.name", "SunEC")); params.init(new ECGenParameterSpec(curveName)); ecParams = params.getParameterSpec( ECParameterSpec.class); diff --git a/test/jdk/sun/security/ec/ECDSAPrvGreaterThanOrder.java b/test/jdk/sun/security/ec/ECDSAPrvGreaterThanOrder.java index 40f52d534a7d9..f5a02971dbf5d 100644 --- a/test/jdk/sun/security/ec/ECDSAPrvGreaterThanOrder.java +++ b/test/jdk/sun/security/ec/ECDSAPrvGreaterThanOrder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ public static void main(String[] args) throws Exception { KeyAgreement ka = null; try { sig = Signature.getInstance("SHA256withECDSA", - "SunEC"); + System.getProperty("test.provider.name", "SunEC")); sig.initSign(ecPrivKey); throw new RuntimeException("Expected exception for " + "ECDSA/" + sig.getAlgorithm() + "/" + curveName + @@ -66,7 +66,8 @@ public static void main(String[] args) throws Exception { // Next, try starting a ECDH operation try { - ka = KeyAgreement.getInstance("ECDH", "SunEC"); + ka = KeyAgreement.getInstance("ECDH", + System.getProperty("test.provider.name", "SunEC")); ka.init(ecPrivKey); throw new RuntimeException("Expected exception for ECDH/" + curveName + " not thrown."); @@ -83,7 +84,7 @@ private static ECPrivateKey makePrivateKey(String curveName) { System.out.println("Creating private key for curve " + curveName); AlgorithmParameters params = AlgorithmParameters.getInstance( - "EC", "SunEC"); + "EC", System.getProperty("test.provider.name", "SunEC")); params.init(new ECGenParameterSpec(curveName)); ECParameterSpec ecParameters = params.getParameterSpec( ECParameterSpec.class); @@ -96,7 +97,8 @@ private static ECPrivateKey makePrivateKey(String curveName) { System.out.println("Modified d Value is: " + dVal); // Create the private key - KeyFactory kf = KeyFactory.getInstance("EC", "SunEC"); + KeyFactory kf = KeyFactory.getInstance("EC", + System.getProperty("test.provider.name", "SunEC")); return (ECPrivateKey)kf.generatePrivate( new ECPrivateKeySpec(dVal, ecParameters)); } catch (GeneralSecurityException gse) { diff --git a/test/jdk/sun/security/ec/InvalidCurve.java b/test/jdk/sun/security/ec/InvalidCurve.java index 4c696970b8427..76d3b6b79e6f8 100644 --- a/test/jdk/sun/security/ec/InvalidCurve.java +++ b/test/jdk/sun/security/ec/InvalidCurve.java @@ -38,7 +38,8 @@ public static void main(String[] args) { KeyPairGenerator keyGen; try { - keyGen = KeyPairGenerator.getInstance("EC", "SunEC"); + keyGen = KeyPairGenerator.getInstance("EC", + System.getProperty("test.provider.name", "SunEC")); ECGenParameterSpec brainpoolSpec = new ECGenParameterSpec("brainpoolP160r1"); keyGen.initialize(brainpoolSpec); diff --git a/test/jdk/sun/security/ec/NSASuiteB/TestSHAwithECDSASignatureOids.java b/test/jdk/sun/security/ec/NSASuiteB/TestSHAwithECDSASignatureOids.java index cca4e77befb90..ba209d7e42981 100644 --- a/test/jdk/sun/security/ec/NSASuiteB/TestSHAwithECDSASignatureOids.java +++ b/test/jdk/sun/security/ec/NSASuiteB/TestSHAwithECDSASignatureOids.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, 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 @@ -45,7 +45,7 @@ public class TestSHAwithECDSASignatureOids { public static void main(String[] args) throws Exception { TestSignatureOidHelper helper = new TestSignatureOidHelper("EC", - "SunEC", 256, DATA); + System.getProperty("test.provider.name", "SunEC"), 256, DATA); helper.execute(); } } diff --git a/test/jdk/sun/security/ec/OidInstance.java b/test/jdk/sun/security/ec/OidInstance.java index 972c8e1026a50..590ddce305e6b 100644 --- a/test/jdk/sun/security/ec/OidInstance.java +++ b/test/jdk/sun/security/ec/OidInstance.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 @@ -38,8 +38,8 @@ public class OidInstance { public static void main(String[] args) throws Exception { String oid = KnownOIDs.EC.value(); - KeyFactory.getInstance(oid, "SunEC"); - KeyPairGenerator.getInstance(oid, "SunEC"); - AlgorithmParameters.getInstance(oid, "SunEC"); + KeyFactory.getInstance(oid, System.getProperty("test.provider.name", "SunEC")); + KeyPairGenerator.getInstance(oid, System.getProperty("test.provider.name", "SunEC")); + AlgorithmParameters.getInstance(oid, System.getProperty("test.provider.name", "SunEC")); } } diff --git a/test/jdk/sun/security/ec/SignatureDigestTruncate.java b/test/jdk/sun/security/ec/SignatureDigestTruncate.java index 47f0123a49164..99048f851375d 100644 --- a/test/jdk/sun/security/ec/SignatureDigestTruncate.java +++ b/test/jdk/sun/security/ec/SignatureDigestTruncate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -96,17 +96,20 @@ private static void runTest(String alg, String curveName, byte[] expectedSig = hex.parseHex(sigStr); AlgorithmParameters params = - AlgorithmParameters.getInstance("EC", "SunEC"); + AlgorithmParameters.getInstance("EC", + System.getProperty("test.provider.name", "SunEC")); params.init(new ECGenParameterSpec(curveName)); ECParameterSpec ecParams = params.getParameterSpec(ECParameterSpec.class); - KeyFactory kf = KeyFactory.getInstance("EC", "SunEC"); + KeyFactory kf = KeyFactory.getInstance("EC", + System.getProperty("test.provider.name", "SunEC")); BigInteger s = new BigInteger(1, privateKey); ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(s, ecParams); PrivateKey privKey = kf.generatePrivate(privKeySpec); - Signature sig = Signature.getInstance(alg, "SunEC"); + Signature sig = Signature.getInstance(alg, + System.getProperty("test.provider.name", "SunEC")); sig.initSign(privKey, new FixedRandom(k)); sig.update(msg); byte[] computedSig = sig.sign(); diff --git a/test/jdk/sun/security/ec/SignatureKAT.java b/test/jdk/sun/security/ec/SignatureKAT.java index 542d90d6ca52c..802c74f3b6922 100644 --- a/test/jdk/sun/security/ec/SignatureKAT.java +++ b/test/jdk/sun/security/ec/SignatureKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,16 +132,19 @@ private static void runTest(TestData td) throws Exception { System.out.println("Testing " + td.sigName + " with " + td.cd.name); AlgorithmParameters params = - AlgorithmParameters.getInstance("EC", "SunEC"); + AlgorithmParameters.getInstance("EC", + System.getProperty("test.provider.name", "SunEC")); params.init(new ECGenParameterSpec(td.cd.name)); ECParameterSpec ecParams = params.getParameterSpec(ECParameterSpec.class); - KeyFactory kf = KeyFactory.getInstance("EC", "SunEC"); + KeyFactory kf = KeyFactory.getInstance("EC", + System.getProperty("test.provider.name", "SunEC")); PrivateKey privKey = kf.generatePrivate (new ECPrivateKeySpec(td.cd.priv, ecParams)); - Signature sig = Signature.getInstance(td.sigName, "SunEC"); + Signature sig = Signature.getInstance(td.sigName, + System.getProperty("test.provider.name", "SunEC")); sig.initSign(privKey); sig.update(td.cd.msgBytes); // NOTE: there is no way to set the nonce value into current SunEC diff --git a/test/jdk/sun/security/ec/SignedObjectChain.java b/test/jdk/sun/security/ec/SignedObjectChain.java index cfeff8c1ad587..e245a6caa2dd7 100644 --- a/test/jdk/sun/security/ec/SignedObjectChain.java +++ b/test/jdk/sun/security/ec/SignedObjectChain.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 @@ -35,7 +35,7 @@ public class SignedObjectChain { private static class Test extends Chain.Test { public Test(Chain.SigAlg sigAlg) { - super(sigAlg, Chain.KeyAlg.EC, Chain.Provider.SunEC); + super(sigAlg, Chain.KeyAlg.EC, Chain.Provider.TestProvider_or_SunEC); } } diff --git a/test/jdk/sun/security/ec/TestEC.java b/test/jdk/sun/security/ec/TestEC.java index de4f47ca5edb5..dacb67ce892fc 100644 --- a/test/jdk/sun/security/ec/TestEC.java +++ b/test/jdk/sun/security/ec/TestEC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,7 +85,7 @@ public static void main(String[] args) throws Exception { } public static void main0(String[] args) throws Exception { - Provider p = Security.getProvider("SunEC"); + Provider p = Security.getProvider(System.getProperty("test.provider.name", "SunEC")); if (p == null) { throw new NoSuchProviderException("Can't get SunEC provider"); diff --git a/test/jdk/sun/security/ec/ed/EdCRLSign.java b/test/jdk/sun/security/ec/ed/EdCRLSign.java index 4ed512b8f20f8..10a801f4f5f87 100644 --- a/test/jdk/sun/security/ec/ed/EdCRLSign.java +++ b/test/jdk/sun/security/ec/ed/EdCRLSign.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 @@ -44,7 +44,7 @@ public class EdCRLSign { private static final String OID25519 = "OID.1.3.101.112"; private static final String OIDN448 = "1.3.101.113"; private static final String OID448 = "OID.1.3.101.113"; - private static final String PROVIDER = "SunEC"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunEC"); private static final SecureRandom S_RND = new SecureRandom(new byte[]{0x1}); public static void main(String[] args) throws Exception { diff --git a/test/jdk/sun/security/ec/ed/EdDSAKeyCompatibility.java b/test/jdk/sun/security/ec/ed/EdDSAKeyCompatibility.java index 4240ec5347762..f3796073b7143 100644 --- a/test/jdk/sun/security/ec/ed/EdDSAKeyCompatibility.java +++ b/test/jdk/sun/security/ec/ed/EdDSAKeyCompatibility.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 @@ -54,7 +54,7 @@ public class EdDSAKeyCompatibility { private static final String EDDSA = "EdDSA"; private static final String ED25519 = "Ed25519"; private static final String ED448 = "Ed448"; - private static final String PROVIDER = "SunEC"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunEC"); public static void main(String[] args) throws Exception { diff --git a/test/jdk/sun/security/ec/ed/EdDSAKeySize.java b/test/jdk/sun/security/ec/ed/EdDSAKeySize.java index d5a6bec6f5a68..8cb207c8fe257 100644 --- a/test/jdk/sun/security/ec/ed/EdDSAKeySize.java +++ b/test/jdk/sun/security/ec/ed/EdDSAKeySize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ public class EdDSAKeySize { private static final String OID25519 = "OID.1.3.101.112"; private static final String OIDN448 = "1.3.101.113"; private static final String OID448 = "OID.1.3.101.113"; - private static final String PROVIDER = "SunEC"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunEC"); private static final SecureRandom RND = new SecureRandom(new byte[]{0x1}); public static void main(String[] args) throws Exception { diff --git a/test/jdk/sun/security/ec/ed/EdDSANegativeTest.java b/test/jdk/sun/security/ec/ed/EdDSANegativeTest.java index c03249e8553c6..ba45be6757555 100644 --- a/test/jdk/sun/security/ec/ed/EdDSANegativeTest.java +++ b/test/jdk/sun/security/ec/ed/EdDSANegativeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ public class EdDSANegativeTest { private static final String EDDSA = "EdDSA"; private static final String ED25519 = "Ed25519"; private static final String ED448 = "Ed448"; - private static final String PROVIDER = "SunEC"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunEC"); private static final String OTHER = "other"; private static final byte[] MSG = "TEST".getBytes(); diff --git a/test/jdk/sun/security/ec/ed/EdDSAParamSpec.java b/test/jdk/sun/security/ec/ed/EdDSAParamSpec.java index 046134f220d9c..b13f51a74a7e9 100644 --- a/test/jdk/sun/security/ec/ed/EdDSAParamSpec.java +++ b/test/jdk/sun/security/ec/ed/EdDSAParamSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ public class EdDSAParamSpec { private static final String EDDSA = "EdDSA"; private static final String ED25519 = "Ed25519"; private static final String ED448 = "Ed448"; - private static final String PROVIDER = "SunEC"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunEC"); private static final byte[] MSG = "TEST".getBytes(); private static final SecureRandom RND = new SecureRandom(new byte[]{0x1}); diff --git a/test/jdk/sun/security/ec/ed/EdDSAReuseTest.java b/test/jdk/sun/security/ec/ed/EdDSAReuseTest.java index bebabb8539f21..9e40b5725139f 100644 --- a/test/jdk/sun/security/ec/ed/EdDSAReuseTest.java +++ b/test/jdk/sun/security/ec/ed/EdDSAReuseTest.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 @@ -42,7 +42,7 @@ public class EdDSAReuseTest { private static final String EDDSA = "EdDSA"; private static final String ED25519 = "Ed25519"; private static final String ED448 = "Ed448"; - private static final String PROVIDER = "SunEC"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunEC"); private static final String MSG = "TEST"; private static final int REUSE = 20; private static final int ONCE = 1; diff --git a/test/jdk/sun/security/ec/ed/EdDSATest.java b/test/jdk/sun/security/ec/ed/EdDSATest.java index 5ba06b8970a1d..c154bca42520c 100644 --- a/test/jdk/sun/security/ec/ed/EdDSATest.java +++ b/test/jdk/sun/security/ec/ed/EdDSATest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,7 +68,7 @@ public class EdDSATest { private static final String OID25519 = "OID.1.3.101.112"; private static final String OIDN448 = "1.3.101.113"; private static final String OID448 = "OID.1.3.101.113"; - private static final String PROVIDER = "SunEC"; + private static final String PROVIDER = System.getProperty("test.provider.name", "SunEC"); private static final byte[] MSG = "TEST".getBytes(); private static final SecureRandom S_RND = new SecureRandom(new byte[]{0x1}); diff --git a/test/jdk/sun/security/ec/ed/TestEdDSA.java b/test/jdk/sun/security/ec/ed/TestEdDSA.java index 511d92ab997e1..1990638496f8f 100644 --- a/test/jdk/sun/security/ec/ed/TestEdDSA.java +++ b/test/jdk/sun/security/ec/ed/TestEdDSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -462,10 +462,14 @@ private static void runBasicTest(String name, Object param) * when the algorithm ID for a specific curve is specified. */ private static void runCurveMixTest() throws Exception { - runCurveMixTest("SunEC", "Ed25519", 448); - runCurveMixTest("SunEC", "Ed25519", "Ed448"); - runCurveMixTest("SunEC", "Ed448", 255); - runCurveMixTest("SunEC", "Ed448", "Ed25519"); + runCurveMixTest(System.getProperty("test.provider.name", "SunEC"), + "Ed25519", 448); + runCurveMixTest(System.getProperty("test.provider.name", "SunEC"), + "Ed25519", "Ed448"); + runCurveMixTest(System.getProperty("test.provider.name", "SunEC"), + "Ed448", 255); + runCurveMixTest(System.getProperty("test.provider.name", "SunEC"), + "Ed448", "Ed25519"); } private static void runCurveMixTest(String providerName, String name, diff --git a/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java b/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java index 58bcbe9115394..cd74b5164d3ef 100644 --- a/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java +++ b/test/jdk/sun/security/jca/PreferredProviderNegativeTest.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 @@ -107,7 +107,7 @@ public static void main(String[] args) String expected; String value = args[1]; - expected = "SunJCE"; + expected = System.getProperty("test.provider.name", "SunJCE"); if (args.length >= 2) { switch (args[0]) { diff --git a/test/jdk/sun/security/mscapi/InteropWithSunRsaSign.java b/test/jdk/sun/security/mscapi/InteropWithSunRsaSign.java index cc01caca17c1d..1494c175c7a4e 100644 --- a/test/jdk/sun/security/mscapi/InteropWithSunRsaSign.java +++ b/test/jdk/sun/security/mscapi/InteropWithSunRsaSign.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,11 +103,13 @@ static void matrix(PSSParameterSpec pss) throws Exception { "-------", "----------------", "------", "--------", "------"); // KeyPairGenerator chooses SPI when getInstance() is called. - String[] provsForKPG = {"SunRsaSign", "SunMSCAPI"}; + String[] provsForKPG = {System.getProperty("test.provider.name", "SunRsaSign"), + "SunMSCAPI"}; // "-" means no preferred provider. In this case, SPI is chosen // when initSign/initVerify is called. Worth testing. - String[] provsForSignature = {"SunRsaSign", "SunMSCAPI", "-"}; + String[] provsForSignature = {System.getProperty("test.provider.name", "SunRsaSign"), + "SunMSCAPI", "-"}; int pos = 0; for (String pg : provsForKPG) { diff --git a/test/jdk/sun/security/pkcs/pkcs10/PKCS10AttrEncoding.java b/test/jdk/sun/security/pkcs/pkcs10/PKCS10AttrEncoding.java index 1e389eb613f13..9f3d72f89837b 100644 --- a/test/jdk/sun/security/pkcs/pkcs10/PKCS10AttrEncoding.java +++ b/test/jdk/sun/security/pkcs/pkcs10/PKCS10AttrEncoding.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 @@ -30,7 +30,8 @@ * java.base/sun.security.util * java.base/sun.security.x509 * @compile -XDignore.symbol.file PKCS10AttrEncoding.java - * @run main PKCS10AttrEncoding + * @run main PKCS10AttrEncoding DSA 512 + * @run main PKCS10AttrEncoding Sha256withDSA 2048 */ import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -69,11 +70,13 @@ public static void main(String[] args) throws Exception { constructedMap.put(ids[j], values[j]); } + String kpgAlgorithm = "DSA"; X500Name subject = new X500Name("cn=Test"); - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); - String sigAlg = "DSA"; + KeyPairGenerator keyGen = KeyPairGenerator.getInstance(kpgAlgorithm); + String sigAlg = args[0]; + int keySize = Integer.parseInt(args[1]); - keyGen.initialize(512); + keyGen.initialize(keySize); KeyPair pair = keyGen.generateKeyPair(); X509Key publicKey = (X509Key) pair.getPublic(); diff --git a/test/jdk/sun/security/pkcs/pkcs7/SignerOrder.java b/test/jdk/sun/security/pkcs/pkcs7/SignerOrder.java index 30f9392cfde65..7d8333e6aa547 100644 --- a/test/jdk/sun/security/pkcs/pkcs7/SignerOrder.java +++ b/test/jdk/sun/security/pkcs/pkcs7/SignerOrder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,8 @@ * @modules java.base/sun.security.pkcs * java.base/sun.security.util * java.base/sun.security.x509 - * @run main SignerOrder + * @run main SignerOrder default 1024 + * @run main SignerOrder Sha256 2048 */ import java.io.IOException; import java.math.BigInteger; @@ -62,20 +63,21 @@ public class SignerOrder { static final byte[] data1 = "12345".getBytes(); static final byte[] data2 = "abcde".getBytes(); - public static void main(String[] argv) throws Exception { - + public static void main(String[] args) throws Exception { + String digestAlg = "default".equals(args[0]) ? null : args[0]; + int keySize = Integer.parseInt(args[1]); SignerInfo[] signerInfos = new SignerInfo[9]; - SimpleSigner signer1 = new SimpleSigner(null, null, null, null); + SimpleSigner signer1 = new SimpleSigner(digestAlg, null, null, null, keySize); signerInfos[8] = signer1.genSignerInfo(data1); signerInfos[7] = signer1.genSignerInfo(new byte[]{}); signerInfos[6] = signer1.genSignerInfo(data2); - SimpleSigner signer2 = new SimpleSigner(null, null, null, null); + SimpleSigner signer2 = new SimpleSigner(digestAlg, null, null, null, keySize); signerInfos[5] = signer2.genSignerInfo(data1); signerInfos[4] = signer2.genSignerInfo(new byte[]{}); signerInfos[3] = signer2.genSignerInfo(data2); - SimpleSigner signer3 = new SimpleSigner(null, null, null, null); + SimpleSigner signer3 = new SimpleSigner(digestAlg, null, null, null, keySize); signerInfos[2] = signer3.genSignerInfo(data1); signerInfos[1] = signer3.genSignerInfo(new byte[]{}); signerInfos[0] = signer3.genSignerInfo(data2); @@ -156,28 +158,33 @@ class SimpleSigner { public SimpleSigner(String digestAlg, String encryptionAlg, KeyPair keyPair, - X500Name agent) throws Exception { + X500Name agent, + int keySize) throws Exception { + String signAlgoDigest; if (agent == null) { agent = new X500Name("cn=test"); } - if (digestAlg == null) { - digestAlg = "SHA"; - } if (encryptionAlg == null) { encryptionAlg = "DSA"; } + if (digestAlg == null) { + digestAlg = "SHA"; + signAlgoDigest = encryptionAlg; + } else { + signAlgoDigest = digestAlg + "with" + encryptionAlg; + } if (keyPair == null) { KeyPairGenerator keyGen = KeyPairGenerator.getInstance(encryptionAlg); - keyGen.initialize(1024); + keyGen.initialize(keySize); keyPair = keyGen.generateKeyPair(); } publicKey = (X509Key) keyPair.getPublic(); privateKey = keyPair.getPrivate(); if ("DSA".equals(encryptionAlg)) { - this.sig = Signature.getInstance(encryptionAlg); + this.sig = Signature.getInstance(signAlgoDigest); } else { // RSA this.sig = Signature.getInstance(digestAlg + "/" + encryptionAlg); } diff --git a/test/jdk/sun/security/pkcs/pkcs8/TestLeadingZeros.java b/test/jdk/sun/security/pkcs/pkcs8/TestLeadingZeros.java index 92a204501571d..4291f4e25c171 100644 --- a/test/jdk/sun/security/pkcs/pkcs8/TestLeadingZeros.java +++ b/test/jdk/sun/security/pkcs/pkcs8/TestLeadingZeros.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 @@ -50,7 +50,8 @@ public class TestLeadingZeros { }; public static void main(String[] argv) throws Exception { - KeyFactory factory = KeyFactory.getInstance("DSA", "SUN"); + KeyFactory factory = KeyFactory.getInstance("DSA", + System.getProperty("test.provider.name", "SUN")); for (String encodings : PKCS8_ENCODINGS) { byte[] encodingBytes = hexToBytes(encodings); diff --git a/test/jdk/sun/security/pkcs11/Cipher/EncryptionPadding.java b/test/jdk/sun/security/pkcs11/Cipher/EncryptionPadding.java index 8757c0bab7a9c..7e1f0561f6cd7 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/EncryptionPadding.java +++ b/test/jdk/sun/security/pkcs11/Cipher/EncryptionPadding.java @@ -93,9 +93,10 @@ private static void testWithInputSize(Provider p, int inputSize, sunPKCS11cipher.doFinal(ByteBuffer.allocate(0), cipherText); } - Cipher sunJCECipher = Cipher.getInstance(transformation, "SunJCE"); - sunJCECipher.init(Cipher.DECRYPT_MODE, key); - byte[] sunJCEPlain = sunJCECipher.doFinal(cipherText.array()); + Cipher providerCipher = Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); + providerCipher.init(Cipher.DECRYPT_MODE, key); + byte[] sunJCEPlain = providerCipher.doFinal(cipherText.array()); if (!Arrays.equals(plainText, sunJCEPlain)) { throw new Exception("Cross-provider cipher test failed."); diff --git a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java index e6724d38321d0..e1f32ea807655 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java +++ b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -259,9 +259,12 @@ public void testKeyWrap(String algo, String key, int keyLen, System.out.println("=> skip, exceeds max allowed size " + allowed); return; } - Cipher c1 = Cipher.getInstance(algo, "SunJCE"); - Cipher c2 = Cipher.getInstance(algo, "SunJCE"); - Cipher c3 = Cipher.getInstance(algo, "SunJCE"); + Cipher c1 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); + Cipher c2 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); + Cipher c3 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); byte[] keyVal = toBytes(key, keyLen << 1); byte[] dataVal = toBytes(data, dataLen << 1); @@ -319,9 +322,12 @@ public void testEnc(String algo, String key, int keyLen, String data, System.out.println("=> skip, exceeds max allowed size " + allowed); return; } - Cipher c1 = Cipher.getInstance(algo, "SunJCE"); - Cipher c2 = Cipher.getInstance(algo, "SunJCE"); - Cipher c3 = Cipher.getInstance(algo, "SunJCE"); + Cipher c1 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); + Cipher c2 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); + Cipher c3 = Cipher.getInstance(algo, + System.getProperty("test.provider.name", "SunJCE")); byte[] keyVal = toBytes(key, keyLen << 1); byte[] dataVal = toBytes(data, dataLen << 1); diff --git a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java index 7ff5ec6563bd2..0cfb4557572c4 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java +++ b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,7 +245,8 @@ public void main(Provider p) throws Exception { SecretKey aes256 = new SecretKeySpec(DATA_32, "AES"); SecretKey any256 = new SecretKeySpec(DATA_32, "ANY"); PrivateKey priv = KeyPairGenerator.getInstance - ("RSA", "SunRsaSign").generateKeyPair().getPrivate(); + ("RSA", System.getProperty("test.provider.name","SunRsaSign")) + .generateKeyPair().getPrivate(); String[] algos = { "AES/KW/PKCS5Padding", "AES/KW/NoPadding", "AES/KWP/NoPadding" diff --git a/test/jdk/sun/security/pkcs11/Cipher/PBECipher.java b/test/jdk/sun/security/pkcs11/Cipher/PBECipher.java index 04e9adf966383..242d09f6e9bf7 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/PBECipher.java +++ b/test/jdk/sun/security/pkcs11/Cipher/PBECipher.java @@ -75,7 +75,8 @@ private enum Configuration { AnonymousPBEKey, } - private static Provider sunJCE = Security.getProvider("SunJCE"); + private static Provider sunJCE = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); private record AssertionData(String pbeCipherAlgo, String cipherAlgo, BigInteger expectedCiphertext) {} diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java b/test/jdk/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java index d192526bf4bdc..cf8e000fce7e2 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018, 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 @@ -78,7 +78,7 @@ public void main(Provider p) throws Exception { KeyGenerator.getInstance(currTest.keyAlgo, p); SecretKey key = kg.generateKey(); Cipher c1 = Cipher.getInstance(currTest.transformation, - "SunJCE"); + System.getProperty("test.provider.name", "SunJCE")); c1.init(Cipher.ENCRYPT_MODE, key); byte[] cipherText = c1.doFinal(plainText); AlgorithmParameters params = c1.getParameters(); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java index 233cb4e623e74..6799b19d3e7ce 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; +import jdk.test.lib.security.SecurityUtils; public class TestRSACipher extends PKCS11Test { @@ -58,8 +59,10 @@ public void main(Provider p) throws Exception { System.out.println("Not supported by provider, skipping"); return; } - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", p); - kpg.initialize(1024); + String kpgAlgorithm = "RSA"; + int keySize = SecurityUtils.getTestKeySize(kpgAlgorithm); + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, p); + kpg.initialize(keySize); KeyPair kp = kpg.generateKeyPair(); PublicKey publicKey = kp.getPublic(); PrivateKey privateKey = kp.getPrivate(); @@ -70,7 +73,8 @@ public void main(Provider p) throws Exception { for (String rsaAlgo: RSA_ALGOS) { Cipher c1 = Cipher.getInstance(rsaAlgo, p); - Cipher c2 = Cipher.getInstance(rsaAlgo, "SunJCE"); + Cipher c2 = Cipher.getInstance(rsaAlgo, + System.getProperty("test.provider.name", "SunJCE")); c1.init(Cipher.ENCRYPT_MODE, publicKey); e = c1.doFinal(b); @@ -112,7 +116,8 @@ public void main(Provider p) throws Exception { c1.update(b); e = c1.doFinal(); - c1.update(new byte[256]); + // Longer buffer size to verify IllegalBlockSizeException is thrown + c1.update(new byte[keySize / 4]); try { e = c1.doFinal(); throw new Exception("completed call"); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java index 7191d5baac5ba..0be916ebf9e72 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.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 @@ -43,6 +43,7 @@ import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; +import jdk.test.lib.security.SecurityUtils; public class TestRSACipherWrap extends PKCS11Test { @@ -57,13 +58,15 @@ public void main(Provider p) throws Exception { System.out.println(RSA_ALGOS[0] + " unsupported, skipping"); return; } - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", p); - kpg.initialize(1024); + String kpgAlgorithm = "RSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, p); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair kp = kpg.generateKeyPair(); for (String rsaAlgo: RSA_ALGOS) { Cipher cipherPKCS11 = Cipher.getInstance(rsaAlgo, p); - Cipher cipherJce = Cipher.getInstance(rsaAlgo, "SunJCE"); + Cipher cipherJce = Cipher.getInstance(rsaAlgo, + System.getProperty("test.provider.name", "SunJCE")); String algos[] = {"AES", "RC2", "Blowfish"}; int keySizes[] = {128, 256}; diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java b/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java index 9eceea3a39438..fe6433d096e32 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.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 @@ -41,6 +41,7 @@ import java.util.HexFormat; import java.util.Random; import javax.crypto.Cipher; +import jdk.test.lib.security.SecurityUtils; public class TestRawRSACipher extends PKCS11Test { @@ -53,8 +54,9 @@ public void main(Provider p) throws Exception { return; } - final int KEY_LEN = 1024; - KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", p); + String kpgAlgorithm = "RSA"; + final int KEY_LEN = SecurityUtils.getTestKeySize(kpgAlgorithm); + KeyPairGenerator kpGen = KeyPairGenerator.getInstance(kpgAlgorithm, p); kpGen.initialize(KEY_LEN); KeyPair kp = kpGen.generateKeyPair(); Random random = new Random(); @@ -64,7 +66,8 @@ public void main(Provider p) throws Exception { plainText[0] = 0; // to ensure that it's less than modulus Cipher c1 = Cipher.getInstance("RSA/ECB/NoPadding", p); - Cipher c2 = Cipher.getInstance("RSA/ECB/NoPadding", "SunJCE"); + Cipher c2 = Cipher.getInstance("RSA/ECB/NoPadding", + System.getProperty("test.provider.name", "SunJCE")); c1.init(Cipher.ENCRYPT_MODE, kp.getPublic()); c2.init(Cipher.DECRYPT_MODE, kp.getPrivate()); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java index e0a7d53e1c1a6..2395b329dd650 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java @@ -103,7 +103,7 @@ public void main(Provider p) throws Exception { SecretKey key = kg.generateKey(); Cipher c1 = Cipher.getInstance(currTest.transformation, p); Cipher c2 = Cipher.getInstance(currTest.transformation, - "SunJCE"); + System.getProperty("test.provider.name", "SunJCE")); byte[] plainTxt = new byte[currTest.dataSize]; random.nextBytes(plainTxt); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java index 2288a5699fb34..7505c21a1ab05 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java @@ -89,7 +89,7 @@ public void main(Provider p) throws Exception { SecretKey key = kg.generateKey(); Cipher c1 = Cipher.getInstance(currTest.transformation, p); Cipher c2 = Cipher.getInstance(currTest.transformation, - "SunJCE"); + System.getProperty("test.provider.name", "SunJCE")); byte[] plainTxt = new byte[currTest.dataSize]; random.nextBytes(plainTxt); diff --git a/test/jdk/sun/security/pkcs11/KeyAgreement/TestDH.java b/test/jdk/sun/security/pkcs11/KeyAgreement/TestDH.java index d5569f0f3cd7b..13b09d16dcf62 100644 --- a/test/jdk/sun/security/pkcs11/KeyAgreement/TestDH.java +++ b/test/jdk/sun/security/pkcs11/KeyAgreement/TestDH.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import java.util.Arrays; import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; +import jdk.test.lib.security.SecurityUtils; public class TestDH extends PKCS11Test { @@ -47,8 +48,9 @@ public void main(Provider p) throws Exception { System.out.println("DH not supported, skipping"); return; } - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", p); - kpg.initialize(512); + String kpgAlgorithm = "DH"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, p); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair kp1 = kpg.generateKeyPair(); KeyPair kp2 = kpg.generateKeyPair(); @@ -68,7 +70,8 @@ public void main(Provider p) throws Exception { throw new Exception("Secrets (1,2) do not match"); } - ka2 = KeyAgreement.getInstance("DH", "SunJCE"); + ka2 = KeyAgreement.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); ka2.init(kp1.getPrivate()); ka2.doPhase(kp2.getPublic(), true); System.out.println("Derive 3..."); @@ -101,7 +104,8 @@ private static void testAlgorithm(KeyAgreement ka1, KeyPair kp1, ka1.init(kp1.getPrivate()); ka1.doPhase(kp2.getPublic(), true); - System.out.println("Derive " + algorithm + " using SunJCE..."); + System.out.println("Derive " + algorithm + " using " + + System.getProperty("test.provider.name", "SunJCE") + "..."); key1 = ka1.generateSecret(algorithm); ka2.init(kp1.getPrivate()); diff --git a/test/jdk/sun/security/pkcs11/KeyAgreement/TestInterop.java b/test/jdk/sun/security/pkcs11/KeyAgreement/TestInterop.java index 146a650542329..7f6f79e767b55 100644 --- a/test/jdk/sun/security/pkcs11/KeyAgreement/TestInterop.java +++ b/test/jdk/sun/security/pkcs11/KeyAgreement/TestInterop.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 @@ -39,43 +39,40 @@ import javax.crypto.KeyAgreement; import javax.crypto.spec.DHPrivateKeySpec; import javax.crypto.spec.DHPublicKeySpec; +import jdk.test.lib.security.DiffieHellmanGroup; +import jdk.test.lib.security.SecurityUtils; public class TestInterop extends PKCS11Test { - private final static BigInteger p = new BigInteger - ("171718397966129586011229151993178480901904202533705695869569760169920539" - + "80807543778874708672297590042574075430109846864794139516459381007417046" - + "27996080624930219892858374168155487210358743785481212360509485282294161" - + "39585571568998066586304075565145536350296006867635076744949977849997684" - + "222020336013226588207303"); - - private final static BigInteger g = new BigInteger("2"); - private final static BigInteger ya = new BigInteger - ("687709211571508809414670982463565909269384277848448625781941269577397703" - + "73675199968849153119146758339814638228795348558483510369322822476757204" - + "22158455966026517829008713407587339322132253724742557954802911059639161" - + "24827916158465757962384625410294483756242900146397201260757102085985457" - + "09397033481077351036224"); + ("22272412859242949963897309866268099957623364986192222381531147912319" + + "23153170556019072276127184001075566033823724518300406542189341984" + + "14728033901164887842157675409022004721268960808255834930605035809" + + "96449867261598768663006346373969582073599358922631400907241847771" + + "58539394502794451638884093173505103869438428833148912071609829581" + + "89477284513896649100113024962862016311693389603523142235630316916" + + "51727812401021776761600004971782662420311224757086651213529674905" + + "34921437167341469749945865459714558842881915928697452568830704027" + + "08840053484115995358953663434943150292283157101600109003253293611" + + "67575903571371898272633920086"); private final static BigInteger xa = new BigInteger - ("104917367119952955556289227181599819745346393858545449202252025137706135" - + "98100778613457655440586438263591136003106529323555991109623536177695714" - + "66884181531401472902830508361532232717792847436112280721439936797741371" - + "245140912614191507"); + ("20959988947516815975588968321965141642005944293655257916834342975849"); private final static BigInteger yb = new BigInteger - ("163887874871842952463100699681506173424091615364591742415764095471629919" - + "08421025296419917755446931473037086355546823601999684501737493240373415" - + "65608293667837249198973539289354492348897732633852665609611113031379864" - + "58514616034107537409230452318065341748503347627733368519091332060477528" - + "173423377887175351037810"); + ("1788841814501653834923092375117807364896992833810838802030127811094" + + "8450381275318704655838368105000403140578033341448162321874634765" + + "6870663019881556386613144025875613921737258766185138415793010195" + + "3802511267742963370821568963965936108932734114202964873644126233" + + "6937947954023458790417933403303562491144788202839815534782475160" + + "7813094179390506418017926774832227342290968359943612529948409558" + + "4647213355501260440663649115694263879691520265343063263385211121" + + "3396751542827391711077192604441343359832896902306354119121777576" + + "6479255602858536672821464920683781338851326155035757018336622673" + + "39973666608754923308482789421630138499"); private final static BigInteger xb = new BigInteger - ("127757517533485947079959908591028646859165238853082197617179368337276371" - + "51601819447716934542027725311863797141734616730248519214531856941516613" - + "30313414180008978013330410484011186019824874948204261839391153650949864" - + "429505597086564709"); + ("37339373137107550077381337769340105015086522284791968753218309293526"); @Override public void main(Provider prov) throws Exception { @@ -90,14 +87,20 @@ public void main(Provider prov) throws Exception { DHPrivateKeySpec privateSpec; KeyFactory kf = KeyFactory.getInstance("DH"); KeyAgreement ka = KeyAgreement.getInstance("DH", prov); - KeyAgreement kbSunJCE = KeyAgreement.getInstance("DH", "SunJCE"); - DHPrivateKeySpec privSpecA = new DHPrivateKeySpec(xa, p, g); - DHPublicKeySpec pubSpecA = new DHPublicKeySpec(ya, p, g); + KeyAgreement kbSunJCE = KeyAgreement.getInstance("DH", + System.getProperty("test.provider.name", "SunJCE")); + DiffieHellmanGroup dhGroup = SecurityUtils.getTestDHGroup(); + DHPrivateKeySpec privSpecA = new DHPrivateKeySpec(xa, dhGroup.getPrime(), + dhGroup.getBase()); + DHPublicKeySpec pubSpecA = new DHPublicKeySpec(ya, dhGroup.getPrime(), + dhGroup.getBase()); PrivateKey privA = kf.generatePrivate(privSpecA); PublicKey pubA = kf.generatePublic(pubSpecA); - DHPrivateKeySpec privSpecB = new DHPrivateKeySpec(xb, p, g); - DHPublicKeySpec pubSpecB = new DHPublicKeySpec(yb, p, g); + DHPrivateKeySpec privSpecB = new DHPrivateKeySpec(xb, dhGroup.getPrime(), + dhGroup.getBase()); + DHPublicKeySpec pubSpecB = new DHPublicKeySpec(yb, dhGroup.getPrime(), + dhGroup.getBase()); PrivateKey privB = kf.generatePrivate(privSpecB); PublicKey pubB = kf.generatePublic(pubSpecB); @@ -109,6 +112,10 @@ public void main(Provider prov) throws Exception { kbSunJCE.doPhase(pubA, true); byte[] n2 = kbSunJCE.generateSecret(); + // verify that a leading zero is present in secrets + if (n1[0] != 0 || n2[0] != 0) { + throw new Exception("First byte is not zero as expected"); + } if (Arrays.equals(n1, n2) == false) { throw new Exception("values mismatch!"); } else { diff --git a/test/jdk/sun/security/pkcs11/KeyStore/Basic.java b/test/jdk/sun/security/pkcs11/KeyStore/Basic.java index 0ac7f37d59ce9..b6c7af91b57a3 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/Basic.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -142,7 +142,8 @@ public void main(Provider p) throws Exception { // get private keys KeyFactory kf = KeyFactory.getInstance("RSA"); - KeyFactory dsaKf = KeyFactory.getInstance("DSA", "SUN"); + KeyFactory dsaKf = KeyFactory.getInstance("DSA", + System.getProperty("test.provider.name", "SUN")); ObjectInputStream ois1 = new ObjectInputStream (new FileInputStream(new File(DIR, "pk1.key"))); diff --git a/test/jdk/sun/security/pkcs11/Mac/PBAMac.java b/test/jdk/sun/security/pkcs11/Mac/PBAMac.java index d0b3312c52bc4..c9b5e2c3e7bcc 100644 --- a/test/jdk/sun/security/pkcs11/Mac/PBAMac.java +++ b/test/jdk/sun/security/pkcs11/Mac/PBAMac.java @@ -66,7 +66,8 @@ private enum Configuration { AnonymousPBEKey, } - private static Provider sunJCE = Security.getProvider("SunJCE"); + private static Provider sunJCE = Security.getProvider( + System.getProperty("test.provider.name", "SunJCE")); private record AssertionData(String pbeHmacAlgo, String hmacAlgo, BigInteger expectedMac) {} diff --git a/test/jdk/sun/security/pkcs11/MessageDigest/ReinitDigest.java b/test/jdk/sun/security/pkcs11/MessageDigest/ReinitDigest.java index 132ba84f6795b..90ed49b42f539 100644 --- a/test/jdk/sun/security/pkcs11/MessageDigest/ReinitDigest.java +++ b/test/jdk/sun/security/pkcs11/MessageDigest/ReinitDigest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -73,7 +73,8 @@ public void main(Provider p) throws Exception { private void doTest(String alg, Provider p, byte[] data1, byte[] data2) throws Exception { System.out.println("Testing " + alg); - MessageDigest md1 = MessageDigest.getInstance(alg, "SUN"); + MessageDigest md1 = MessageDigest.getInstance(alg, + System.getProperty("test.provider.name", "SUN")); byte[] d1 = md1.digest(data1); MessageDigest md2 = MessageDigest.getInstance(alg, p); checkInstances(md1, md2); diff --git a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java index 1114702277179..d5b22400bffef 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 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 @@ -59,7 +59,8 @@ public void main(Provider p) throws Exception { } Signature sigSunRsaSign = - Signature.getInstance("RSASSA-PSS", "SunRsaSign"); + Signature.getInstance("RSASSA-PSS", + System.getProperty("test.provider.name", "SunRsaSign")); KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", p); kpg.initialize(3072); diff --git a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java index c15f10aab3ee6..dfe561678486e 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java +++ b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java @@ -51,8 +51,9 @@ public static void main(String[] args) throws Exception { @Override public void main(Provider p) throws Exception { - Provider sunRsaSign = Security.getProvider("SunRsaSign"); - Security.removeProvider("SunRsaSign"); + String providerName = System.getProperty("test.provider.name", "SunRsaSign"); + Provider sunRsaSign = Security.getProvider(providerName); + Security.removeProvider(providerName); Signature sigPkcs11; Signature sigSunRsaSign = diff --git a/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java b/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java index b2ab96c90c62a..d2515fa0f5a28 100644 --- a/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java +++ b/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java @@ -62,7 +62,8 @@ protected boolean skipTest(Provider provider) { @Override public void main(Provider provider) throws Exception { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", "SUN"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", + System.getProperty("test.provider.name", "SUN")); kpg.initialize(2048, new SecureRandom()); KeyPair pair = kpg.generateKeyPair(); diff --git a/test/jdk/sun/security/pkcs11/policy b/test/jdk/sun/security/pkcs11/policy index 54281a7817945..d5a78b6ba8279 100644 --- a/test/jdk/sun/security/pkcs11/policy +++ b/test/jdk/sun/security/pkcs11/policy @@ -1,3 +1,4 @@ grant { permission java.lang.RuntimePermission "setSecurityManager"; -}; \ No newline at end of file + permission java.util.PropertyPermission "test.provider.name", "read"; +}; diff --git a/test/jdk/sun/security/pkcs11/rsa/GenKeyStore.java b/test/jdk/sun/security/pkcs11/rsa/GenKeyStore.java index 629a504a04082..26178e9a576ad 100644 --- a/test/jdk/sun/security/pkcs11/rsa/GenKeyStore.java +++ b/test/jdk/sun/security/pkcs11/rsa/GenKeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 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 @@ -74,7 +74,8 @@ private static void addToKeyStore(KeyStore ks, KeyPair kp, String name) throws E private static void generateKeyPair(KeyStore ks, int keyLength, String alias) throws Exception { System.out.println("Generating " + keyLength + " keypair " + alias + "..."); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SunRsaSign"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", + System.getProperty("test.provider.name", "SunRsaSign")); kpg.initialize(keyLength); KeyPair kp = kpg.generateKeyPair(); addToKeyStore(ks, kp, alias); diff --git a/test/jdk/sun/security/pkcs11/rsa/rsakeys.ks.policy b/test/jdk/sun/security/pkcs11/rsa/rsakeys.ks.policy index 4a0b0d2c46dc5..6cc9a8f0248ad 100644 --- a/test/jdk/sun/security/pkcs11/rsa/rsakeys.ks.policy +++ b/test/jdk/sun/security/pkcs11/rsa/rsakeys.ks.policy @@ -1,4 +1,5 @@ grant { permission java.lang.RuntimePermission "setSecurityManager"; permission java.io.FilePermission "${test.src}/rsakeys.ks", "read"; -}; \ No newline at end of file + permission java.util.PropertyPermission "test.provider.name", "read"; +}; diff --git a/test/jdk/sun/security/provider/DSA/SupportedDSAParamGen.java b/test/jdk/sun/security/provider/DSA/SupportedDSAParamGen.java index 52a97b34a3e93..5dcd86e247404 100644 --- a/test/jdk/sun/security/provider/DSA/SupportedDSAParamGen.java +++ b/test/jdk/sun/security/provider/DSA/SupportedDSAParamGen.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 @@ -40,7 +40,8 @@ public class SupportedDSAParamGen { public static void main(String[] args) throws Exception { AlgorithmParameterGenerator apg = - AlgorithmParameterGenerator.getInstance("DSA", "SUN"); + AlgorithmParameterGenerator.getInstance("DSA", + System.getProperty("test.provider.name", "SUN")); DSAGenParameterSpec spec = new DSAGenParameterSpec( Integer.valueOf(args[0]).intValue(), diff --git a/test/jdk/sun/security/provider/DSA/TestAlgParameterGenerator.java b/test/jdk/sun/security/provider/DSA/TestAlgParameterGenerator.java index cf39a5bab5e2a..2eac80d91bb6a 100644 --- a/test/jdk/sun/security/provider/DSA/TestAlgParameterGenerator.java +++ b/test/jdk/sun/security/provider/DSA/TestAlgParameterGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, 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 @@ -73,7 +73,8 @@ private static void checkParamStrength(AlgorithmParameters param, public static void main(String[] args) throws Exception { AlgorithmParameterGenerator apg - = AlgorithmParameterGenerator.getInstance("DSA", "SUN"); + = AlgorithmParameterGenerator.getInstance("DSA", + System.getProperty("test.provider.name", "SUN")); long start, stop; // make sure no-init still works diff --git a/test/jdk/sun/security/provider/DSA/TestDSA.java b/test/jdk/sun/security/provider/DSA/TestDSA.java index 5d3228949f5cd..918f18ed08185 100644 --- a/test/jdk/sun/security/provider/DSA/TestDSA.java +++ b/test/jdk/sun/security/provider/DSA/TestDSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -108,7 +108,7 @@ private static void verify(Provider provider, String alg, PublicKey key, byte[] public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); - Provider provider = Security.getProvider("SUN"); + Provider provider = Security.getProvider(System.getProperty("test.provider.name", "SUN")); System.out.println("Testing provider " + provider + "..."); KeyFactory kf = KeyFactory.getInstance("DSA", provider); diff --git a/test/jdk/sun/security/provider/DSA/TestDSA2.java b/test/jdk/sun/security/provider/DSA/TestDSA2.java index 320acce488042..ed3111695f112 100644 --- a/test/jdk/sun/security/provider/DSA/TestDSA2.java +++ b/test/jdk/sun/security/provider/DSA/TestDSA2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,8 @@ public class TestDSA2 { // NOTE: need to explictly specify provider since the more // preferred provider SunPKCS11 provider only supports up // 1024 bits. - private static final String PROV = "SUN"; + private static final String PROV = + System.getProperty("test.provider.name", "SUN"); private static final String[] SIG_ALGOS = { "NONEwithDSA", diff --git a/test/jdk/sun/security/provider/DSA/TestKeyPairGenerator.java b/test/jdk/sun/security/provider/DSA/TestKeyPairGenerator.java index 105c50015dac8..f2ddcec9d8d44 100644 --- a/test/jdk/sun/security/provider/DSA/TestKeyPairGenerator.java +++ b/test/jdk/sun/security/provider/DSA/TestKeyPairGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, 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 @@ -57,10 +57,12 @@ public static void main(String[] args) throws Exception { // problem was when not calling initialize() // do that twice to artifically inflate the time // on JDKs that do not have the fix - kpg = KeyPairGenerator.getInstance("DSA", "SUN"); + kpg = KeyPairGenerator.getInstance("DSA", + System.getProperty("test.provider.name", "SUN")); kp = kpg.generateKeyPair(); - kpg = KeyPairGenerator.getInstance("DSA", "SUN"); + kpg = KeyPairGenerator.getInstance("DSA", + System.getProperty("test.provider.name", "SUN")); kp = kpg.generateKeyPair(); // some other basic tests diff --git a/test/jdk/sun/security/provider/KeyStore/CaseSensitiveAliases.java b/test/jdk/sun/security/provider/KeyStore/CaseSensitiveAliases.java index e11a8ac87dce9..fd47d0ac60fa2 100644 --- a/test/jdk/sun/security/provider/KeyStore/CaseSensitiveAliases.java +++ b/test/jdk/sun/security/provider/KeyStore/CaseSensitiveAliases.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 5091374 5100603 + * @library /test/lib * @summary make sure the JKS case sensitivity works correctly * @author Andreas Sterbenz */ @@ -34,6 +35,7 @@ import java.security.*; import java.security.cert.*; import java.security.cert.Certificate; +import jdk.test.lib.security.SecurityUtils; public class CaseSensitiveAliases { @@ -90,8 +92,9 @@ private static void main(String jks, boolean caseInsensitive) throws Exception { X509Certificate[] a1 = {c1}; X509Certificate[] a2 = {c2}; - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); - kpg.initialize(512); + String kpgAlgorithm = "RSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); PrivateKey p1 = kpg.generateKeyPair().getPrivate(); PrivateKey p2 = kpg.generateKeyPair().getPrivate(); diff --git a/test/jdk/sun/security/provider/MessageDigest/DigestKAT.java b/test/jdk/sun/security/provider/MessageDigest/DigestKAT.java index 1f797330c4811..ce3c9b3c7a95e 100644 --- a/test/jdk/sun/security/provider/MessageDigest/DigestKAT.java +++ b/test/jdk/sun/security/provider/MessageDigest/DigestKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -177,7 +177,7 @@ private static Test t(String alg, byte[] data, String digest) { static void runTests(Test[] tests) throws Exception { long start = System.currentTimeMillis(); - Provider p = Security.getProvider("SUN"); + Provider p = Security.getProvider(System.getProperty("test.provider.name","SUN")); System.out.println("Testing provider " + p.getName() + "..."); for (int i = 0; i < tests.length; i++) { Test test = tests[i]; diff --git a/test/jdk/sun/security/provider/MessageDigest/Offsets.java b/test/jdk/sun/security/provider/MessageDigest/Offsets.java index 44850c2970d5d..2c800fcb854b0 100644 --- a/test/jdk/sun/security/provider/MessageDigest/Offsets.java +++ b/test/jdk/sun/security/provider/MessageDigest/Offsets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2016, 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 @@ -47,7 +47,8 @@ private static void outOfBounds(MessageDigest md, int arrayLen, int ofs, int len private static void test(String algorithm, int minOfs, int maxOfs, int minLen, int maxLen) throws Exception { Random random = new Random(); - MessageDigest md = MessageDigest.getInstance(algorithm, "SUN"); + MessageDigest md = MessageDigest.getInstance(algorithm, + System.getProperty("test.provider.name", "SUN")); System.out.println("Testing " + algorithm + "..."); outOfBounds(md, 16, 0, 32); outOfBounds(md, 16, -8, 16); diff --git a/test/jdk/sun/security/provider/MessageDigest/TestSHAClone.java b/test/jdk/sun/security/provider/MessageDigest/TestSHAClone.java index ac809153b3961..28c2dd6fb772d 100644 --- a/test/jdk/sun/security/provider/MessageDigest/TestSHAClone.java +++ b/test/jdk/sun/security/provider/MessageDigest/TestSHAClone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, 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 @@ -75,7 +75,8 @@ private void run() throws Exception { public static void main(String[] argv) throws Exception { - Provider p = Security.getProvider("SUN"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SUN")); for (int i=0; i DATA = Arrays.asList( diff --git a/test/jdk/sun/security/provider/NSASuiteB/TestSHAwithDSASignatureOids.java b/test/jdk/sun/security/provider/NSASuiteB/TestSHAwithDSASignatureOids.java index dad84ccfd7eb1..c7f1ce75ca4d0 100644 --- a/test/jdk/sun/security/provider/NSASuiteB/TestSHAwithDSASignatureOids.java +++ b/test/jdk/sun/security/provider/NSASuiteB/TestSHAwithDSASignatureOids.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,12 @@ import java.util.Arrays; import java.util.List; +import jdk.test.lib.security.SecurityUtils; /* * @test * @bug 8075286 + * @library /test/lib * @summary Test the SHAwithDSA signature algorithm OIDs in JDK. * OID and algorithm transformation string should match. * Both could be able to be used to generate the algorithm instance. @@ -40,8 +42,10 @@ public class TestSHAwithDSASignatureOids { new OidAlgorithmPair("2.16.840.1.101.3.4.3.2", "SHA256withDSA")); public static void main(String[] args) throws Exception { - TestSignatureOidHelper helper = new TestSignatureOidHelper("DSA", - "SUN", 1024, DATA); + String kpgAlgorithm = "DSA"; + TestSignatureOidHelper helper = new TestSignatureOidHelper(kpgAlgorithm, + System.getProperty("test.provider.name", "SUN"), + SecurityUtils.getTestKeySize(kpgAlgorithm), DATA); helper.execute(); } } diff --git a/test/jdk/sun/security/provider/NamedEdDSA.java b/test/jdk/sun/security/provider/NamedEdDSA.java new file mode 100644 index 0000000000000..4d0e3e9228aac --- /dev/null +++ b/test/jdk/sun/security/provider/NamedEdDSA.java @@ -0,0 +1,239 @@ +/* + * 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 8340327 + * @modules java.base/sun.security.ec.ed + * java.base/sun.security.ec.point + * java.base/sun.security.jca + * java.base/sun.security.provider + * @library /test/lib + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.security.ec.ed.EdDSAOperations; +import sun.security.ec.ed.EdDSAParameters; +import sun.security.ec.point.AffinePoint; +import sun.security.jca.JCAUtil; +import sun.security.provider.NamedKeyFactory; +import sun.security.provider.NamedKeyPairGenerator; +import sun.security.provider.NamedSignature; + +import java.security.*; +import java.security.spec.EdDSAParameterSpec; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; +import java.util.List; + +public class NamedEdDSA { + + public static class ProviderImpl extends Provider { + public ProviderImpl() { + super("Named", "0", ""); + put("KeyPairGenerator.EdDSA", EdDSAKeyPairGenerator.class.getName()); + put("KeyPairGenerator.Ed25519", EdDSAKeyPairGenerator.Ed25519.class.getName()); + put("KeyPairGenerator.Ed448", EdDSAKeyPairGenerator.Ed448.class.getName()); + put("KeyFactory.EdDSA", EdDSAKeyFactory.class.getName()); + put("KeyFactory.Ed25519", EdDSAKeyFactory.Ed25519.class.getName()); + put("KeyFactory.Ed448", EdDSAKeyFactory.Ed448.class.getName()); + put("Signature.EdDSA", EdDSASignature.class.getName()); + put("Signature.Ed25519", EdDSASignature.Ed25519.class.getName()); + put("Signature.Ed448", EdDSASignature.Ed448.class.getName()); + } + } + + public static class EdDSASignature extends NamedSignature { + public EdDSASignature() { + super("EdDSA", "Ed25519", "Ed448"); + } + + protected EdDSASignature(String pname) { + super("EdDSA", pname); + } + + public static class Ed25519 extends EdDSASignature { + public Ed25519() { + super("Ed25519"); + } + } + + public static class Ed448 extends EdDSASignature { + public Ed448() { + super("Ed448"); + } + } + + @Override + public byte[] implSign(String name, byte[] sk, Object sk2, byte[] msg, SecureRandom sr) throws SignatureException { + return getOps(name).sign(plain, sk, msg); + } + + @Override + public boolean implVerify(String name, byte[] pk, Object pk2, byte[] msg, byte[] sig) throws SignatureException { + return getOps(name).verify(plain, (AffinePoint) pk2, pk, msg, sig); + } + + @Override + public Object implCheckPublicKey(String name, byte[] pk) throws InvalidKeyException { + return getOps(name).decodeAffinePoint(InvalidKeyException::new, pk); + } + } + + public static class EdDSAKeyFactory extends NamedKeyFactory { + public EdDSAKeyFactory() { + super("EdDSA", "Ed25519", "Ed448"); + } + + protected EdDSAKeyFactory(String pname) { + super("EdDSA", pname); + } + + public static class Ed25519 extends EdDSAKeyFactory { + public Ed25519() { + super("Ed25519"); + } + } + + public static class Ed448 extends EdDSAKeyFactory { + public Ed448() { + super("Ed448"); + } + } + } + + public static class EdDSAKeyPairGenerator extends NamedKeyPairGenerator { + public EdDSAKeyPairGenerator() { + super("EdDSA", "Ed25519", "Ed448"); + } + + protected EdDSAKeyPairGenerator(String pname) { + super("EdDSA", pname); + } + + public static class Ed25519 extends EdDSAKeyPairGenerator { + public Ed25519() { + super("Ed25519"); + } + } + + public static class Ed448 extends EdDSAKeyPairGenerator { + public Ed448() { + super("Ed448"); + } + } + + @Override + public byte[][] implGenerateKeyPair(String pname, SecureRandom sr) { + sr = sr == null ? JCAUtil.getDefSecureRandom() : sr; + var op = getOps(pname); + var sk = op.generatePrivate(sr); + var point = op.computePublic(sk); + byte[] encodedPoint = point.getY().toByteArray(); + reverse(encodedPoint); + // array may be too large or too small, depending on the value + encodedPoint = Arrays.copyOf(encodedPoint, op.getParameters().getKeyLength()); + // set the high-order bit of the encoded point + byte msb = (byte) (point.isXOdd() ? 0x80 : 0); + encodedPoint[encodedPoint.length - 1] |= msb; + return new byte[][] { encodedPoint, sk }; + } + + private static void swap(byte[] arr, int i, int j) { + byte tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } + + private static void reverse(byte [] arr) { + int i = 0; + int j = arr.length - 1; + + while (i < j) { + swap(arr, i, j); + i++; + j--; + } + } + } + + private static EdDSAOperations getOps(String pname) { + var op = switch (pname) { + case "Ed25519" -> e2; + case "Ed448" -> e4; + default -> throw new AssertionError("unknown pname " + pname); + }; + return op; + } + + static final EdDSAParameterSpec plain = new EdDSAParameterSpec(false); + static final EdDSAOperations e2, e4; + static { + try { + e2 = new EdDSAOperations(EdDSAParameters.getBySize(AssertionError::new, 255)); + e4 = new EdDSAOperations(EdDSAParameters.getBySize(AssertionError::new, 448)); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + public static void main(String[] args) throws Exception { + var ps = List.of(new ProviderImpl(), Security.getProvider("SunEC")); + for (var p1 : ps) { + for (var p2 : ps) { + for (var p3 : ps) { + test(p1, p2, p3); + } + } + } + } + + static void test(Provider p1, Provider p2, Provider p3) throws Exception { + System.out.println(p1.getName() + " " + p2.getName() + " " + p3.getName()); + var g = KeyPairGenerator.getInstance("EdDSA", p1); + g.initialize(NamedParameterSpec.ED448); + var kp = g.generateKeyPair(); + var s1 = Signature.getInstance("EdDSA", p2); + var s2 = Signature.getInstance("EdDSA", p3); + var f1 = KeyFactory.getInstance("EdDSA", p2); + var f2 = KeyFactory.getInstance("EdDSA", p3); + var sk = (PrivateKey) f1.translateKey(kp.getPrivate()); + var pk = (PublicKey) f2.translateKey(kp.getPublic()); + // sign and verify twice to make sure the key is intact + s1.initSign(sk); + var sig1 = s1.sign(); + s1.initSign(sk); + var sig2 = s1.sign(); + // EdDSA signing is deterministic + Asserts.assertEqualsByteArray(sig1, sig2); + s2.initVerify(pk); + Asserts.assertTrue(s2.verify(sig1)); + s2.initVerify(pk); + Asserts.assertTrue(s2.verify(sig2)); + // No parameters defined + s1.setParameter(null); + Utils.runAndCheckException(() -> s1.setParameter(NamedParameterSpec.ED448), + InvalidAlgorithmParameterException.class); + } +} diff --git a/test/jdk/sun/security/provider/NamedKeyFactoryTest.java b/test/jdk/sun/security/provider/NamedKeyFactoryTest.java new file mode 100644 index 0000000000000..1ca179bc04690 --- /dev/null +++ b/test/jdk/sun/security/provider/NamedKeyFactoryTest.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8340327 + * @modules java.base/sun.security.x509 + * java.base/sun.security.pkcs + * java.base/sun.security.provider + * java.base/sun.security.util + * @library /test/lib + */ +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import jdk.test.lib.security.SeededSecureRandom; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.provider.NamedKeyFactory; +import sun.security.provider.NamedKeyPairGenerator; +import sun.security.util.RawKeySpec; +import sun.security.x509.NamedX509Key; + +import java.security.*; +import java.security.spec.*; + +public class NamedKeyFactoryTest { + + private static final SeededSecureRandom RAND = SeededSecureRandom.one(); + + public static void main(String[] args) throws Exception { + Security.addProvider(new ProviderImpl()); + + var g = KeyPairGenerator.getInstance("sHA"); + var g2 = KeyPairGenerator.getInstance("ShA-256"); + var g5 = KeyPairGenerator.getInstance("SHa-512"); + var kf = KeyFactory.getInstance("ShA"); + var kf2 = KeyFactory.getInstance("Sha-256"); + var kf5 = KeyFactory.getInstance("Sha-512"); + + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g2.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g5.generateKeyPair(), "SHA", "SHA-512"); + + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g2.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g5.generateKeyPair(), "SHA", "SHA-512"); + + Utils.runAndCheckException(() -> g.initialize(NamedParameterSpec.ED448), + InvalidAlgorithmParameterException.class); // wrong pname + Utils.runAndCheckException(() -> g.initialize(new NamedParameterSpec("SHA-384")), + InvalidAlgorithmParameterException.class); // wrong pname + + Utils.runAndCheckException(() -> g5.initialize(new NamedParameterSpec("SHA-256")), + InvalidAlgorithmParameterException.class); // diff pname + g5.initialize(new NamedParameterSpec("SHA-512")); + + g.initialize(new NamedParameterSpec("sHA-512")); + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-512"); + g.initialize(new NamedParameterSpec("ShA-256")); + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-256"); + + var pk = new NamedX509Key("sHa", "ShA-256", RAND.nBytes(2)); + var sk = new NamedPKCS8Key("sHa", "SHa-256", RAND.nBytes(2)); + checkKey(pk, "sHa", "ShA-256"); + checkKey(sk, "sHa", "SHa-256"); + + Asserts.assertEquals("X.509", pk.getFormat()); + Asserts.assertEquals("PKCS#8", sk.getFormat()); + + var pkSpec = kf.getKeySpec(pk, X509EncodedKeySpec.class); + var skSpec = kf.getKeySpec(sk, PKCS8EncodedKeySpec.class); + + kf2.getKeySpec(pk, X509EncodedKeySpec.class); + kf2.getKeySpec(sk, PKCS8EncodedKeySpec.class); + Utils.runAndCheckException(() -> kf5.getKeySpec(pk, X509EncodedKeySpec.class), + InvalidKeySpecException.class); // wrong KF + Utils.runAndCheckException(() -> kf5.getKeySpec(sk, PKCS8EncodedKeySpec.class), + InvalidKeySpecException.class); + Utils.runAndCheckException(() -> kf.getKeySpec(pk, PKCS8EncodedKeySpec.class), + InvalidKeySpecException.class); // wrong KeySpec + Utils.runAndCheckException(() -> kf.getKeySpec(sk, X509EncodedKeySpec.class), + InvalidKeySpecException.class); + + checkKey(kf.generatePublic(pkSpec), "SHA", "SHA-256"); + Utils.runAndCheckException(() -> kf.generatePrivate(pkSpec), + InvalidKeySpecException.class); + + checkKey(kf.generatePrivate(skSpec), "SHA", "SHA-256"); + Utils.runAndCheckException(() -> kf.generatePublic(skSpec), + InvalidKeySpecException.class); + + checkKey(kf2.generatePrivate(skSpec), "SHA", "SHA-256"); + checkKey(kf2.generatePublic(pkSpec), "SHA", "SHA-256"); + + Utils.runAndCheckException(() -> kf5.generatePublic(pkSpec), + InvalidKeySpecException.class); // wrong KF + Utils.runAndCheckException(() -> kf5.generatePublic(skSpec), + InvalidKeySpecException.class); + + // The private RawKeySpec and unnamed RAW EncodedKeySpec + var prk = kf.getKeySpec(pk, RawKeySpec.class); + Asserts.assertEqualsByteArray(prk.getKeyArr(), pk.getRawBytes()); + var prk2 = kf.getKeySpec(pk, EncodedKeySpec.class); + Asserts.assertEquals("RAW", prk2.getFormat()); + Asserts.assertEqualsByteArray(prk.getKeyArr(), prk2.getEncoded()); + + Asserts.assertEqualsByteArray(kf2.generatePublic(prk).getEncoded(), pk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePublic(prk), InvalidKeySpecException.class); // no pname + Asserts.assertEqualsByteArray(kf2.generatePublic(prk2).getEncoded(), pk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePublic(prk2), InvalidKeySpecException.class); // no pname + + var srk = kf.getKeySpec(sk, RawKeySpec.class); + Asserts.assertEqualsByteArray(srk.getKeyArr(), sk.getRawBytes()); + var srk2 = kf.getKeySpec(sk, EncodedKeySpec.class); + Asserts.assertEquals("RAW", srk2.getFormat()); + Asserts.assertEqualsByteArray(srk2.getEncoded(), sk.getRawBytes()); + + Asserts.assertEqualsByteArray(kf2.generatePrivate(srk).getEncoded(), sk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePrivate(srk), InvalidKeySpecException.class); // no pname + Asserts.assertEqualsByteArray(kf2.generatePrivate(srk2).getEncoded(), sk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePrivate(srk2), InvalidKeySpecException.class); // no pname + + var pk1 = new PublicKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + }; + var pk2 = new PublicKey() { + public String getAlgorithm() { return "sHA-256"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + }; + var pk3 = new PublicKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + public AlgorithmParameterSpec getParams() { return new NamedParameterSpec("sHA-256"); } + }; + + checkKey(kf2.translateKey(pk1), "SHA", "SHA-256"); + checkKey(kf.translateKey(pk2), "SHA", "SHA-256"); + checkKey(kf.translateKey(pk3), "SHA", "SHA-256"); + + Utils.runAndCheckException(() -> kf.translateKey(pk1), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(pk2), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(pk3), InvalidKeyException.class); + + var sk1 = new PrivateKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + }; + var sk2 = new PrivateKey() { + public String getAlgorithm() { return "sHA-256"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + }; + var sk3 = new PrivateKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + public AlgorithmParameterSpec getParams() { return new NamedParameterSpec("sHA-256"); } + }; + + checkKey(kf2.translateKey(sk1), "SHA", "SHA-256"); + checkKey(kf.translateKey(sk2), "SHA", "SHA-256"); + checkKey(kf.translateKey(sk3), "SHA", "SHA-256"); + + Utils.runAndCheckException(() -> kf.translateKey(sk1), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(sk2), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(sk3), InvalidKeyException.class); + } + + static void checkKeyPair(KeyPair kp, String algName, String toString) { + checkKey(kp.getPrivate(), algName, toString); + checkKey(kp.getPublic(), algName, toString); + } + + static void checkKey(Key k, String algName, String pname) { + Asserts.assertEquals(algName, k.getAlgorithm()); + Asserts.assertTrue(k.toString().contains(pname)); + if (k instanceof AsymmetricKey ak && ak.getParams() instanceof NamedParameterSpec nps) { + Asserts.assertEquals(pname, nps.getName()); + } + } + + // Provider + + public static class ProviderImpl extends Provider { + public ProviderImpl() { + super("P", "1", "..."); + put("KeyFactory.SHA", KF.class.getName()); + put("KeyFactory.SHA-256", KF1.class.getName()); + put("KeyFactory.SHA-512", KF2.class.getName()); + put("KeyPairGenerator.SHA", KPG.class.getName()); + put("KeyPairGenerator.SHA-256", KPG1.class.getName()); + put("KeyPairGenerator.SHA-512", KPG2.class.getName()); + } + } + public static class KF extends NamedKeyFactory { + public KF() { + super("SHA", "SHA-256", "SHA-512"); + } + } + public static class KF1 extends NamedKeyFactory { + public KF1() { + super("SHA", "SHA-256"); + } + } + public static class KF2 extends NamedKeyFactory { + public KF2() { + super("SHA", "SHA-512"); + } + } + public static class KPG extends NamedKeyPairGenerator { + public KPG() { + super("SHA", "SHA-256", "SHA-512"); + } + + public KPG(String pname) { + super("SHA", pname); + } + + @Override + public byte[][] implGenerateKeyPair(String name, SecureRandom sr) { + var out = new byte[2][]; + out[0] = RAND.nBytes(name.endsWith("256") ? 2 : 4); + out[1] = RAND.nBytes(name.endsWith("256") ? 2 : 4); + return out; + } + } + public static class KPG1 extends KPG { + public KPG1() { + super("SHA-256"); + } + } + public static class KPG2 extends KPG { + public KPG2() { + super("SHA-512"); + } + } +} diff --git a/test/jdk/sun/security/rsa/BrokenRSAPrivateCrtKey.java b/test/jdk/sun/security/rsa/BrokenRSAPrivateCrtKey.java index 0f03cdde6fc42..aef92647396cd 100644 --- a/test/jdk/sun/security/rsa/BrokenRSAPrivateCrtKey.java +++ b/test/jdk/sun/security/rsa/BrokenRSAPrivateCrtKey.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 @@ -24,6 +24,7 @@ /* * @test * @bug 4503229 8220016 + * @library /test/lib * @summary default RSA KeyFactory can return broken RSAPrivateCrtKey objects * This test was taken directly from the bug report, which * was fixed in the crippled JSAFE provider, and needed @@ -35,12 +36,15 @@ import java.security.interfaces.*; import java.security.spec.*; import java.math.BigInteger; +import jdk.test.lib.security.SecurityUtils; public class BrokenRSAPrivateCrtKey { public static void main(String[] args) throws Exception { + String kpgAlgorithm = "RSA"; KeyPairGenerator generator = - KeyPairGenerator.getInstance("RSA", "SunRsaSign"); - generator.initialize(512); + KeyPairGenerator.getInstance(kpgAlgorithm, + System.getProperty("test.provider.name", "SunRsaSign")); + generator.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair pair = generator.generateKeyPair(); @@ -55,7 +59,8 @@ public static void main(String[] args) throws Exception { privatekey.getPrimeExponentQ(), privatekey.getCrtCoefficient()); - KeyFactory factory = KeyFactory.getInstance("RSA", "SunRsaSign"); + KeyFactory factory = KeyFactory.getInstance("RSA", + System.getProperty("test.provider.name", "SunRsaSign")); PrivateKey privatekey2 = factory.generatePrivate(spec); diff --git a/test/jdk/sun/security/rsa/GenKeyStore.java b/test/jdk/sun/security/rsa/GenKeyStore.java index 629a504a04082..26178e9a576ad 100644 --- a/test/jdk/sun/security/rsa/GenKeyStore.java +++ b/test/jdk/sun/security/rsa/GenKeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 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 @@ -74,7 +74,8 @@ private static void addToKeyStore(KeyStore ks, KeyPair kp, String name) throws E private static void generateKeyPair(KeyStore ks, int keyLength, String alias) throws Exception { System.out.println("Generating " + keyLength + " keypair " + alias + "..."); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SunRsaSign"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", + System.getProperty("test.provider.name", "SunRsaSign")); kpg.initialize(keyLength); KeyPair kp = kpg.generateKeyPair(); addToKeyStore(ks, kp, alias); diff --git a/test/jdk/sun/security/rsa/KeySizeTest.java b/test/jdk/sun/security/rsa/KeySizeTest.java index 35f9902b8c3d5..129a3539b51f5 100644 --- a/test/jdk/sun/security/rsa/KeySizeTest.java +++ b/test/jdk/sun/security/rsa/KeySizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,8 @@ public class KeySizeTest { /** * JDK default RSA Provider. */ - private static final String PROVIDER_NAME = "SunRsaSign"; + private static final String PROVIDER_NAME = + System.getProperty("test.provider.name", "SunRsaSign"); public static void main(String[] args) throws Exception { int iKeyPairSize = Integer.parseInt(args[0]); diff --git a/test/jdk/sun/security/rsa/PrivateKeyEqualityTest.java b/test/jdk/sun/security/rsa/PrivateKeyEqualityTest.java index 1a3a6df756a1e..3ed4aae37b0a6 100644 --- a/test/jdk/sun/security/rsa/PrivateKeyEqualityTest.java +++ b/test/jdk/sun/security/rsa/PrivateKeyEqualityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,8 @@ public class PrivateKeyEqualityTest { /** * JDK default RSA Provider. */ - private static final String PROVIDER_NAME = "SunRsaSign"; + private static final String PROVIDER_NAME = + System.getProperty("test.provider.name", "SunRsaSign"); public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException { diff --git a/test/jdk/sun/security/rsa/SignatureTest.java b/test/jdk/sun/security/rsa/SignatureTest.java index 15df96354b38e..d48d7ca481bd1 100644 --- a/test/jdk/sun/security/rsa/SignatureTest.java +++ b/test/jdk/sun/security/rsa/SignatureTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,8 @@ public class SignatureTest { /** * JDK default RSA Provider. */ - private static final String PROVIDER = "SunRsaSign"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunRsaSign"); /** * How much times signature updated. diff --git a/test/jdk/sun/security/rsa/SpecTest.java b/test/jdk/sun/security/rsa/SpecTest.java index 43ccf3ca718c7..8cc0bca9898b0 100644 --- a/test/jdk/sun/security/rsa/SpecTest.java +++ b/test/jdk/sun/security/rsa/SpecTest.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 @@ -53,7 +53,8 @@ public class SpecTest { /** * JDK default RSA Provider. */ - private static final String PROVIDER = "SunRsaSign"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunRsaSign"); /** * diff --git a/test/jdk/sun/security/rsa/TestCACerts.java b/test/jdk/sun/security/rsa/TestCACerts.java index 14ed422947217..2d8a1246e5e35 100644 --- a/test/jdk/sun/security/rsa/TestCACerts.java +++ b/test/jdk/sun/security/rsa/TestCACerts.java @@ -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 @@ -38,7 +38,8 @@ public class TestCACerts { - private final static String PROVIDER = "SunRsaSign"; + private final static String PROVIDER = + System.getProperty("test.provider.name", "SunRsaSign"); private final static char SEP = File.separatorChar; diff --git a/test/jdk/sun/security/rsa/TestKeyFactory.java b/test/jdk/sun/security/rsa/TestKeyFactory.java index 8a4f4b7f47f67..8be2037a833df 100644 --- a/test/jdk/sun/security/rsa/TestKeyFactory.java +++ b/test/jdk/sun/security/rsa/TestKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -228,7 +228,8 @@ private static void test(KeyFactory kf, Key key) throws Exception { public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); KeyStore ks = getKeyStore(); - KeyFactory kf = KeyFactory.getInstance("RSA", "SunRsaSign"); + KeyFactory kf = KeyFactory.getInstance("RSA", + System.getProperty("test.provider.name", "SunRsaSign")); for (Enumeration e = ks.aliases(); e.hasMoreElements(); ) { String alias = (String)e.nextElement(); Key key = null; diff --git a/test/jdk/sun/security/rsa/TestKeyPairGenerator.java b/test/jdk/sun/security/rsa/TestKeyPairGenerator.java index 72ab7e73acff7..f5bd6c47f3b02 100644 --- a/test/jdk/sun/security/rsa/TestKeyPairGenerator.java +++ b/test/jdk/sun/security/rsa/TestKeyPairGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import java.security.interfaces.*; import java.security.spec.*; +import jdk.test.lib.security.SecurityUtils; import jdk.test.lib.SigTestUtil; import static jdk.test.lib.SigTestUtil.SignatureType; @@ -85,9 +86,10 @@ private static void test(PrivateKey privateKey, PublicKey publicKey) throws Exce } // regression test for 4865198 - private static void testInvalidSignature(KeyPair kp1, KeyPair kp2) throws Exception { + private static void testInvalidSignature(KeyPair kp1, KeyPair kp2, String signAlgo) + throws Exception { System.out.println("Testing signature with incorrect key..."); - Signature sig = Signature.getInstance("MD5withRSA", provider); + Signature sig = Signature.getInstance(signAlgo, provider); sig.initSign(kp1.getPrivate()); byte[] data = new byte[100]; sig.update(data); @@ -111,14 +113,16 @@ private static void testInvalidSignature(KeyPair kp1, KeyPair kp2) throws Except public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); - provider = Security.getProvider("SunRsaSign"); + provider = Security.getProvider( + System.getProperty("test.provider.name", "SunRsaSign")); data = new byte[2048]; - // keypair generation is very slow, test only a few short keys - int[] keyLengths = {512, 512, 1024}; + String kpgAlgorithm = "RSA"; + int keySize = SecurityUtils.getTestKeySize(kpgAlgorithm); + int[] keyLengths = {keySize, keySize, keySize + 1024}; BigInteger[] pubExps = {null, BigInteger.valueOf(3), null}; KeyPair[] keyPairs = new KeyPair[3]; new Random().nextBytes(data); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", provider); + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, provider); for (int i = 0; i < keyLengths.length; i++) { int len = keyLengths[i]; BigInteger exp = pubExps[i]; @@ -150,9 +154,14 @@ public static void main(String[] args) throws Exception { } test(privateKey, publicKey); } - testInvalidSignature(keyPairs[0], keyPairs[1]); - testInvalidSignature(keyPairs[0], keyPairs[2]); - testInvalidSignature(keyPairs[2], keyPairs[0]); + String md5Algo = "MD5withRSA"; + String sha256Algo = "Sha256withRSA"; + testInvalidSignature(keyPairs[0], keyPairs[1], md5Algo); + testInvalidSignature(keyPairs[0], keyPairs[2], md5Algo); + testInvalidSignature(keyPairs[2], keyPairs[0], md5Algo); + testInvalidSignature(keyPairs[0], keyPairs[1], sha256Algo); + testInvalidSignature(keyPairs[0], keyPairs[2], sha256Algo); + testInvalidSignature(keyPairs[2], keyPairs[0], sha256Algo); long stop = System.currentTimeMillis(); System.out.println("All tests passed (" + (stop - start) + " ms)."); } diff --git a/test/jdk/sun/security/rsa/TestKeyPairGeneratorExponent.java b/test/jdk/sun/security/rsa/TestKeyPairGeneratorExponent.java index 7f17ed7bc4861..2c60d66664e1d 100644 --- a/test/jdk/sun/security/rsa/TestKeyPairGeneratorExponent.java +++ b/test/jdk/sun/security/rsa/TestKeyPairGeneratorExponent.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 @@ -24,6 +24,7 @@ /** * @test * @bug 8216012 + * @library /test/lib * @summary Tests the RSA public key exponent for KeyPairGenerator * @run main/timeout=60 TestKeyPairGeneratorExponent */ @@ -33,14 +34,16 @@ import java.security.*; import java.security.interfaces.*; import java.security.spec.*; +import jdk.test.lib.security.SecurityUtils; public class TestKeyPairGeneratorExponent { - private static int keyLen = 512; + private static final String KPG_ALGORITHM = "RSA"; + private static final int KEY_LENGTH = SecurityUtils.getTestKeySize(KPG_ALGORITHM); private static BigInteger[] validExponents = new BigInteger[] { RSAKeyGenParameterSpec.F0, RSAKeyGenParameterSpec.F4, - BigInteger.ONE.shiftLeft(keyLen - 1).subtract(BigInteger.ONE) + BigInteger.ONE.shiftLeft(KEY_LENGTH - 1).subtract(BigInteger.ONE) }; private static BigInteger[] invalidExponents = new BigInteger[] { @@ -55,7 +58,7 @@ public static void testValidExponents(KeyPairGenerator kpg, BigInteger exponent) { System.out.println("Testing exponent = " + exponent.toString(16)); try { - kpg.initialize(new RSAKeyGenParameterSpec(keyLen, exponent)); + kpg.initialize(new RSAKeyGenParameterSpec(KEY_LENGTH, exponent)); kpg.generateKeyPair(); System.out.println("OK, key pair generated"); } catch(InvalidAlgorithmParameterException iape){ @@ -67,7 +70,7 @@ public static void testInvalidExponents(KeyPairGenerator kpg, BigInteger exponent) { System.out.println("Testing exponent = " + exponent.toString(16)); try { - kpg.initialize(new RSAKeyGenParameterSpec(keyLen, exponent)); + kpg.initialize(new RSAKeyGenParameterSpec(KEY_LENGTH, exponent)); kpg.generateKeyPair(); throw new RuntimeException("Error: Expected IAPE not thrown."); } catch(InvalidAlgorithmParameterException iape){ @@ -81,7 +84,8 @@ public static void testInvalidExponents(KeyPairGenerator kpg, public static void main(String[] args) throws Exception { KeyPairGenerator kpg = - KeyPairGenerator.getInstance("RSA", "SunRsaSign"); + KeyPairGenerator.getInstance(KPG_ALGORITHM, + System.getProperty("test.provider.name", "SunRsaSign")); for(BigInteger validExponent : validExponents) { testValidExponents(kpg, validExponent); diff --git a/test/jdk/sun/security/rsa/TestKeyPairGeneratorInit.java b/test/jdk/sun/security/rsa/TestKeyPairGeneratorInit.java index e87d5a5b6a409..7d85c56e68461 100644 --- a/test/jdk/sun/security/rsa/TestKeyPairGeneratorInit.java +++ b/test/jdk/sun/security/rsa/TestKeyPairGeneratorInit.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 @@ -24,11 +24,13 @@ /** * @test * @bug 8211049 + * @library /test/lib * @summary make sure the supplied SecureRandom object is used */ import java.security.*; import java.security.interfaces.*; +import jdk.test.lib.security.SecurityUtils; public class TestKeyPairGeneratorInit { @@ -45,10 +47,12 @@ public void nextBytes(byte[] bytes) { } public static void main(String[] args) throws Exception { + String kpgAlgorithm = "RSA"; KeyPairGenerator kpg = - KeyPairGenerator.getInstance("RSA", "SunRsaSign"); + KeyPairGenerator.getInstance(kpgAlgorithm, + System.getProperty("test.provider.name", "SunRsaSign")); MySecureRandom rnd = new MySecureRandom(); - kpg.initialize(2048, rnd); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm), rnd); System.out.println("Generate keypair then check"); KeyPair kp = kpg.generateKeyPair(); if (!rnd.isUsed) { diff --git a/test/jdk/sun/security/rsa/TestKeyPairGeneratorLength.java b/test/jdk/sun/security/rsa/TestKeyPairGeneratorLength.java index 8959ede5f30fb..765ca485bbc79 100644 --- a/test/jdk/sun/security/rsa/TestKeyPairGeneratorLength.java +++ b/test/jdk/sun/security/rsa/TestKeyPairGeneratorLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 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 @@ -24,23 +24,28 @@ /** * @test * @bug 5078280 + * @library /test/lib * @summary make sure generated key pairs are exactly the requested length * @author Andreas Sterbenz */ import java.security.*; import java.security.interfaces.*; +import jdk.test.lib.security.SecurityUtils; public class TestKeyPairGeneratorLength { + private static final String KPG_ALGORITHM = "RSA"; + private static final int KEY_LENGTH = SecurityUtils.getTestKeySize(KPG_ALGORITHM); public static void main(String[] args) throws Exception { - test(512); - test(513); + test(KEY_LENGTH); + test(KEY_LENGTH + 1); System.out.println("Done."); } private static void test(int len) throws Exception { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SunRsaSign"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance(KPG_ALGORITHM, + System.getProperty("test.provider.name", "SunRsaSign")); kpg.initialize(len); for (int i = 0; i < 6; i++) { System.out.println("Generating keypair " + len + " bit keypair " + (i + 1) + "..."); diff --git a/test/jdk/sun/security/rsa/TestRSAOidSupport.java b/test/jdk/sun/security/rsa/TestRSAOidSupport.java index 2cd0625860978..551fa33cd8a7c 100644 --- a/test/jdk/sun/security/rsa/TestRSAOidSupport.java +++ b/test/jdk/sun/security/rsa/TestRSAOidSupport.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 @@ -59,14 +59,16 @@ public static void main(String[] args) throws Exception { X509EncodedKeySpec x509Spec = new X509EncodedKeySpec (toByteArray(DER_BYTES)); String keyAlgo = "RSA"; - KeyFactory kf = KeyFactory.getInstance(keyAlgo, "SunRsaSign"); + KeyFactory kf = KeyFactory.getInstance(keyAlgo, + System.getProperty("test.provider.name", "SunRsaSign")); RSAPublicKey rsaKey = (RSAPublicKey) kf.generatePublic(x509Spec); if (rsaKey.getAlgorithm() != keyAlgo) { throw new RuntimeException("Key algo should be " + keyAlgo + ", but got " + rsaKey.getAlgorithm()); } - kf = KeyFactory.getInstance("RSASSA-PSS", "SunRsaSign"); + kf = KeyFactory.getInstance("RSASSA-PSS", + System.getProperty("test.provider.name", "SunRsaSign")); try { kf.generatePublic(x509Spec); throw new RuntimeException("Should throw IKSE"); diff --git a/test/jdk/sun/security/rsa/TestSigGen15.java b/test/jdk/sun/security/rsa/TestSigGen15.java index 12cc028b07249..480ed8d878c53 100644 --- a/test/jdk/sun/security/rsa/TestSigGen15.java +++ b/test/jdk/sun/security/rsa/TestSigGen15.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 @@ -71,7 +71,8 @@ public static void main(String[] args) throws Exception { static boolean runTest(List records) throws Exception { boolean success = true; //for (Provider provider : Security.getProviders()) { - Provider p = Security.getProvider("SunRsaSign"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name","SunRsaSign")); KeyFactory kf = KeyFactory.getInstance("RSA", p); for (SigRecord sr : records) { System.out.println("==Testing Record : " + sr + "=="); diff --git a/test/jdk/sun/security/rsa/TestSignatures.java b/test/jdk/sun/security/rsa/TestSignatures.java index 3a6a086b7db26..0296ac21d6443 100644 --- a/test/jdk/sun/security/rsa/TestSignatures.java +++ b/test/jdk/sun/security/rsa/TestSignatures.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,7 +111,8 @@ private static void test(PrivateKey privateKey, PublicKey publicKey) public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); - provider = Security.getProvider("SunRsaSign"); + provider = Security.getProvider( + System.getProperty("test.provider.name", "SunRsaSign")); data = new byte[2048]; new Random().nextBytes(data); KeyStore ks = getKeyStore(); diff --git a/test/jdk/sun/security/rsa/WithoutNULL.java b/test/jdk/sun/security/rsa/WithoutNULL.java index 64cf831099d2a..39daca6d30404 100644 --- a/test/jdk/sun/security/rsa/WithoutNULL.java +++ b/test/jdk/sun/security/rsa/WithoutNULL.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 @@ -48,7 +48,8 @@ public static void main(String[] args) throws Exception { b8oaWkxk069jDTM1RhllPJZkAjeQRbw4gkg4N6wKZz9B/jdSRMNJg/b9QdRYZOHOBxsEHMbUREPV DoCOLaxB8eIXX0EWkiE="""); - Signature s = Signature.getInstance("SHA1withRSA", "SunRsaSign"); + Signature s = Signature.getInstance("SHA1withRSA", + System.getProperty("test.provider.name", "SunRsaSign")); s.initVerify(KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(key))); if (!s.verify(sig)) { throw new RuntimeException("Does not verify"); diff --git a/test/jdk/sun/security/rsa/pss/DefaultParamSpec.java b/test/jdk/sun/security/rsa/pss/DefaultParamSpec.java index 6f121c75fd268..782fbe510b7a0 100644 --- a/test/jdk/sun/security/rsa/pss/DefaultParamSpec.java +++ b/test/jdk/sun/security/rsa/pss/DefaultParamSpec.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 @@ -30,10 +30,12 @@ import java.security.spec.PSSParameterSpec; import java.security.spec.RSAKeyGenParameterSpec; import java.util.Date; +import jdk.test.lib.security.SecurityUtils; /** * @test * @bug 8242811 + * @library /test/lib * @modules java.base/sun.security.x509 * @summary AlgorithmId::getDefaultAlgorithmParameterSpec returns incompatible * PSSParameterSpec for an RSASSA-PSS key @@ -42,7 +44,7 @@ public class DefaultParamSpec { public static void main(String[] args) throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSASSA-PSS"); KeyFactory kf = KeyFactory.getInstance("RSASSA-PSS"); - kpg.initialize(new RSAKeyGenParameterSpec(2048, + kpg.initialize(new RSAKeyGenParameterSpec(SecurityUtils.getTestKeySize("RSA"), RSAKeyGenParameterSpec.F4, new PSSParameterSpec( "SHA-384", "MGF1", diff --git a/test/jdk/sun/security/rsa/pss/InitAgain.java b/test/jdk/sun/security/rsa/pss/InitAgain.java index 209d5f46178a2..9fe8d1a0131d2 100644 --- a/test/jdk/sun/security/rsa/pss/InitAgain.java +++ b/test/jdk/sun/security/rsa/pss/InitAgain.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 @@ -22,26 +22,34 @@ */ import java.security.*; import java.security.spec.*; +import jdk.test.lib.security.SecurityUtils; /** * @test * @bug 8205445 + * @library /test/lib * @summary Make sure old state is cleared when init is called again + * @run main InitAgain default + * @run main InitAgain SHA-256 */ public class InitAgain { public static void main(String[] args) throws Exception { + String mdName = args[0]; + PSSParameterSpec pssParamSpec = "default".equals(mdName) ? PSSParameterSpec.DEFAULT : + new PSSParameterSpec(mdName, "MGF1", new MGF1ParameterSpec(mdName), 20, 1); byte[] msg = "hello".getBytes(); Signature s1 = Signature.getInstance("RSASSA-PSS"); Signature s2 = Signature.getInstance("RSASSA-PSS"); - s1.setParameter(PSSParameterSpec.DEFAULT); - s2.setParameter(PSSParameterSpec.DEFAULT); + s1.setParameter(pssParamSpec); + s2.setParameter(pssParamSpec); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); - kpg.initialize(1024); + String kpgAlgorithm = "RSA"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm); + kpg.initialize(SecurityUtils.getTestKeySize(kpgAlgorithm)); KeyPair kp = kpg.generateKeyPair(); s1.initSign(kp.getPrivate()); diff --git a/test/jdk/sun/security/rsa/pss/PSSKeyCompatibility.java b/test/jdk/sun/security/rsa/pss/PSSKeyCompatibility.java index 4961a2a2ad8c3..5515e770c267e 100644 --- a/test/jdk/sun/security/rsa/pss/PSSKeyCompatibility.java +++ b/test/jdk/sun/security/rsa/pss/PSSKeyCompatibility.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 @@ -51,7 +51,8 @@ public class PSSKeyCompatibility { private static final String ALGO = "RSASSA-PSS"; private static final String OID = "1.2.840.113549.1.1.10"; - private static final String PROVIDER = "SunRsaSign"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunRsaSign"); public static void main(String[] args) { diff --git a/test/jdk/sun/security/rsa/pss/PSSParametersTest.java b/test/jdk/sun/security/rsa/pss/PSSParametersTest.java index c71e5bb34a4d2..a489b3273ad9f 100644 --- a/test/jdk/sun/security/rsa/pss/PSSParametersTest.java +++ b/test/jdk/sun/security/rsa/pss/PSSParametersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,8 @@ public class PSSParametersTest { /** * JDK default RSA Provider. */ - private static final String PROVIDER = "SunRsaSign"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunRsaSign"); private static final String PSS_ALGO = "RSASSA-PSS"; private static final String PSS_OID = "1.2.840.113549.1.1.10"; diff --git a/test/jdk/sun/security/rsa/pss/SerializedPSSKey.java b/test/jdk/sun/security/rsa/pss/SerializedPSSKey.java index eb0bd1dde7a98..f946427092cf7 100644 --- a/test/jdk/sun/security/rsa/pss/SerializedPSSKey.java +++ b/test/jdk/sun/security/rsa/pss/SerializedPSSKey.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 @@ -50,9 +50,11 @@ import java.security.spec.RSAPublicKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; +import jdk.test.lib.security.SecurityUtils; /** * @test @bug 8242335 + * @library /test/lib * @summary Test RSASSA-PSS serialized keys * @run main SerializedPSSKey */ @@ -60,8 +62,9 @@ public class SerializedPSSKey { private static final String ALGO = "RSASSA-PSS"; private static final String OID = "1.2.840.113549.1.1.10"; - private static final String PROVIDER = "SunRsaSign"; - private static final int KEY_SIZE = 2048; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunRsaSign"); + private static final int KEY_SIZE = SecurityUtils.getTestKeySize("RSA"); private static final byte[] DATA = "Test".getBytes(); /** * Digest algorithms to test w/ RSASSA-PSS signature algorithms diff --git a/test/jdk/sun/security/rsa/pss/SignatureTest2.java b/test/jdk/sun/security/rsa/pss/SignatureTest2.java index ea548d04dad09..7d3d76ef0ae9a 100644 --- a/test/jdk/sun/security/rsa/pss/SignatureTest2.java +++ b/test/jdk/sun/security/rsa/pss/SignatureTest2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,8 @@ public class SignatureTest2 { /** * JDK default RSA Provider. */ - private static final String PROVIDER = "SunRsaSign"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunRsaSign"); /** * How much times signature updated. diff --git a/test/jdk/sun/security/rsa/pss/SignatureTestPSS.java b/test/jdk/sun/security/rsa/pss/SignatureTestPSS.java index daa0fc51d8a3a..82580b0c354be 100644 --- a/test/jdk/sun/security/rsa/pss/SignatureTestPSS.java +++ b/test/jdk/sun/security/rsa/pss/SignatureTestPSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,8 @@ public class SignatureTestPSS { /** * JDK default RSA Provider. */ - private static final String PROVIDER = "SunRsaSign"; + private static final String PROVIDER = + System.getProperty("test.provider.name", "SunRsaSign"); /** * How much times signature updated. diff --git a/test/jdk/sun/security/rsa/pss/TestPSSKeySupport.java b/test/jdk/sun/security/rsa/pss/TestPSSKeySupport.java index 5e8c48a178ab1..44d1324b00e1e 100644 --- a/test/jdk/sun/security/rsa/pss/TestPSSKeySupport.java +++ b/test/jdk/sun/security/rsa/pss/TestPSSKeySupport.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 @@ -24,6 +24,7 @@ /** * @test * @bug 8146293 8242556 8172366 8254717 + * @library /test/lib * @summary Test RSASSA-PSS Key related support such as KeyPairGenerator * and KeyFactory of the SunRsaSign provider */ @@ -35,6 +36,7 @@ import java.security.*; import java.security.interfaces.*; import java.security.spec.*; +import jdk.test.lib.security.SecurityUtils; public class TestPSSKeySupport { @@ -130,11 +132,13 @@ private static void checkKeyPair(KeyPair kp) throws Exception { } public static void main(String[] args) throws Exception { + int keySize = SecurityUtils.getTestKeySize("RSA"); KeyPairGenerator kpg = - KeyPairGenerator.getInstance(ALGO, "SunRsaSign"); + KeyPairGenerator.getInstance(ALGO, + System.getProperty("test.provider.name", "SunRsaSign")); // Algorithm-Independent Initialization - kpg.initialize(2048); + kpg.initialize(keySize); KeyPair kp = kpg.generateKeyPair(); checkKeyPair(kp); BigInteger pubExp = ((RSAPublicKey)kp.getPublic()).getPublicExponent(); @@ -142,17 +146,18 @@ public static void main(String[] args) throws Exception { // Algorithm-specific Initialization PSSParameterSpec params = new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 32, 1); - kpg.initialize(new RSAKeyGenParameterSpec(2048, pubExp, params)); + kpg.initialize(new RSAKeyGenParameterSpec(keySize, pubExp, params)); KeyPair kp2 = kpg.generateKeyPair(); checkKeyPair(kp2); params = new PSSParameterSpec("SHA3-256", "MGF1", new MGF1ParameterSpec("SHA3-256"), 32, 1); - kpg.initialize(new RSAKeyGenParameterSpec(2048, pubExp, params)); + kpg.initialize(new RSAKeyGenParameterSpec(keySize, pubExp, params)); KeyPair kp3 = kpg.generateKeyPair(); checkKeyPair(kp3); - KeyFactory kf = KeyFactory.getInstance(ALGO, "SunRsaSign"); + KeyFactory kf = KeyFactory.getInstance(ALGO, + System.getProperty("test.provider.name", "SunRsaSign")); test(kf, kp.getPublic()); test(kf, kp.getPrivate()); test(kf, kp2.getPublic()); diff --git a/test/jdk/sun/security/rsa/pss/TestSigGenPSS.java b/test/jdk/sun/security/rsa/pss/TestSigGenPSS.java index dfadef03f04ed..cbda2b1df93a0 100644 --- a/test/jdk/sun/security/rsa/pss/TestSigGenPSS.java +++ b/test/jdk/sun/security/rsa/pss/TestSigGenPSS.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 @@ -62,7 +62,8 @@ public void nextBytes(byte[] bytes) { public static void main(String[] args) throws Exception { //for (Provider provider : Security.getProviders()) { - Provider p = Security.getProvider("SunRsaSign"); + Provider p = Security.getProvider( + System.getProperty("test.provider.name", "SunRsaSign")); Signature sig; try { sig = Signature.getInstance("RSASSA-PSS", p); diff --git a/test/jdk/sun/security/ssl/HandshakeHash/DigestBase.java b/test/jdk/sun/security/ssl/HandshakeHash/DigestBase.java index a92de6fff6eda..437973049a88e 100644 --- a/test/jdk/sun/security/ssl/HandshakeHash/DigestBase.java +++ b/test/jdk/sun/security/ssl/HandshakeHash/DigestBase.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 @@ -59,13 +59,13 @@ public MD5() throws Exception { public static final class SHA extends DigestBase { public SHA() throws Exception { - super("SHA", "SUN"); + super("SHA", System.getProperty("test.provider.name", "SUN")); } } public static final class SHA256 extends DigestBase { public SHA256() throws Exception { - super("SHA-256", "SUN"); + super("SHA-256", System.getProperty("test.provider.name", "SUN")); } } } diff --git a/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java b/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java index 58ebb5b876af8..5555363374ca9 100644 --- a/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java +++ b/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8046321 + * @bug 8046321 8339403 * @library ../../../../java/security/testlibrary * @build CertificateBuilder SimpleOCSPServer * @run main/othervm -Djavax.net.debug=ssl:respmgr java.base/sun.security.ssl.StatusResponseManagerTests diff --git a/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java b/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java index f6b0d1f10e20f..b210cfb26eaed 100644 --- a/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java +++ b/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,7 @@ public static void main(String[] args) throws Exception { put("Clear StatusResponseManager cache", testClearSRM); put("Basic OCSP_MULTI fetch test", testOcspMultiFetch); put("Test Cache Expiration", testCacheExpiry); + put("Test Interrupt while fetching", forceInterruptMainThread); }}; // Create the CAs and OCSP responders @@ -262,6 +263,38 @@ public Map.Entry runTest() { } }; + public static final TestCase forceInterruptMainThread = new TestCase() { + @Override + public Map.Entry runTest() { + StatusResponseManager srm = new StatusResponseManager(); + Boolean pass = Boolean.FALSE; + String message = null; + CertStatusRequest oReq = OCSPStatusRequest.EMPTY_OCSP; + + try { + // Force the interrupt flag to be set on the thread that + // performs the invokeAll in the SRM. + Thread.currentThread().interrupt(); + + // Get OCSP responses for non-root certs in the chain + Map responseMap = srm.get( + CertStatusRequestType.OCSP, oReq, chain, 5000, + TimeUnit.MILLISECONDS); + if (Thread.currentThread().isInterrupted()) { + pass = Boolean.TRUE; + message = "Thread is in expected interrupted state."; + } else { + message = "Missing expectedInterruptedException."; + } + message += " Number of SRM entries: " + responseMap.size(); + } catch (Exception exc) { + message = "Unexpected exception: " + exc; + } + + return new AbstractMap.SimpleEntry<>(pass, message); + } + }; + /** * Creates the PKI components necessary for this test, including * Root CA, Intermediate CA and SSL server certificates, the keystores diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/PKIXExtendedTM.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/PKIXExtendedTM.java index 1cf22f042933b..e2e5e066f9c6a 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/PKIXExtendedTM.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/PKIXExtendedTM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, 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 @@ -56,354 +56,495 @@ * * TLS server certificate: * server private key: - * -----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,D9AE407F6D0E389A * - * WPrA7TFol/cQCcp9oHnXWNpYlvRbbIcQj0m+RKT2Iuzfus+DHt3Zadf8nJpKfX2e - * h2rnhlzCN9M7djRDooZKDOPCsdBn51Au7HlZF3S3Opgo7D8XFM1a8t1Je4ke14oI - * nw6QKYsBblRziPnP2PZ0zvX24nOv7bbY8beynlJHGs00VWSFdoH2DS0aE1p6D+3n - * ptJuJ75dVfZFK4X7162APlNXevX8D6PEQpSiRw1rjjGGcnvQ4HdWk3BxDVDcCNJb - * Y1aGNRxsjTDvPi3R9Qx2M+W03QzEPx4SR3ZHVskeSJHaetM0TM/w/45Paq4GokXP - * ZeTnbEx1xmjkA7h+t4doLL4watx5F6yLsJzu8xB3lt/1EtmkYtLz1t7X4BetPAXz - * zS69X/VwhKfsOI3qXBWuL2oHPyhDmT1gcaUQwEPSV6ogHEEQEDXdiUS8heNK13KF - * TCQYFkETvV2BLxUhV1hypPzRQ6tUpJiAbD5KmoK2lD9slshG2QtvKQq0/bgkDY5J - * LhDHV2dtcZ3kDPkkZXpbcJQvoeH3d09C5sIsuTFo2zgNR6oETHUc5TzP6FY2YYRa - * QcK5HcmtsRRiXFm01ac+aMejJUIujjFt84SiKWT/73vC8AmY4tYcJBLjCg4XIxSH - * fdDFLL1YZENNO5ivlp8mdiHqcawx+36L7DrEZQ8RZt6cqST5t/+XTdM74s6k81GT - * pNsa82P2K2zmIUZ/DL2mKjW1vfRByw1NQFEBkN3vdyZxYfM/JyUzX4hbjXBEkh9Q - * QYrcwLKLjis2QzSvK04B3bvRzRb+4ocWiso8ZPAXAIxZFBWDpTMM2A== - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICXAIBAAKBgQClrFscN6LdmYktsnm4j9VIpecchBeNaZzGrG358h0fORna03Ie - * buxEzHCk3LoAMPagTz1UemFqzFfQCn+VKBg/mtmU8hvIJIh+/p0PPftXUwizIDPU - * PxdHFNHN6gjYDnVOr77M0uyvqXpJ38LZrLgkQJCmA1Yq0DAFQCxPq9l0iQIDAQAB - * AoGAbqcbg1E1mkR99uOJoNeQYKFOJyGiiXTMnXV1TseC4+PDfQBU7Dax35GcesBi - * CtapIpFKKS5D+ozY6b7ZT8ojxuQ/uHLPAvz0WDR3ds4iRF8tyu71Q1ZHcQsJa17y - * yO7UbkSSKn/Mp9Rb+/dKqftUGNXVFLqgHBOzN2s3We3bbbECQQDYBPKOg3hkaGHo - * OhpHKqtQ6EVkldihG/3i4WejRonelXN+HRh1KrB2HBx0M8D/qAzP1i3rNSlSHer4 - * 59YRTJnHAkEAxFX/sVYSn07BHv9Zhn6XXct/Cj43z/tKNbzlNbcxqQwQerw3IH51 - * 8UH2YOA+GD3lXbKp+MytoFLWv8zg4YT/LwJAfqan75Z1R6lLffRS49bIiq8jwE16 - * rTrUJ+kv8jKxMqc9B3vXkxpsS1M/+4E8bqgAmvpgAb8xcsvHsBd9ErdukQJBAKs2 - * j67W75BrPjBI34pQ1LEfp56IGWXOrq1kF8IbCjxv3+MYRT6Z6UJFkpRymNPNDjsC - * dgUYgITiGJHUGXuw3lMCQHEHqo9ZtXz92yFT+VhsNc29B8m/sqUJdtCcMd/jGpAF - * u6GHufjqIZBpQsk63wbwESAPZZ+kk1O1kS5GIRLX608= - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) + * Private-Key: (2048 bit, 2 primes) * modulus: - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 + * 00:9a:0c:e0:8f:a8:02:7e:5a:ef:ed:b2:42:ad:08: + * 4e:91:ba:c2:ad:9b:79:d7:9b:0f:fd:d2:f8:15:2f: + * 19:89:80:10:00:02:19:6d:27:c2:90:d7:a5:23:53: + * 74:6e:64:28:7c:24:aa:ed:ea:21:59:dc:a3:5c:b5: + * c9:42:31:4f:a2:de:fb:09:7c:73:ed:88:04:34:f1: + * 15:ad:3d:60:cd:ca:c5:13:99:d3:9f:9b:b2:92:70: + * cb:ba:4b:3d:20:96:ad:be:92:53:ed:54:3b:c5:14: + * bd:cf:d4:0f:cb:05:4f:fd:2b:9e:e0:50:bb:65:13: + * 92:c0:d6:bd:4d:02:0c:70:b6:65:d4:7d:b4:4d:c3: + * df:2c:08:9e:d2:3e:69:32:46:6f:6f:ca:d1:73:a4: + * 94:07:ef:14:e3:da:9e:2f:c0:ac:0e:10:33:4c:68: + * 79:f3:79:40:d6:e9:3c:c2:e6:70:e0:89:ce:a0:7a: + * a8:84:28:85:32:37:08:b0:cf:b1:7f:5f:bc:1f:a5: + * 3d:ef:d6:68:a8:17:21:5f:87:d5:4b:b5:cc:ee:78: + * 8d:dd:b1:28:6a:c0:fb:64:bd:b7:70:02:33:03:0b: + * b8:b8:bb:08:82:f6:8e:05:27:d1:3b:e6:c5:ac:4d: + * 85:5b:a1:1d:a3:48:5d:03:15:76:63:6c:71:21:3e: + * 98:cd * publicExponent: 65537 (0x10001) * privateExponent: - * 6e:a7:1b:83:51:35:9a:44:7d:f6:e3:89:a0:d7:90: - * 60:a1:4e:27:21:a2:89:74:cc:9d:75:75:4e:c7:82: - * e3:e3:c3:7d:00:54:ec:36:b1:df:91:9c:7a:c0:62: - * 0a:d6:a9:22:91:4a:29:2e:43:fa:8c:d8:e9:be:d9: - * 4f:ca:23:c6:e4:3f:b8:72:cf:02:fc:f4:58:34:77: - * 76:ce:22:44:5f:2d:ca:ee:f5:43:56:47:71:0b:09: - * 6b:5e:f2:c8:ee:d4:6e:44:92:2a:7f:cc:a7:d4:5b: - * fb:f7:4a:a9:fb:54:18:d5:d5:14:ba:a0:1c:13:b3: - * 37:6b:37:59:ed:db:6d:b1 + * 68:87:36:54:a3:c6:d5:5f:f5:0f:4f:76:c8:9c:2b: + * 5b:dc:e2:be:14:12:2f:c7:0a:a9:cb:5e:04:59:ca: + * 35:2f:8d:2b:c4:40:e6:7d:25:1b:4d:07:c3:99:9c: + * 16:4f:a5:dc:de:b0:90:f0:de:22:70:80:f4:a6:70: + * e2:96:3d:18:21:bf:2b:27:a4:2d:d7:ae:2b:12:2f: + * 08:36:ee:99:94:ed:f6:a7:d9:1d:a2:f3:1f:44:a4: + * 28:4b:67:35:d6:a8:1b:f8:84:34:34:84:bd:ec:9e: + * 03:08:3c:93:20:8e:af:15:cb:1f:20:08:97:c4:19: + * 3e:fa:36:c6:ab:0e:2f:e7:b3:c0:a7:bc:e4:e0:a6: + * 08:1c:69:20:4d:78:bd:7a:e5:25:48:60:9e:2e:50: + * 8d:36:1e:07:e9:d5:0d:39:67:41:42:24:db:87:e5: + * 77:76:fd:5e:d5:c6:e5:d3:b0:98:71:48:69:47:4f: + * 46:05:0c:9e:58:45:2e:e2:27:d0:f6:11:05:78:ad: + * 83:5a:5b:ec:d7:2e:26:5a:a5:4f:9e:52:84:2c:1f: + * 59:1a:78:56:0a:44:54:c6:37:64:01:ca:e4:a8:01: + * c7:86:c1:b4:d6:6c:7a:15:9a:65:69:46:9e:fd:f6: + * 08:17:0c:6c:ac:38:bd:c2:cd:da:ef:54:7a:48:92: + * 4d * prime1: - * 00:d8:04:f2:8e:83:78:64:68:61:e8:3a:1a:47:2a: - * ab:50:e8:45:64:95:d8:a1:1b:fd:e2:e1:67:a3:46: - * 89:de:95:73:7e:1d:18:75:2a:b0:76:1c:1c:74:33: - * c0:ff:a8:0c:cf:d6:2d:eb:35:29:52:1d:ea:f8:e7: - * d6:11:4c:99:c7 + * 00:e4:43:cc:51:25:aa:1d:90:41:95:2c:e8:9f:aa: + * 1c:9b:ea:bd:fd:29:e5:68:6b:28:00:ec:31:31:36: + * d0:3d:84:db:c5:5d:32:f6:38:b9:04:4f:45:cb:19: + * f5:88:cd:a8:fc:70:b8:6d:98:68:a6:b4:9e:c1:da: + * fd:db:eb:1a:53:3c:3b:e6:85:d2:6f:03:45:7a:ad: + * 49:8c:c3:96:a7:46:a4:bb:3b:48:d3:d7:1c:b4:3c: + * f7:04:0a:a3:85:9d:94:3e:bd:35:f5:34:21:3d:08: + * 89:df:c5:54:af:cf:90:f7:d8:5c:57:c5:77:5a:c8: + * d1:b3:8f:ee:01:5c:07:13:3f * prime2: - * 00:c4:55:ff:b1:56:12:9f:4e:c1:1e:ff:59:86:7e: - * 97:5d:cb:7f:0a:3e:37:cf:fb:4a:35:bc:e5:35:b7: - * 31:a9:0c:10:7a:bc:37:20:7e:75:f1:41:f6:60:e0: - * 3e:18:3d:e5:5d:b2:a9:f8:cc:ad:a0:52:d6:bf:cc: - * e0:e1:84:ff:2f + * 00:ac:c4:a0:cc:7c:51:db:65:0a:02:da:bc:d8:77: + * 21:8c:d3:30:ae:ec:50:60:4b:b9:39:c7:2d:bd:98: + * aa:4f:9b:44:74:ab:f8:86:de:e2:44:15:73:7a:cd: + * d5:46:f2:03:62:c5:87:9c:6d:91:d5:7a:9a:17:c2: + * c6:2f:29:0e:8a:a4:a9:f4:c2:63:a2:77:97:bf:c6: + * 90:e8:39:70:87:cc:fd:62:4f:d2:3d:e7:47:70:fb: + * f3:bd:bd:5c:9c:77:fe:23:33:7d:83:ef:cb:0e:4e: + * f1:dd:05:47:40:97:f4:da:b6:1f:b9:8d:e2:92:04: + * 09:be:fb:6a:97:29:27:ac:f3 * exponent1: - * 7e:a6:a7:ef:96:75:47:a9:4b:7d:f4:52:e3:d6:c8: - * 8a:af:23:c0:4d:7a:ad:3a:d4:27:e9:2f:f2:32:b1: - * 32:a7:3d:07:7b:d7:93:1a:6c:4b:53:3f:fb:81:3c: - * 6e:a8:00:9a:fa:60:01:bf:31:72:cb:c7:b0:17:7d: - * 12:b7:6e:91 + * 3f:08:1d:b6:56:b1:38:02:aa:a9:77:c2:30:bc:b7: + * b3:b2:49:8e:4b:f0:66:3a:18:cc:d0:6b:f1:0c:12: + * ca:ba:12:39:d8:b7:86:d8:38:f6:e0:b1:04:19:81: + * fc:a9:d5:bd:07:9f:55:dc:1d:21:d3:84:77:41:72: + * 92:34:c4:8b:31:79:d4:f9:25:17:b4:8e:8e:06:a5: + * e5:b1:e8:ba:fe:3d:e4:d9:c5:0d:82:3c:11:e5:37: + * cc:ac:e7:64:b1:13:cb:93:52:00:08:ca:18:e1:6f: + * b9:13:f3:83:ac:cc:7a:34:0b:a3:cd:0a:5d:4e:50: + * e1:c5:9f:d2:4e:48:41:df * exponent2: - * 00:ab:36:8f:ae:d6:ef:90:6b:3e:30:48:df:8a:50: - * d4:b1:1f:a7:9e:88:19:65:ce:ae:ad:64:17:c2:1b: - * 0a:3c:6f:df:e3:18:45:3e:99:e9:42:45:92:94:72: - * 98:d3:cd:0e:3b:02:76:05:18:80:84:e2:18:91:d4: - * 19:7b:b0:de:53 + * 02:c7:fb:8a:af:29:a6:2d:7f:36:c2:8c:ad:b3:65: + * 3f:de:1a:77:86:68:58:d4:7f:3b:d5:df:ff:a0:58: + * 85:85:8b:59:91:77:23:bc:ac:c9:c9:ca:9d:1c:79: + * 25:76:39:e5:ba:26:4f:b7:57:d4:a6:ef:9a:18:51: + * 96:6a:c3:c8:29:94:6e:d3:3e:45:5c:45:7e:19:d5: + * 35:57:cf:5e:f0:46:d7:f1:4f:02:1e:1a:01:50:9d: + * 00:dd:ee:82:ba:4f:c6:03:4b:2e:f7:8a:3e:45:b9: + * 11:04:c7:bb:db:76:5e:9a:f5:f1:c7:bd:f0:f9:cd: + * aa:5c:63:bf:e1:32:b9:4f * coefficient: - * 71:07:aa:8f:59:b5:7c:fd:db:21:53:f9:58:6c:35: - * cd:bd:07:c9:bf:b2:a5:09:76:d0:9c:31:df:e3:1a: - * 90:05:bb:a1:87:b9:f8:ea:21:90:69:42:c9:3a:df: - * 06:f0:11:20:0f:65:9f:a4:93:53:b5:91:2e:46:21: - * 12:d7:eb:4f - * + * 50:4c:e6:1e:23:f3:e2:2b:d6:3f:87:53:fb:19:53: + * 4b:84:21:0b:77:31:ed:8d:c3:0c:ea:31:b0:a6:38: + * a9:e6:44:6e:18:05:53:8f:4a:5f:75:e5:3e:b5:26: + * 9b:46:3d:73:e7:c1:2a:a6:3e:c3:cd:41:b1:a6:55: + * 57:84:11:13:ec:44:92:59:7f:dd:0d:67:30:d3:b7: + * 13:ee:9e:2d:ea:be:b3:ca:4a:f0:6e:4f:22:e8:be: + * 8b:8d:9b:2c:30:a5:ed:2c:2b:13:4c:f7:61:19:64: + * 35:9d:b0:c8:10:85:01:e7:2a:70:13:00:39:c5:73: + * 63:34:fd:28:2d:7f:8d:20 + * -----BEGIN PRIVATE KEY----- + * MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCaDOCPqAJ+Wu/t + * skKtCE6RusKtm3nXmw/90vgVLxmJgBAAAhltJ8KQ16UjU3RuZCh8JKrt6iFZ3KNc + * tclCMU+i3vsJfHPtiAQ08RWtPWDNysUTmdOfm7KScMu6Sz0glq2+klPtVDvFFL3P + * 1A/LBU/9K57gULtlE5LA1r1NAgxwtmXUfbRNw98sCJ7SPmkyRm9vytFzpJQH7xTj + * 2p4vwKwOEDNMaHnzeUDW6TzC5nDgic6geqiEKIUyNwiwz7F/X7wfpT3v1mioFyFf + * h9VLtczueI3dsShqwPtkvbdwAjMDC7i4uwiC9o4FJ9E75sWsTYVboR2jSF0DFXZj + * bHEhPpjNAgMBAAECggEAaIc2VKPG1V/1D092yJwrW9zivhQSL8cKqcteBFnKNS+N + * K8RA5n0lG00Hw5mcFk+l3N6wkPDeInCA9KZw4pY9GCG/KyekLdeuKxIvCDbumZTt + * 9qfZHaLzH0SkKEtnNdaoG/iENDSEveyeAwg8kyCOrxXLHyAIl8QZPvo2xqsOL+ez + * wKe85OCmCBxpIE14vXrlJUhgni5QjTYeB+nVDTlnQUIk24fld3b9XtXG5dOwmHFI + * aUdPRgUMnlhFLuIn0PYRBXitg1pb7NcuJlqlT55ShCwfWRp4VgpEVMY3ZAHK5KgB + * x4bBtNZsehWaZWlGnv32CBcMbKw4vcLN2u9UekiSTQKBgQDkQ8xRJaodkEGVLOif + * qhyb6r39KeVoaygA7DExNtA9hNvFXTL2OLkET0XLGfWIzaj8cLhtmGimtJ7B2v3b + * 6xpTPDvmhdJvA0V6rUmMw5anRqS7O0jT1xy0PPcECqOFnZQ+vTX1NCE9CInfxVSv + * z5D32FxXxXdayNGzj+4BXAcTPwKBgQCsxKDMfFHbZQoC2rzYdyGM0zCu7FBgS7k5 + * xy29mKpPm0R0q/iG3uJEFXN6zdVG8gNixYecbZHVepoXwsYvKQ6KpKn0wmOid5e/ + * xpDoOXCHzP1iT9I950dw+/O9vVycd/4jM32D78sOTvHdBUdAl/Tath+5jeKSBAm+ + * +2qXKSes8wKBgD8IHbZWsTgCqql3wjC8t7OySY5L8GY6GMzQa/EMEsq6EjnYt4bY + * OPbgsQQZgfyp1b0Hn1XcHSHThHdBcpI0xIsxedT5JRe0jo4GpeWx6Lr+PeTZxQ2C + * PBHlN8ys52SxE8uTUgAIyhjhb7kT84OszHo0C6PNCl1OUOHFn9JOSEHfAoGAAsf7 + * iq8ppi1/NsKMrbNlP94ad4ZoWNR/O9Xf/6BYhYWLWZF3I7ysycnKnRx5JXY55bom + * T7dX1KbvmhhRlmrDyCmUbtM+RVxFfhnVNVfPXvBG1/FPAh4aAVCdAN3ugrpPxgNL + * LveKPkW5EQTHu9t2Xpr18ce98PnNqlxjv+EyuU8CgYBQTOYeI/PiK9Y/h1P7GVNL + * hCELdzHtjcMM6jGwpjip5kRuGAVTj0pfdeU+tSabRj1z58Eqpj7DzUGxplVXhBET + * 7ESSWX/dDWcw07cT7p4t6r6zykrwbk8i6L6LjZssMKXtLCsTTPdhGWQ1nbDIEIUB + * 5ypwEwA5xXNjNP0oLX+NIA== + * -----END PRIVATE KEY----- * * server certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 8 (0x8) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:43:04 2008 GMT - * Not After : Aug 25 03:43:04 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Server, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * ED:6E:DB:F4:B5:56:C8:FB:1A:06:61:3F:0F:08:BB:A6:04:D8:16:54 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * DNS:localhost - * Signature Algorithm: md5WithRSAEncryption0 - * + * Data: + * Version: 3 (0x2) + * Serial Number: 106315679 (0x6563f9f) + * Signature Algorithm: sha1WithRSAEncryption + * Issuer: C=Us, ST=Some-State, L=Some-City, O=Some-Org + * Validity + * Not Before: Jul 1 04:16:55 2024 GMT + * Not After : Jul 2 04:16:55 2034 GMT + * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, CN=localhost ou=SSL-Server + * Subject Public Key Info: + * Public Key Algorithm: rsaEncryption + * Public-Key: (2048 bit) + * Modulus: + * 00:9a:0c:e0:8f:a8:02:7e:5a:ef:ed:b2:42:ad:08: + * 4e:91:ba:c2:ad:9b:79:d7:9b:0f:fd:d2:f8:15:2f: + * 19:89:80:10:00:02:19:6d:27:c2:90:d7:a5:23:53: + * 74:6e:64:28:7c:24:aa:ed:ea:21:59:dc:a3:5c:b5: + * c9:42:31:4f:a2:de:fb:09:7c:73:ed:88:04:34:f1: + * 15:ad:3d:60:cd:ca:c5:13:99:d3:9f:9b:b2:92:70: + * cb:ba:4b:3d:20:96:ad:be:92:53:ed:54:3b:c5:14: + * bd:cf:d4:0f:cb:05:4f:fd:2b:9e:e0:50:bb:65:13: + * 92:c0:d6:bd:4d:02:0c:70:b6:65:d4:7d:b4:4d:c3: + * df:2c:08:9e:d2:3e:69:32:46:6f:6f:ca:d1:73:a4: + * 94:07:ef:14:e3:da:9e:2f:c0:ac:0e:10:33:4c:68: + * 79:f3:79:40:d6:e9:3c:c2:e6:70:e0:89:ce:a0:7a: + * a8:84:28:85:32:37:08:b0:cf:b1:7f:5f:bc:1f:a5: + * 3d:ef:d6:68:a8:17:21:5f:87:d5:4b:b5:cc:ee:78: + * 8d:dd:b1:28:6a:c0:fb:64:bd:b7:70:02:33:03:0b: + * b8:b8:bb:08:82:f6:8e:05:27:d1:3b:e6:c5:ac:4d: + * 85:5b:a1:1d:a3:48:5d:03:15:76:63:6c:71:21:3e: + * 98:cd + * Exponent: 65537 (0x10001) + * X509v3 extensions: + * X509v3 Subject Key Identifier: + * 5C:AF:44:B1:48:B8:59:9A:64:53:9D:2E:A6:B2:09:D3:0A:92:04:83 + * X509v3 Key Usage: + * Digital Signature, Non Repudiation, Key Encipherment + * X509v3 Subject Alternative Name: critical + * DNS:localhost + * X509v3 Basic Constraints: + * CA:FALSE + * X509v3 Authority Key Identifier: + * E0:03:90:F6:4F:BB:57:E6:7E:AF:5C:94:25:B3:85:DA:16:0A:51:40 + * Signature Algorithm: sha1WithRSAEncryption + * Signature Value: + * 9d:22:49:5f:56:23:e6:80:35:cc:ab:44:1c:27:bd:c9:8d:89: + * 93:49:58:e8:c1:7a:68:dd:cf:bd:e0:12:76:06:54:cd:2f:62: + * 9b:54:84:f2:bb:90:a0:bb:37:e2:13:1d:f3:df:41:aa:e0:fe: + * c0:ef:46:78:8d:aa:f4:1b:70:ad:a9:16:24:fa:15:4a:c6:0a: + * 8d:e1:99:93:00:a9:d4:b6:08:5d:8e:65:03:dc:d0:95:fc:95: + * 61:a6:ad:b5:ab:4d:a6:e0:05:48:8c:db:42:42:8a:d6:5e:c0: + * 2a:a0:11:15:b8:07:69:5c:3f:99:a0:bd:53:65:db:4e:cf:46: + * 61:93:09:7b:81:40:ff:5c:fe:4c:eb:f4:ac:de:1f:38:ad:b2: + * 60:28:f6:0e:9f:46:e7:07:8f:20:9a:a4:e1:8f:ab:54:99:76: + * 82:d8:9e:70:c4:da:98:85:71:af:3b:54:e4:01:b4:9e:83:d0: + * 7b:c6:8d:1f:ed:25:08:89:05:e9:87:97:76:5a:a3:85:c3:f8: + * 59:d7:bb:3b:5a:db:cb:ed:5d:ff:ac:21:b9:9a:e2:65:0a:bc: + * de:d1:dc:53:94:98:44:97:91:b3:1b:6b:80:0b:9b:57:b3:ae: + * 5c:7c:35:ca:39:71:f7:4e:8f:4a:d7:eb:0b:25:da:b2:1e:17: + * 48:b8:eb:09 * -----BEGIN CERTIFICATE----- - * MIICpDCCAg2gAwIBAgIBCDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMDRaFw0yODA4MjUwMzQzMDRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3 - * ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6 - * YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS - * 7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjczBxMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh - * bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAoqVTciHtcvsUj+YaTct8tUh3aTCsKsac - * PHhfQ+ObjiXSgxsKYTX7ym/wk/wvlbUcbqLKxsu7qrcJitH+H9heV1hEHEu65Uoi - * nRugFruyOrwvAylV8Cm2af7ddilmYJ+sdJA6N2M3xJRxR0G2LFHEXDNEjYReyexn - * JqCpf5uZGOo= + * MIIDpTCCAo2gAwIBAgIEBlY/nzANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV + * czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD + * VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTVaFw0zNDA3MDIwNDE2NTVaMGsx + * CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l + * LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMSAwHgYDVQQDExdsb2NhbGhvc3Qgb3U9 + * U1NMLVNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJoM4I+o + * An5a7+2yQq0ITpG6wq2bedebD/3S+BUvGYmAEAACGW0nwpDXpSNTdG5kKHwkqu3q + * IVnco1y1yUIxT6Le+wl8c+2IBDTxFa09YM3KxROZ05+bspJwy7pLPSCWrb6SU+1U + * O8UUvc/UD8sFT/0rnuBQu2UTksDWvU0CDHC2ZdR9tE3D3ywIntI+aTJGb2/K0XOk + * lAfvFOPani/ArA4QM0xoefN5QNbpPMLmcOCJzqB6qIQohTI3CLDPsX9fvB+lPe/W + * aKgXIV+H1Uu1zO54jd2xKGrA+2S9t3ACMwMLuLi7CIL2jgUn0TvmxaxNhVuhHaNI + * XQMVdmNscSE+mM0CAwEAAaNzMHEwHQYDVR0OBBYEFFyvRLFIuFmaZFOdLqayCdMK + * kgSDMAsGA1UdDwQEAwIF4DAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwCQYDVR0T + * BAIwADAfBgNVHSMEGDAWgBTgA5D2T7tX5n6vXJQls4XaFgpRQDANBgkqhkiG9w0B + * AQUFAAOCAQEAnSJJX1Yj5oA1zKtEHCe9yY2Jk0lY6MF6aN3PveASdgZUzS9im1SE + * 8ruQoLs34hMd899BquD+wO9GeI2q9BtwrakWJPoVSsYKjeGZkwCp1LYIXY5lA9zQ + * lfyVYaattatNpuAFSIzbQkKK1l7AKqARFbgHaVw/maC9U2XbTs9GYZMJe4FA/1z+ + * TOv0rN4fOK2yYCj2Dp9G5wePIJqk4Y+rVJl2gtiecMTamIVxrztU5AG0noPQe8aN + * H+0lCIkF6YeXdlqjhcP4Wde7O1rby+1d/6whuZriZQq83tHcU5SYRJeRsxtrgAub + * V7OuXHw1yjlx906PStfrCyXash4XSLjrCQ== * -----END CERTIFICATE----- * * * TLS client certificate: * client private key: - * ----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,FA2A435CD35A9390 - * - * Z+Y2uaETbsUWIyJUyVu1UV2G4rgFYJyACZT6Tp1KjRtxflSh2kXkJ9MpuXMXA0V4 - * Yy3fDzPqCL9NJmQAYRlAx/W/+j4F5EyMWDIx8fUxzONRZyoiwF7jLm+KscAfv6Pf - * q7ItWOdj3z7IYrwlB8YIGd3F2cDKT3S+lYRk7rKb/qT7itbuHnY4Ardh3yl+MZak - * jBp+ELUlRsUqSr1V0LoM+0rCCykarpyfhpxEcqsrl0v9Cyi5uhU50/oKv5zql3SH - * l2ImgDjp3batAs8+Bd4NF2aqi0a7Hy44JUHxRm4caZryU/i/D9N1MbuM6882HLat - * 5N0G+NaIUfywa8mjwq2D5aiit18HqKA6XeRRYeJ5Dvu9DCO4GeFSwcUFIBMI0L46 - * 7s114+oDodg57pMgITi+04vmUxvqlN9aiyd7f5Fgd7PeHGeOdbMz1NaJLJaPI9++ - * NakK8eK9iwT/Gdq0Uap5/CHW7vCT5PO+h3HY0STH0lWStXhdWnFO04zTdywsbSp+ - * DLpHeFT66shfeUlxR0PsCbG9vPRt/QmGLeYQZITppWo/ylSq4j+pRIuXvuWHdBRN - * rTZ8QF4Y7AxQUXVz1j1++s6ZMHTzaK2i9HrhmDs1MbJl+QwWre3Xpv3LvTVz3k5U - * wX8kuY1m3STt71QCaRWENq5sRaMImLxZbxc/ivFl9RAzUqo4NCxLod/QgA4iLqtO - * ztnlpzwlC/F8HbQ1oqYWwnZAPhzU/cULtstl+Yrws2c2atO323LbPXZqbASySgig - * sNpFXQMObdfP6LN23bY+1SvtK7V4NUTNhpdIc6INQAQ= - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICWwIBAAKBgQC78EA2rCZUTvSjWgAvaSFvuXo6k+yi9uGOx2PYLxIwmS6w8o/4 - * Jy0keCiE9wG/jUR53TvSVfPOPLJbIX3v/TNKsaP/xsibuQ98QTWX+ds6BWAFFa9Z - * F5KjEK0WHOQHU6+odqJWKpLT+SjgeM9eH0irXBnd4WdDunWN9YKsQ5JEGwIDAQAB - * AoGAEbdqNj0wN85hnWyEi/ObJU8UyKTdL9eaF72QGfcF/fLSxfd3vurihIeXOkGW - * tpn4lIxYcVGM9CognhqgJpl11jFTQzn1KqZ+NEJRKkCHA4hDabKJbSC9fXHvRwrf - * BsFpZqgiNxp3HseUTiwnaUVeyPgMt/jAj5nB5Sib+UyUxrECQQDnNQBiF2aifEg6 - * zbJOOC7he5CHAdkFxSxWVFVHL6EfXfqdLVkUohMbgZv+XxyIeU2biOExSg49Kds3 - * FOKgTau1AkEA0Bd1haj6QuCo8I0AXm2WO+MMTZMTvtHD/bGjKNM+fT4I8rKYnQRX - * 1acHdqS9Xx2rNJqZgkMmpESIdPR2fc4yjwJALFeM6EMmqvj8/VIf5UJ/Mz14fXwM - * PEARfckUxd9LnnFutCBTWlKvKXJVEZb6KO5ixPaegc57Jp3Vbh3yTN44lQJADD/1 - * SSMDaIB1MYP7a5Oj7m6VQNPRq8AJe5vDcRnOae0G9dKRrVyeFxO4GsHj6/+BHp2j - * P8nYMn9eURQ7DXjf/QJAAQzMlWnKGSO8pyTDtnQx3hRMoUkOEhmNq4bQhLkYqtnY - * FcqpUQ2qMjW+NiNWk5HnTrMS3L9EdJobMUzaNZLy4w== - * -----END RSA PRIVATE KEY----- * - * Private-Key: (1024 bit) + * Private-Key: (2048 bit, 2 primes) * modulus: - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b + * 00:cc:bf:92:3c:a6:57:74:1f:58:ad:c7:69:88:6f: + * 59:32:47:50:60:22:e4:98:49:0e:3e:1d:b8:ba:e2: + * 3b:b6:71:5b:fd:64:02:6d:0d:50:77:72:6e:a8:3d: + * 5d:d4:bd:1f:76:51:dc:9a:d0:d6:3e:d0:31:a5:24: + * 5a:2c:be:77:fa:88:a1:fa:06:41:c8:0f:47:70:47: + * 24:99:50:52:44:5b:30:62:5b:65:35:c4:28:b0:5c: + * ee:d0:1b:eb:39:2b:0b:a1:ac:96:48:da:56:6c:e0: + * e3:e6:e3:dd:45:cb:51:33:8d:40:43:d7:f0:a4:31: + * aa:b5:c0:df:4b:df:2b:0a:ed:7e:10:0c:ae:1f:96: + * a2:10:1e:6b:d0:f9:37:8b:df:0d:0e:02:35:f8:58: + * bc:6e:b5:57:0e:2f:ea:20:e6:73:9a:e5:6b:82:70: + * 25:bb:51:9a:7c:9d:e2:50:3d:cf:1e:24:3e:92:55: + * cf:2a:ad:0d:84:8f:a8:43:24:cd:ad:50:64:74:c2: + * 73:b6:e1:92:1c:b2:2b:8c:2d:7b:96:a6:41:61:5c: + * 1b:8f:78:28:51:40:ed:41:90:ce:1d:b8:26:81:47: + * 6b:e3:57:41:74:4e:20:f0:5a:1b:97:37:91:86:19: + * c5:f2:6d:04:c9:78:2b:5a:16:bc:fc:2b:71:5b:d0: + * 00:4f * publicExponent: 65537 (0x10001) * privateExponent: - * 11:b7:6a:36:3d:30:37:ce:61:9d:6c:84:8b:f3:9b: - * 25:4f:14:c8:a4:dd:2f:d7:9a:17:bd:90:19:f7:05: - * fd:f2:d2:c5:f7:77:be:ea:e2:84:87:97:3a:41:96: - * b6:99:f8:94:8c:58:71:51:8c:f4:2a:20:9e:1a:a0: - * 26:99:75:d6:31:53:43:39:f5:2a:a6:7e:34:42:51: - * 2a:40:87:03:88:43:69:b2:89:6d:20:bd:7d:71:ef: - * 47:0a:df:06:c1:69:66:a8:22:37:1a:77:1e:c7:94: - * 4e:2c:27:69:45:5e:c8:f8:0c:b7:f8:c0:8f:99:c1: - * e5:28:9b:f9:4c:94:c6:b1 + * 62:b2:d6:63:b6:2b:e2:26:5a:31:2b:37:8c:35:60: + * e2:03:ce:93:09:3e:f8:c9:fe:bb:a2:c8:32:0e:6c: + * 8a:7e:0a:c2:13:3b:b8:25:fa:ec:19:95:8e:34:46: + * cf:0e:7b:e4:25:82:1a:7f:21:48:16:44:58:3f:35: + * d8:eb:d8:1a:45:53:0f:9b:84:8a:54:13:33:e4:97: + * 97:f0:48:37:fb:5d:4f:8c:8f:35:63:e1:d9:62:73: + * 1c:8e:d8:cd:2e:1a:e5:4c:b5:05:59:7a:df:f1:68: + * eb:1c:5c:c6:10:44:8c:7d:42:c5:71:8a:e7:1b:aa: + * 17:03:6a:a0:c0:6b:97:50:17:ad:6e:5e:d9:db:6f: + * 3e:e9:3f:35:c3:45:bc:e8:3d:5a:b4:b9:3f:53:80: + * 64:dc:12:24:35:35:bd:98:bb:8d:fa:19:a3:5e:9e: + * ac:70:4a:fc:8d:ae:55:8b:71:81:0e:4d:c8:2f:87: + * b0:44:f7:4f:dc:a8:c8:50:b5:95:24:63:74:13:54: + * 58:de:fc:e0:75:eb:f4:06:58:83:12:4c:56:c4:c4: + * 18:0c:ea:a3:e7:25:a3:de:19:23:a2:5a:2a:b6:56: + * 04:bc:65:ba:7c:0a:f4:91:10:22:88:3f:9d:be:58: + * 43:4c:2e:ad:db:d6:32:cf:8e:b5:05:55:39:8b:e1: + * 01 * prime1: - * 00:e7:35:00:62:17:66:a2:7c:48:3a:cd:b2:4e:38: - * 2e:e1:7b:90:87:01:d9:05:c5:2c:56:54:55:47:2f: - * a1:1f:5d:fa:9d:2d:59:14:a2:13:1b:81:9b:fe:5f: - * 1c:88:79:4d:9b:88:e1:31:4a:0e:3d:29:db:37:14: - * e2:a0:4d:ab:b5 + * 00:f1:da:c2:8a:e5:66:45:8a:14:fc:08:6e:fb:aa: + * 50:d2:8c:b1:c4:f4:88:26:d4:b8:c4:63:30:ca:e3: + * 0c:6c:50:d4:93:5c:1c:13:37:60:21:11:3b:d1:f1: + * 9f:4c:0d:7b:0e:53:3d:c9:a4:fb:fa:6b:9e:b4:0a: + * 5d:d3:50:88:d7:be:c3:88:b2:b1:8a:6e:7b:d6:70: + * 88:96:a4:fe:90:ef:d1:84:ad:a8:9e:9f:3a:68:3f: + * 3f:82:07:be:c2:44:1e:d5:a1:a9:1a:db:39:d7:7f: + * 0c:6e:35:5b:1d:33:1b:a9:cd:38:2a:64:d1:70:2a: + * fe:b9:c2:b6:ed:59:19:73:b1 * prime2: - * 00:d0:17:75:85:a8:fa:42:e0:a8:f0:8d:00:5e:6d: - * 96:3b:e3:0c:4d:93:13:be:d1:c3:fd:b1:a3:28:d3: - * 3e:7d:3e:08:f2:b2:98:9d:04:57:d5:a7:07:76:a4: - * bd:5f:1d:ab:34:9a:99:82:43:26:a4:44:88:74:f4: - * 76:7d:ce:32:8f + * 00:d8:b9:3a:38:6c:79:cd:0b:1f:2b:34:74:bf:7a: + * 3d:0c:21:5a:a6:ea:f2:9e:de:68:42:05:7f:ea:a5: + * 00:c9:10:f8:fd:c5:05:8d:03:45:5d:4f:6f:fa:6e: + * 9d:ef:ad:8a:ec:83:d4:ed:57:f3:86:73:15:2f:d2: + * 67:70:d1:62:ef:1d:25:08:59:47:20:62:47:16:35: + * e1:57:38:bf:39:dd:fc:b9:c8:d8:23:53:e2:02:7d: + * 22:31:4c:66:72:96:df:d8:7c:01:2c:71:00:89:18: + * e9:8c:08:44:8c:64:1f:93:9b:7a:97:26:c9:50:d0: + * 87:b2:48:a8:19:71:e1:b3:ff * exponent1: - * 2c:57:8c:e8:43:26:aa:f8:fc:fd:52:1f:e5:42:7f: - * 33:3d:78:7d:7c:0c:3c:40:11:7d:c9:14:c5:df:4b: - * 9e:71:6e:b4:20:53:5a:52:af:29:72:55:11:96:fa: - * 28:ee:62:c4:f6:9e:81:ce:7b:26:9d:d5:6e:1d:f2: - * 4c:de:38:95 + * 23:98:dd:35:70:5a:43:35:f5:ac:ba:d9:0a:f5:a0: + * 7b:bc:f5:95:55:a0:8c:86:96:c3:61:0e:17:6e:9f: + * af:79:9e:30:2a:48:7f:93:90:f4:8d:02:ce:fd:cf: + * 42:74:61:7e:54:46:2d:dd:b8:b0:bd:12:58:d1:85: + * c9:ca:7a:b9:b6:7c:35:2c:87:f1:26:1d:d8:0c:2c: + * 2e:70:0e:7f:ea:ac:5d:e8:e9:7e:9f:55:0b:6e:f3: + * bc:01:c3:d3:f8:0e:c9:c6:c7:8b:0a:65:53:10:82: + * 15:de:88:90:9d:ab:1e:ac:f3:ed:59:75:72:1b:01: + * ee:f9:77:cf:2b:64:11:a1 * exponent2: - * 0c:3f:f5:49:23:03:68:80:75:31:83:fb:6b:93:a3: - * ee:6e:95:40:d3:d1:ab:c0:09:7b:9b:c3:71:19:ce: - * 69:ed:06:f5:d2:91:ad:5c:9e:17:13:b8:1a:c1:e3: - * eb:ff:81:1e:9d:a3:3f:c9:d8:32:7f:5e:51:14:3b: - * 0d:78:df:fd + * 00:9e:29:6f:87:c6:02:8d:d5:54:05:df:de:63:ee: + * fd:a6:60:a1:1b:b7:d3:20:86:07:68:47:43:37:26: + * fc:0f:c0:c7:35:cc:17:64:f5:c2:25:7a:d7:a9:d8: + * 18:82:d6:0f:d0:d3:d5:0c:f1:66:d3:f4:20:be:29: + * bb:3b:e6:53:61:55:cf:b4:ec:12:b0:5b:88:ad:78: + * dc:df:1e:96:cf:d0:65:a3:e0:23:7c:84:b7:28:41: + * d2:36:50:1f:63:f9:1f:9b:89:c4:01:7e:e6:79:27: + * 29:29:fc:ce:a9:f6:57:e5:0d:4e:c6:08:94:5a:da: + * 14:6d:d4:00:79:b1:56:9a:59 * coefficient: - * 01:0c:cc:95:69:ca:19:23:bc:a7:24:c3:b6:74:31: - * de:14:4c:a1:49:0e:12:19:8d:ab:86:d0:84:b9:18: - * aa:d9:d8:15:ca:a9:51:0d:aa:32:35:be:36:23:56: - * 93:91:e7:4e:b3:12:dc:bf:44:74:9a:1b:31:4c:da: - * 35:92:f2:e3 + * 6c:73:0d:fe:c7:22:15:5d:8c:a1:91:2b:d1:88:e8: + * 91:f9:d0:3e:d0:ba:c4:74:88:ce:14:20:4e:1e:4b: + * c5:91:8f:c1:56:e9:74:e0:f6:cf:71:91:ed:2c:f5: + * 90:9d:d6:c8:cd:f5:79:dc:6e:b3:83:3e:fa:d6:b4: + * 60:d9:3a:52:12:76:9d:92:fb:db:26:ee:43:33:c4: + * 0b:84:74:1b:91:e0:41:8b:cc:cc:24:da:52:af:2d: + * 42:e7:11:57:0d:aa:66:af:1a:ba:c2:8e:6a:ee:8f: + * 2c:e6:5b:76:38:96:bb:7a:2f:59:fe:de:a1:02:fc: + * 12:3a:aa:9f:3c:0e:a4:78 + * writing RSA key + * -----BEGIN PRIVATE KEY----- + * MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMv5I8pld0H1it + * x2mIb1kyR1BgIuSYSQ4+Hbi64ju2cVv9ZAJtDVB3cm6oPV3UvR92Udya0NY+0DGl + * JFosvnf6iKH6BkHID0dwRySZUFJEWzBiW2U1xCiwXO7QG+s5KwuhrJZI2lZs4OPm + * 491Fy1EzjUBD1/CkMaq1wN9L3ysK7X4QDK4flqIQHmvQ+TeL3w0OAjX4WLxutVcO + * L+og5nOa5WuCcCW7UZp8neJQPc8eJD6SVc8qrQ2Ej6hDJM2tUGR0wnO24ZIcsiuM + * LXuWpkFhXBuPeChRQO1BkM4duCaBR2vjV0F0TiDwWhuXN5GGGcXybQTJeCtaFrz8 + * K3Fb0ABPAgMBAAECggEAYrLWY7Yr4iZaMSs3jDVg4gPOkwk++Mn+u6LIMg5sin4K + * whM7uCX67BmVjjRGzw575CWCGn8hSBZEWD812OvYGkVTD5uEilQTM+SXl/BIN/td + * T4yPNWPh2WJzHI7YzS4a5Uy1BVl63/Fo6xxcxhBEjH1CxXGK5xuqFwNqoMBrl1AX + * rW5e2dtvPuk/NcNFvOg9WrS5P1OAZNwSJDU1vZi7jfoZo16erHBK/I2uVYtxgQ5N + * yC+HsET3T9yoyFC1lSRjdBNUWN784HXr9AZYgxJMVsTEGAzqo+clo94ZI6JaKrZW + * BLxlunwK9JEQIog/nb5YQ0wurdvWMs+OtQVVOYvhAQKBgQDx2sKK5WZFihT8CG77 + * qlDSjLHE9Igm1LjEYzDK4wxsUNSTXBwTN2AhETvR8Z9MDXsOUz3JpPv6a560Cl3T + * UIjXvsOIsrGKbnvWcIiWpP6Q79GEraienzpoPz+CB77CRB7Voaka2znXfwxuNVsd + * MxupzTgqZNFwKv65wrbtWRlzsQKBgQDYuTo4bHnNCx8rNHS/ej0MIVqm6vKe3mhC + * BX/qpQDJEPj9xQWNA0VdT2/6bp3vrYrsg9TtV/OGcxUv0mdw0WLvHSUIWUcgYkcW + * NeFXOL853fy5yNgjU+ICfSIxTGZylt/YfAEscQCJGOmMCESMZB+Tm3qXJslQ0Iey + * SKgZceGz/wKBgCOY3TVwWkM19ay62Qr1oHu89ZVVoIyGlsNhDhdun695njAqSH+T + * kPSNAs79z0J0YX5URi3duLC9EljRhcnKerm2fDUsh/EmHdgMLC5wDn/qrF3o6X6f + * VQtu87wBw9P4DsnGx4sKZVMQghXeiJCdqx6s8+1ZdXIbAe75d88rZBGhAoGBAJ4p + * b4fGAo3VVAXf3mPu/aZgoRu30yCGB2hHQzcm/A/AxzXMF2T1wiV616nYGILWD9DT + * 1QzxZtP0IL4puzvmU2FVz7TsErBbiK143N8els/QZaPgI3yEtyhB0jZQH2P5H5uJ + * xAF+5nknKSn8zqn2V+UNTsYIlFraFG3UAHmxVppZAoGAbHMN/sciFV2MoZEr0Yjo + * kfnQPtC6xHSIzhQgTh5LxZGPwVbpdOD2z3GR7Sz1kJ3WyM31edxus4M++ta0YNk6 + * UhJ2nZL72ybuQzPEC4R0G5HgQYvMzCTaUq8tQucRVw2qZq8ausKOau6PLOZbdjiW + * u3ovWf7eoQL8EjqqnzwOpHg= + * -----END PRIVATE KEY----- * * client certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 9 (0x9) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:43:24 2008 GMT - * Not After : Aug 25 03:43:24 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * DNS:localhost - * Signature Algorithm: md5WithRSAEncryption - * + * Data: + * Version: 3 (0x2) + * Serial Number: 1500699355 (0x5972dadb) + * Signature Algorithm: sha1WithRSAEncryption + * Issuer: C=Us, ST=Some-State, L=Some-City, O=Some-Org + * Validity + * Not Before: Jul 1 04:16:52 2024 GMT + * Not After : Jul 2 04:16:52 2034 GMT + * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, CN=localhost ou=SSL-Client + * Subject Public Key Info: + * Public Key Algorithm: rsaEncryption + * Public-Key: (2048 bit) + * Modulus: + * 00:cc:bf:92:3c:a6:57:74:1f:58:ad:c7:69:88:6f: + * 59:32:47:50:60:22:e4:98:49:0e:3e:1d:b8:ba:e2: + * 3b:b6:71:5b:fd:64:02:6d:0d:50:77:72:6e:a8:3d: + * 5d:d4:bd:1f:76:51:dc:9a:d0:d6:3e:d0:31:a5:24: + * 5a:2c:be:77:fa:88:a1:fa:06:41:c8:0f:47:70:47: + * 24:99:50:52:44:5b:30:62:5b:65:35:c4:28:b0:5c: + * ee:d0:1b:eb:39:2b:0b:a1:ac:96:48:da:56:6c:e0: + * e3:e6:e3:dd:45:cb:51:33:8d:40:43:d7:f0:a4:31: + * aa:b5:c0:df:4b:df:2b:0a:ed:7e:10:0c:ae:1f:96: + * a2:10:1e:6b:d0:f9:37:8b:df:0d:0e:02:35:f8:58: + * bc:6e:b5:57:0e:2f:ea:20:e6:73:9a:e5:6b:82:70: + * 25:bb:51:9a:7c:9d:e2:50:3d:cf:1e:24:3e:92:55: + * cf:2a:ad:0d:84:8f:a8:43:24:cd:ad:50:64:74:c2: + * 73:b6:e1:92:1c:b2:2b:8c:2d:7b:96:a6:41:61:5c: + * 1b:8f:78:28:51:40:ed:41:90:ce:1d:b8:26:81:47: + * 6b:e3:57:41:74:4e:20:f0:5a:1b:97:37:91:86:19: + * c5:f2:6d:04:c9:78:2b:5a:16:bc:fc:2b:71:5b:d0: + * 00:4f + * Exponent: 65537 (0x10001) + * X509v3 extensions: + * X509v3 Subject Key Identifier: + * CD:45:E2:05:92:88:A3:C7:49:28:E7:D3:37:B7:13:92:FB:B1:36:C4 + * X509v3 Key Usage: + * Digital Signature, Non Repudiation, Key Encipherment + * X509v3 Subject Alternative Name: critical + * DNS:localhost + * X509v3 Basic Constraints: + * CA:FALSE + * X509v3 Authority Key Identifier: + * E0:03:90:F6:4F:BB:57:E6:7E:AF:5C:94:25:B3:85:DA:16:0A:51:40 + * Signature Algorithm: sha1WithRSAEncryption + * Signature Value: + * 23:6e:e9:5d:80:0d:b3:86:c9:cd:17:81:33:bd:5b:aa:c0:65: + * 4c:6b:9f:fa:ee:32:e9:89:e1:d0:c7:1d:5c:43:7e:94:ac:83: + * af:91:90:4c:26:61:8d:fe:6b:1a:aa:6e:61:39:b3:24:4a:dc: + * 92:c8:ca:f2:80:b0:05:41:0c:b3:dd:ed:b7:81:42:9a:1e:4e: + * f2:80:6c:72:62:8b:bd:d4:cd:23:7d:7c:e8:6f:e3:67:89:6a: + * 79:19:dd:f6:57:62:12:fa:eb:cd:66:c3:d2:d8:40:5a:1c:dd: + * 7f:9f:b2:34:e9:2a:d6:14:52:ba:6e:a8:9b:0d:a9:a1:03:bf: + * c4:0d:92:3d:59:e4:a9:8e:20:41:39:99:81:70:9d:d0:68:98: + * fc:5f:49:4a:92:e5:a2:c1:51:61:f6:1e:49:56:0b:b6:8c:57: + * db:08:2a:f0:a3:04:dc:a1:04:a2:5c:d0:90:4f:13:8d:1c:e6: + * 2e:7a:63:9c:32:40:65:59:04:5d:71:90:5a:a8:db:6a:30:42: + * 57:5b:0b:df:ce:a1:1f:fa:23:71:f3:57:12:c4:1c:66:3b:37: + * 77:32:28:a7:fb:ad:ee:86:51:4c:80:2f:dd:c8:5b:9f:a7:15: + * 07:fa:2b:5a:ee:93:00:5f:a6:43:22:1b:40:52:15:66:01:84: + * 32:9e:71:21 * -----BEGIN CERTIFICATE----- - * MIICpDCCAg2gAwIBAgIBCTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMjRaFw0yODA4MjUwMzQzMjRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas - * JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV - * 8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq - * ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjczBxMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh - * bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAm25gJyqW1JznQ1EyOtTGswBVwfgBOf+F - * HJuBTcflYQLbTD/AETPQJGvZU9tdhuLtbG3OPhR7vSY8zeAbfM3dbH7QFr3r47Gj - * XEH7qM/MX+Z3ifVaC4MeJmrYQkYFSuKeyyKpdRVX4w4nnFHF6OsNASsYrMW6LpxN - * cl/epUcHL7E= + * MIIDpTCCAo2gAwIBAgIEWXLa2zANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV + * czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD + * VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTJaFw0zNDA3MDIwNDE2NTJaMGsx + * CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l + * LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMSAwHgYDVQQDExdsb2NhbGhvc3Qgb3U9 + * U1NMLUNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMy/kjym + * V3QfWK3HaYhvWTJHUGAi5JhJDj4duLriO7ZxW/1kAm0NUHdybqg9XdS9H3ZR3JrQ + * 1j7QMaUkWiy+d/qIofoGQcgPR3BHJJlQUkRbMGJbZTXEKLBc7tAb6zkrC6Gslkja + * Vmzg4+bj3UXLUTONQEPX8KQxqrXA30vfKwrtfhAMrh+WohAea9D5N4vfDQ4CNfhY + * vG61Vw4v6iDmc5rla4JwJbtRmnyd4lA9zx4kPpJVzyqtDYSPqEMkza1QZHTCc7bh + * khyyK4wte5amQWFcG494KFFA7UGQzh24JoFHa+NXQXROIPBaG5c3kYYZxfJtBMl4 + * K1oWvPwrcVvQAE8CAwEAAaNzMHEwHQYDVR0OBBYEFM1F4gWSiKPHSSjn0ze3E5L7 + * sTbEMAsGA1UdDwQEAwIF4DAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwCQYDVR0T + * BAIwADAfBgNVHSMEGDAWgBTgA5D2T7tX5n6vXJQls4XaFgpRQDANBgkqhkiG9w0B + * AQUFAAOCAQEAI27pXYANs4bJzReBM71bqsBlTGuf+u4y6Ynh0McdXEN+lKyDr5GQ + * TCZhjf5rGqpuYTmzJErcksjK8oCwBUEMs93tt4FCmh5O8oBscmKLvdTNI3186G/j + * Z4lqeRnd9ldiEvrrzWbD0thAWhzdf5+yNOkq1hRSum6omw2poQO/xA2SPVnkqY4g + * QTmZgXCd0GiY/F9JSpLlosFRYfYeSVYLtoxX2wgq8KME3KEEolzQkE8TjRzmLnpj + * nDJAZVkEXXGQWqjbajBCV1sL386hH/ojcfNXEsQcZjs3dzIop/ut7oZRTIAv3chb + * n6cVB/orWu6TAF+mQyIbQFIVZgGEMp5xIQ== * -----END CERTIFICATE----- * * - * * Trusted CA certificate: * Certificate: * Data: - * Version: 3 (0x2) - * Serial Number: 0 (0x0) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 02:43:36 2008 GMT - * Not After : Aug 25 02:43:36 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d: - * d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53: - * 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9: - * 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f: - * 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7: - * 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee: - * f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee: - * 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97: - * 89:2a:95:12:4c:d8:09:2a:e9 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Subject Key Identifier: - * FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org - * serial:00 - * - * X509v3 Basic Constraints: - * CA:TRUE - * Signature Algorithm: md5WithRSAEncryption - * + * Version: 3 (0x2) + * Serial Number: 1539881479 (0x5bc8ba07) + * Signature Algorithm: sha1WithRSAEncryption + * Issuer: C=Us, ST=Some-State, L=Some-City, O=Some-Org + * Validity + * Not Before: Jul 1 04:16:50 2024 GMT + * Not After : Jul 2 04:16:50 2034 GMT + * Subject: C=Us, ST=Some-State, L=Some-City, O=Some-Org + * Subject Public Key Info: + * Public Key Algorithm: rsaEncryption + * Public-Key: (2048 bit) + * Modulus: + * 00:bc:a6:55:60:3f:17:74:39:ba:71:8c:ef:11:3f: + * 9d:36:47:d5:02:d1:4d:9d:7e:b8:fe:59:b1:2b:f1: + * b7:b0:0c:31:57:eb:9c:9d:13:f5:4c:5f:fc:c4:9e: + * f9:75:09:0f:96:8f:05:77:30:a8:35:48:71:96:e4: + * a5:7d:1a:81:fb:e6:bf:90:80:60:5d:11:20:54:16: + * 0b:6d:df:64:de:18:d5:98:51:38:9d:c9:d6:5f:de: + * 9d:de:fe:a8:5f:d3:25:3d:ad:f3:2b:45:c8:4a:80: + * 97:14:7b:85:9d:cf:59:08:bb:c7:67:ac:8b:29:f3: + * 1e:93:bf:fb:82:53:c5:ae:b4:bc:55:30:15:a8:7e: + * 3f:82:22:59:43:cc:d2:62:e7:65:67:72:ec:10:8a: + * fc:05:90:91:72:dd:e9:6f:e2:9f:0c:ab:a1:83:55: + * 02:23:b7:a3:c3:50:ab:be:0b:bb:51:75:50:d1:a8: + * c9:e5:f5:06:fe:00:09:a6:1b:8a:16:29:0d:ab:00: + * 3e:bc:d2:73:d9:37:d7:d9:9a:58:6e:2d:2a:f6:76: + * ae:f4:ea:6d:70:de:7f:e3:04:43:c0:4f:91:3f:78: + * 58:d7:c2:ad:74:eb:04:9d:d0:7e:82:b8:7a:97:44: + * 61:fa:41:45:a6:ca:7d:a5:2e:fc:f9:a6:cf:61:cd: + * 75:bf + * Exponent: 65537 (0x10001) + * X509v3 extensions: + * X509v3 Subject Key Identifier: + * E0:03:90:F6:4F:BB:57:E6:7E:AF:5C:94:25:B3:85:DA:16:0A:51:40 + * X509v3 Basic Constraints: critical + * CA:TRUE + * Signature Algorithm: sha1WithRSAEncryption + * Signature Value: + * 1f:89:34:e3:ee:05:33:3b:18:ca:96:13:3d:ad:cd:5a:e6:24: + * 46:94:36:ad:37:a5:36:a9:92:37:f9:ed:07:dd:44:5b:c9:2e: + * 68:f7:82:f3:58:1c:64:ed:64:d0:ad:eb:30:15:e0:04:3a:d7: + * c8:c7:9d:65:76:ae:84:e4:2e:2d:0d:68:09:0d:e5:ae:cc:a7: + * 54:86:ad:ff:00:95:85:01:49:db:5b:8e:c2:6f:e7:19:10:17: + * f7:03:b9:a8:97:21:a2:fc:7f:c0:e0:7a:12:64:b8:70:f5:e8: + * b6:e1:25:f7:eb:32:3e:46:ce:43:55:fc:0b:62:59:90:61:63: + * f9:94:6c:95:63:31:1b:00:59:1f:72:9d:d0:0b:4f:cd:02:eb: + * de:20:4e:60:48:4e:ea:ad:3c:0f:1d:bf:1a:69:3d:a8:3d:8b: + * f5:a2:ae:8c:4f:d7:0e:b3:e1:9b:b3:2c:89:19:18:da:db:e1: + * 6d:d5:ab:c8:b8:48:57:d8:8b:33:01:d4:97:91:d9:da:34:a1: + * ef:36:00:e1:38:19:34:8f:0d:47:af:57:cf:59:d6:8b:0d:9e: + * 89:05:82:3d:3c:f3:45:1d:4a:3f:0e:0f:5a:28:6f:5c:e1:e9: + * 60:72:87:28:b6:97:44:8b:d7:c6:cd:cb:dc:5a:5d:60:f1:b4: + * 37:ee:44:db * -----BEGIN CERTIFICATE----- - * MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB - * gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX - * 4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj - * 7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G - * A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ - * hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt - * U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw - * DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA - * ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ - * LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P - * 6Mvf0r1PNTY2hwTJLJmKtg== - * -----END CERTIFICATE--- + * MIIDQjCCAiqgAwIBAgIEW8i6BzANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV + * czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD + * VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTBaFw0zNDA3MDIwNDE2NTBaMEkx + * CzAJBgNVBAYTAlVzMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l + * LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A + * MIIBCgKCAQEAvKZVYD8XdDm6cYzvET+dNkfVAtFNnX64/lmxK/G3sAwxV+ucnRP1 + * TF/8xJ75dQkPlo8FdzCoNUhxluSlfRqB++a/kIBgXREgVBYLbd9k3hjVmFE4ncnW + * X96d3v6oX9MlPa3zK0XISoCXFHuFnc9ZCLvHZ6yLKfMek7/7glPFrrS8VTAVqH4/ + * giJZQ8zSYudlZ3LsEIr8BZCRct3pb+KfDKuhg1UCI7ejw1Crvgu7UXVQ0ajJ5fUG + * /gAJphuKFikNqwA+vNJz2TfX2ZpYbi0q9nau9OptcN5/4wRDwE+RP3hY18KtdOsE + * ndB+grh6l0Rh+kFFpsp9pS78+abPYc11vwIDAQABozIwMDAdBgNVHQ4EFgQU4AOQ + * 9k+7V+Z+r1yUJbOF2hYKUUAwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUF + * AAOCAQEAH4k04+4FMzsYypYTPa3NWuYkRpQ2rTelNqmSN/ntB91EW8kuaPeC81gc + * ZO1k0K3rMBXgBDrXyMedZXauhOQuLQ1oCQ3lrsynVIat/wCVhQFJ21uOwm/nGRAX + * 9wO5qJchovx/wOB6EmS4cPXotuEl9+syPkbOQ1X8C2JZkGFj+ZRslWMxGwBZH3Kd + * 0AtPzQLr3iBOYEhO6q08Dx2/Gmk9qD2L9aKujE/XDrPhm7MsiRkY2tvhbdWryLhI + * V9iLMwHUl5HZ2jSh7zYA4TgZNI8NR69Xz1nWiw2eiQWCPTzzRR1KPw4PWihvXOHp + * YHKHKLaXRIvXxs3L3FpdYPG0N+5E2w== + * */ @@ -427,201 +568,342 @@ public class PKIXExtendedTM { */ static String trusedCertStr = "-----BEGIN CERTIFICATE-----\n" + - "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + - "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" + - "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" + - "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" + - "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" + - "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" + - "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" + - "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" + - "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" + - "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" + - "6Mvf0r1PNTY2hwTJLJmKtg==\n" + + "MIIDQjCCAiqgAwIBAgIEW8i6BzANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV\n" + + "czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD\n" + + "VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTBaFw0zNDA3MDIwNDE2NTBaMEkx\n" + + "CzAJBgNVBAYTAlVzMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l\n" + + "LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + + "MIIBCgKCAQEAvKZVYD8XdDm6cYzvET+dNkfVAtFNnX64/lmxK/G3sAwxV+ucnRP1\n" + + "TF/8xJ75dQkPlo8FdzCoNUhxluSlfRqB++a/kIBgXREgVBYLbd9k3hjVmFE4ncnW\n" + + "X96d3v6oX9MlPa3zK0XISoCXFHuFnc9ZCLvHZ6yLKfMek7/7glPFrrS8VTAVqH4/\n" + + "giJZQ8zSYudlZ3LsEIr8BZCRct3pb+KfDKuhg1UCI7ejw1Crvgu7UXVQ0ajJ5fUG\n" + + "/gAJphuKFikNqwA+vNJz2TfX2ZpYbi0q9nau9OptcN5/4wRDwE+RP3hY18KtdOsE\n" + + "ndB+grh6l0Rh+kFFpsp9pS78+abPYc11vwIDAQABozIwMDAdBgNVHQ4EFgQU4AOQ\n" + + "9k+7V+Z+r1yUJbOF2hYKUUAwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUF\n" + + "AAOCAQEAH4k04+4FMzsYypYTPa3NWuYkRpQ2rTelNqmSN/ntB91EW8kuaPeC81gc\n" + + "ZO1k0K3rMBXgBDrXyMedZXauhOQuLQ1oCQ3lrsynVIat/wCVhQFJ21uOwm/nGRAX\n" + + "9wO5qJchovx/wOB6EmS4cPXotuEl9+syPkbOQ1X8C2JZkGFj+ZRslWMxGwBZH3Kd\n" + + "0AtPzQLr3iBOYEhO6q08Dx2/Gmk9qD2L9aKujE/XDrPhm7MsiRkY2tvhbdWryLhI\n" + + "V9iLMwHUl5HZ2jSh7zYA4TgZNI8NR69Xz1nWiw2eiQWCPTzzRR1KPw4PWihvXOHp\n" + + "YHKHKLaXRIvXxs3L3FpdYPG0N+5E2w==\n" + "-----END CERTIFICATE-----"; static String serverCertStr = "-----BEGIN CERTIFICATE-----\n" + - "MIICpDCCAg2gAwIBAgIBCDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMDRaFw0yODA4MjUwMzQzMDRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3\n" + - "ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6\n" + - "YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS\n" + - "7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjczBxMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh\n" + - "bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAoqVTciHtcvsUj+YaTct8tUh3aTCsKsac\n" + - "PHhfQ+ObjiXSgxsKYTX7ym/wk/wvlbUcbqLKxsu7qrcJitH+H9heV1hEHEu65Uoi\n" + - "nRugFruyOrwvAylV8Cm2af7ddilmYJ+sdJA6N2M3xJRxR0G2LFHEXDNEjYReyexn\n" + - "JqCpf5uZGOo=\n" + + "MIIDpTCCAo2gAwIBAgIEBlY/nzANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV\n" + + "czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD\n" + + "VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTVaFw0zNDA3MDIwNDE2NTVaMGsx\n" + + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l\n" + + "LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMSAwHgYDVQQDExdsb2NhbGhvc3Qgb3U9\n" + + "U1NMLVNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJoM4I+o\n" + + "An5a7+2yQq0ITpG6wq2bedebD/3S+BUvGYmAEAACGW0nwpDXpSNTdG5kKHwkqu3q\n" + + "IVnco1y1yUIxT6Le+wl8c+2IBDTxFa09YM3KxROZ05+bspJwy7pLPSCWrb6SU+1U\n" + + "O8UUvc/UD8sFT/0rnuBQu2UTksDWvU0CDHC2ZdR9tE3D3ywIntI+aTJGb2/K0XOk\n" + + "lAfvFOPani/ArA4QM0xoefN5QNbpPMLmcOCJzqB6qIQohTI3CLDPsX9fvB+lPe/W\n" + + "aKgXIV+H1Uu1zO54jd2xKGrA+2S9t3ACMwMLuLi7CIL2jgUn0TvmxaxNhVuhHaNI\n" + + "XQMVdmNscSE+mM0CAwEAAaNzMHEwHQYDVR0OBBYEFFyvRLFIuFmaZFOdLqayCdMK\n" + + "kgSDMAsGA1UdDwQEAwIF4DAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwCQYDVR0T\n" + + "BAIwADAfBgNVHSMEGDAWgBTgA5D2T7tX5n6vXJQls4XaFgpRQDANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEAnSJJX1Yj5oA1zKtEHCe9yY2Jk0lY6MF6aN3PveASdgZUzS9im1SE\n" + + "8ruQoLs34hMd899BquD+wO9GeI2q9BtwrakWJPoVSsYKjeGZkwCp1LYIXY5lA9zQ\n" + + "lfyVYaattatNpuAFSIzbQkKK1l7AKqARFbgHaVw/maC9U2XbTs9GYZMJe4FA/1z+\n" + + "TOv0rN4fOK2yYCj2Dp9G5wePIJqk4Y+rVJl2gtiecMTamIVxrztU5AG0noPQe8aN\n" + + "H+0lCIkF6YeXdlqjhcP4Wde7O1rby+1d/6whuZriZQq83tHcU5SYRJeRsxtrgAub\n" + + "V7OuXHw1yjlx906PStfrCyXash4XSLjrCQ==\n" + "-----END CERTIFICATE-----"; static String clientCertStr = "-----BEGIN CERTIFICATE-----\n" + - "MIICpDCCAg2gAwIBAgIBCTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMjRaFw0yODA4MjUwMzQzMjRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" + - "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" + - "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" + - "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjczBxMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh\n" + - "bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAm25gJyqW1JznQ1EyOtTGswBVwfgBOf+F\n" + - "HJuBTcflYQLbTD/AETPQJGvZU9tdhuLtbG3OPhR7vSY8zeAbfM3dbH7QFr3r47Gj\n" + - "XEH7qM/MX+Z3ifVaC4MeJmrYQkYFSuKeyyKpdRVX4w4nnFHF6OsNASsYrMW6LpxN\n" + - "cl/epUcHL7E=\n" + + "MIIDpTCCAo2gAwIBAgIEWXLa2zANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV\n" + + "czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD\n" + + "VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTJaFw0zNDA3MDIwNDE2NTJaMGsx\n" + + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l\n" + + "LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMSAwHgYDVQQDExdsb2NhbGhvc3Qgb3U9\n" + + "U1NMLUNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMy/kjym\n" + + "V3QfWK3HaYhvWTJHUGAi5JhJDj4duLriO7ZxW/1kAm0NUHdybqg9XdS9H3ZR3JrQ\n" + + "1j7QMaUkWiy+d/qIofoGQcgPR3BHJJlQUkRbMGJbZTXEKLBc7tAb6zkrC6Gslkja\n" + + "Vmzg4+bj3UXLUTONQEPX8KQxqrXA30vfKwrtfhAMrh+WohAea9D5N4vfDQ4CNfhY\n" + + "vG61Vw4v6iDmc5rla4JwJbtRmnyd4lA9zx4kPpJVzyqtDYSPqEMkza1QZHTCc7bh\n" + + "khyyK4wte5amQWFcG494KFFA7UGQzh24JoFHa+NXQXROIPBaG5c3kYYZxfJtBMl4\n" + + "K1oWvPwrcVvQAE8CAwEAAaNzMHEwHQYDVR0OBBYEFM1F4gWSiKPHSSjn0ze3E5L7\n" + + "sTbEMAsGA1UdDwQEAwIF4DAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwCQYDVR0T\n" + + "BAIwADAfBgNVHSMEGDAWgBTgA5D2T7tX5n6vXJQls4XaFgpRQDANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEAI27pXYANs4bJzReBM71bqsBlTGuf+u4y6Ynh0McdXEN+lKyDr5GQ\n" + + "TCZhjf5rGqpuYTmzJErcksjK8oCwBUEMs93tt4FCmh5O8oBscmKLvdTNI3186G/j\n" + + "Z4lqeRnd9ldiEvrrzWbD0thAWhzdf5+yNOkq1hRSum6omw2poQO/xA2SPVnkqY4g\n" + + "QTmZgXCd0GiY/F9JSpLlosFRYfYeSVYLtoxX2wgq8KME3KEEolzQkE8TjRzmLnpj\n" + + "nDJAZVkEXXGQWqjbajBCV1sL386hH/ojcfNXEsQcZjs3dzIop/ut7oZRTIAv3chb\n" + + "n6cVB/orWu6TAF+mQyIbQFIVZgGEMp5xIQ==\n" + "-----END CERTIFICATE-----"; static byte serverPrivateExponent[] = { - (byte)0x6e, (byte)0xa7, (byte)0x1b, (byte)0x83, - (byte)0x51, (byte)0x35, (byte)0x9a, (byte)0x44, - (byte)0x7d, (byte)0xf6, (byte)0xe3, (byte)0x89, - (byte)0xa0, (byte)0xd7, (byte)0x90, (byte)0x60, - (byte)0xa1, (byte)0x4e, (byte)0x27, (byte)0x21, - (byte)0xa2, (byte)0x89, (byte)0x74, (byte)0xcc, - (byte)0x9d, (byte)0x75, (byte)0x75, (byte)0x4e, - (byte)0xc7, (byte)0x82, (byte)0xe3, (byte)0xe3, - (byte)0xc3, (byte)0x7d, (byte)0x00, (byte)0x54, - (byte)0xec, (byte)0x36, (byte)0xb1, (byte)0xdf, - (byte)0x91, (byte)0x9c, (byte)0x7a, (byte)0xc0, - (byte)0x62, (byte)0x0a, (byte)0xd6, (byte)0xa9, - (byte)0x22, (byte)0x91, (byte)0x4a, (byte)0x29, - (byte)0x2e, (byte)0x43, (byte)0xfa, (byte)0x8c, - (byte)0xd8, (byte)0xe9, (byte)0xbe, (byte)0xd9, - (byte)0x4f, (byte)0xca, (byte)0x23, (byte)0xc6, - (byte)0xe4, (byte)0x3f, (byte)0xb8, (byte)0x72, - (byte)0xcf, (byte)0x02, (byte)0xfc, (byte)0xf4, - (byte)0x58, (byte)0x34, (byte)0x77, (byte)0x76, - (byte)0xce, (byte)0x22, (byte)0x44, (byte)0x5f, - (byte)0x2d, (byte)0xca, (byte)0xee, (byte)0xf5, - (byte)0x43, (byte)0x56, (byte)0x47, (byte)0x71, - (byte)0x0b, (byte)0x09, (byte)0x6b, (byte)0x5e, - (byte)0xf2, (byte)0xc8, (byte)0xee, (byte)0xd4, - (byte)0x6e, (byte)0x44, (byte)0x92, (byte)0x2a, - (byte)0x7f, (byte)0xcc, (byte)0xa7, (byte)0xd4, - (byte)0x5b, (byte)0xfb, (byte)0xf7, (byte)0x4a, - (byte)0xa9, (byte)0xfb, (byte)0x54, (byte)0x18, - (byte)0xd5, (byte)0xd5, (byte)0x14, (byte)0xba, - (byte)0xa0, (byte)0x1c, (byte)0x13, (byte)0xb3, - (byte)0x37, (byte)0x6b, (byte)0x37, (byte)0x59, - (byte)0xed, (byte)0xdb, (byte)0x6d, (byte)0xb1 + (byte)0x68, (byte)0x87, (byte)0x36, (byte)0x54, + (byte)0xa3, (byte)0xc6, (byte)0xd5, (byte)0x5f, + (byte)0xf5, (byte)0x0f, (byte)0x4f, (byte)0x76, + (byte)0xc8, (byte)0x9c, (byte)0x2b, (byte)0x5b, + (byte)0xdc, (byte)0xe2, (byte)0xbe, (byte)0x14, + (byte)0x12, (byte)0x2f, (byte)0xc7, (byte)0x0a, + (byte)0xa9, (byte)0xcb, (byte)0x5e, (byte)0x04, + (byte)0x59, (byte)0xca, (byte)0x35, (byte)0x2f, + (byte)0x8d, (byte)0x2b, (byte)0xc4, (byte)0x40, + (byte)0xe6, (byte)0x7d, (byte)0x25, (byte)0x1b, + (byte)0x4d, (byte)0x07, (byte)0xc3, (byte)0x99, + (byte)0x9c, (byte)0x16, (byte)0x4f, (byte)0xa5, + (byte)0xdc, (byte)0xde, (byte)0xb0, (byte)0x90, + (byte)0xf0, (byte)0xde, (byte)0x22, (byte)0x70, + (byte)0x80, (byte)0xf4, (byte)0xa6, (byte)0x70, + (byte)0xe2, (byte)0x96, (byte)0x3d, (byte)0x18, + (byte)0x21, (byte)0xbf, (byte)0x2b, (byte)0x27, + (byte)0xa4, (byte)0x2d, (byte)0xd7, (byte)0xae, + (byte)0x2b, (byte)0x12, (byte)0x2f, (byte)0x08, + (byte)0x36, (byte)0xee, (byte)0x99, (byte)0x94, + (byte)0xed, (byte)0xf6, (byte)0xa7, (byte)0xd9, + (byte)0x1d, (byte)0xa2, (byte)0xf3, (byte)0x1f, + (byte)0x44, (byte)0xa4, (byte)0x28, (byte)0x4b, + (byte)0x67, (byte)0x35, (byte)0xd6, (byte)0xa8, + (byte)0x1b, (byte)0xf8, (byte)0x84, (byte)0x34, + (byte)0x34, (byte)0x84, (byte)0xbd, (byte)0xec, + (byte)0x9e, (byte)0x03, (byte)0x08, (byte)0x3c, + (byte)0x93, (byte)0x20, (byte)0x8e, (byte)0xaf, + (byte)0x15, (byte)0xcb, (byte)0x1f, (byte)0x20, + (byte)0x08, (byte)0x97, (byte)0xc4, (byte)0x19, + (byte)0x3e, (byte)0xfa, (byte)0x36, (byte)0xc6, + (byte)0xab, (byte)0x0e, (byte)0x2f, (byte)0xe7, + (byte)0xb3, (byte)0xc0, (byte)0xa7, (byte)0xbc, + (byte)0xe4, (byte)0xe0, (byte)0xa6, (byte)0x08, + (byte)0x1c, (byte)0x69, (byte)0x20, (byte)0x4d, + (byte)0x78, (byte)0xbd, (byte)0x7a, (byte)0xe5, + (byte)0x25, (byte)0x48, (byte)0x60, (byte)0x9e, + (byte)0x2e, (byte)0x50, (byte)0x8d, (byte)0x36, + (byte)0x1e, (byte)0x07, (byte)0xe9, (byte)0xd5, + (byte)0x0d, (byte)0x39, (byte)0x67, (byte)0x41, + (byte)0x42, (byte)0x24, (byte)0xdb, (byte)0x87, + (byte)0xe5, (byte)0x77, (byte)0x76, (byte)0xfd, + (byte)0x5e, (byte)0xd5, (byte)0xc6, (byte)0xe5, + (byte)0xd3, (byte)0xb0, (byte)0x98, (byte)0x71, + (byte)0x48, (byte)0x69, (byte)0x47, (byte)0x4f, + (byte)0x46, (byte)0x05, (byte)0x0c, (byte)0x9e, + (byte)0x58, (byte)0x45, (byte)0x2e, (byte)0xe2, + (byte)0x27, (byte)0xd0, (byte)0xf6, (byte)0x11, + (byte)0x05, (byte)0x78, (byte)0xad, (byte)0x83, + (byte)0x5a, (byte)0x5b, (byte)0xec, (byte)0xd7, + (byte)0x2e, (byte)0x26, (byte)0x5a, (byte)0xa5, + (byte)0x4f, (byte)0x9e, (byte)0x52, (byte)0x84, + (byte)0x2c, (byte)0x1f, (byte)0x59, (byte)0x1a, + (byte)0x78, (byte)0x56, (byte)0x0a, (byte)0x44, + (byte)0x54, (byte)0xc6, (byte)0x37, (byte)0x64, + (byte)0x01, (byte)0xca, (byte)0xe4, (byte)0xa8, + (byte)0x01, (byte)0xc7, (byte)0x86, (byte)0xc1, + (byte)0xb4, (byte)0xd6, (byte)0x6c, (byte)0x7a, + (byte)0x15, (byte)0x9a, (byte)0x65, (byte)0x69, + (byte)0x46, (byte)0x9e, (byte)0xfd, (byte)0xf6, + (byte)0x08, (byte)0x17, (byte)0x0c, (byte)0x6c, + (byte)0xac, (byte)0x38, (byte)0xbd, (byte)0xc2, + (byte)0xcd, (byte)0xda, (byte)0xef, (byte)0x54, + (byte)0x7a, (byte)0x48, (byte)0x92, (byte)0x4d }; static byte serverModulus[] = { - (byte)0x00, - (byte)0xa5, (byte)0xac, (byte)0x5b, (byte)0x1c, - (byte)0x37, (byte)0xa2, (byte)0xdd, (byte)0x99, - (byte)0x89, (byte)0x2d, (byte)0xb2, (byte)0x79, - (byte)0xb8, (byte)0x8f, (byte)0xd5, (byte)0x48, - (byte)0xa5, (byte)0xe7, (byte)0x1c, (byte)0x84, - (byte)0x17, (byte)0x8d, (byte)0x69, (byte)0x9c, - (byte)0xc6, (byte)0xac, (byte)0x6d, (byte)0xf9, - (byte)0xf2, (byte)0x1d, (byte)0x1f, (byte)0x39, - (byte)0x19, (byte)0xda, (byte)0xd3, (byte)0x72, - (byte)0x1e, (byte)0x6e, (byte)0xec, (byte)0x44, - (byte)0xcc, (byte)0x70, (byte)0xa4, (byte)0xdc, - (byte)0xba, (byte)0x00, (byte)0x30, (byte)0xf6, - (byte)0xa0, (byte)0x4f, (byte)0x3d, (byte)0x54, - (byte)0x7a, (byte)0x61, (byte)0x6a, (byte)0xcc, - (byte)0x57, (byte)0xd0, (byte)0x0a, (byte)0x7f, - (byte)0x95, (byte)0x28, (byte)0x18, (byte)0x3f, - (byte)0x9a, (byte)0xd9, (byte)0x94, (byte)0xf2, - (byte)0x1b, (byte)0xc8, (byte)0x24, (byte)0x88, - (byte)0x7e, (byte)0xfe, (byte)0x9d, (byte)0x0f, - (byte)0x3d, (byte)0xfb, (byte)0x57, (byte)0x53, - (byte)0x08, (byte)0xb3, (byte)0x20, (byte)0x33, - (byte)0xd4, (byte)0x3f, (byte)0x17, (byte)0x47, - (byte)0x14, (byte)0xd1, (byte)0xcd, (byte)0xea, - (byte)0x08, (byte)0xd8, (byte)0x0e, (byte)0x75, - (byte)0x4e, (byte)0xaf, (byte)0xbe, (byte)0xcc, - (byte)0xd2, (byte)0xec, (byte)0xaf, (byte)0xa9, - (byte)0x7a, (byte)0x49, (byte)0xdf, (byte)0xc2, - (byte)0xd9, (byte)0xac, (byte)0xb8, (byte)0x24, - (byte)0x40, (byte)0x90, (byte)0xa6, (byte)0x03, - (byte)0x56, (byte)0x2a, (byte)0xd0, (byte)0x30, - (byte)0x05, (byte)0x40, (byte)0x2c, (byte)0x4f, - (byte)0xab, (byte)0xd9, (byte)0x74, (byte)0x89 + (byte)0x00, (byte)0x9a, (byte)0x0c, (byte)0xe0, + (byte)0x8f, (byte)0xa8, (byte)0x02, (byte)0x7e, + (byte)0x5a, (byte)0xef, (byte)0xed, (byte)0xb2, + (byte)0x42, (byte)0xad, (byte)0x08, (byte)0x4e, + (byte)0x91, (byte)0xba, (byte)0xc2, (byte)0xad, + (byte)0x9b, (byte)0x79, (byte)0xd7, (byte)0x9b, + (byte)0x0f, (byte)0xfd, (byte)0xd2, (byte)0xf8, + (byte)0x15, (byte)0x2f, (byte)0x19, (byte)0x89, + (byte)0x80, (byte)0x10, (byte)0x00, (byte)0x02, + (byte)0x19, (byte)0x6d, (byte)0x27, (byte)0xc2, + (byte)0x90, (byte)0xd7, (byte)0xa5, (byte)0x23, + (byte)0x53, (byte)0x74, (byte)0x6e, (byte)0x64, + (byte)0x28, (byte)0x7c, (byte)0x24, (byte)0xaa, + (byte)0xed, (byte)0xea, (byte)0x21, (byte)0x59, + (byte)0xdc, (byte)0xa3, (byte)0x5c, (byte)0xb5, + (byte)0xc9, (byte)0x42, (byte)0x31, (byte)0x4f, + (byte)0xa2, (byte)0xde, (byte)0xfb, (byte)0x09, + (byte)0x7c, (byte)0x73, (byte)0xed, (byte)0x88, + (byte)0x04, (byte)0x34, (byte)0xf1, (byte)0x15, + (byte)0xad, (byte)0x3d, (byte)0x60, (byte)0xcd, + (byte)0xca, (byte)0xc5, (byte)0x13, (byte)0x99, + (byte)0xd3, (byte)0x9f, (byte)0x9b, (byte)0xb2, + (byte)0x92, (byte)0x70, (byte)0xcb, (byte)0xba, + (byte)0x4b, (byte)0x3d, (byte)0x20, (byte)0x96, + (byte)0xad, (byte)0xbe, (byte)0x92, (byte)0x53, + (byte)0xed, (byte)0x54, (byte)0x3b, (byte)0xc5, + (byte)0x14, (byte)0xbd, (byte)0xcf, (byte)0xd4, + (byte)0x0f, (byte)0xcb, (byte)0x05, (byte)0x4f, + (byte)0xfd, (byte)0x2b, (byte)0x9e, (byte)0xe0, + (byte)0x50, (byte)0xbb, (byte)0x65, (byte)0x13, + (byte)0x92, (byte)0xc0, (byte)0xd6, (byte)0xbd, + (byte)0x4d, (byte)0x02, (byte)0x0c, (byte)0x70, + (byte)0xb6, (byte)0x65, (byte)0xd4, (byte)0x7d, + (byte)0xb4, (byte)0x4d, (byte)0xc3, (byte)0xdf, + (byte)0x2c, (byte)0x08, (byte)0x9e, (byte)0xd2, + (byte)0x3e, (byte)0x69, (byte)0x32, (byte)0x46, + (byte)0x6f, (byte)0x6f, (byte)0xca, (byte)0xd1, + (byte)0x73, (byte)0xa4, (byte)0x94, (byte)0x07, + (byte)0xef, (byte)0x14, (byte)0xe3, (byte)0xda, + (byte)0x9e, (byte)0x2f, (byte)0xc0, (byte)0xac, + (byte)0x0e, (byte)0x10, (byte)0x33, (byte)0x4c, + (byte)0x68, (byte)0x79, (byte)0xf3, (byte)0x79, + (byte)0x40, (byte)0xd6, (byte)0xe9, (byte)0x3c, + (byte)0xc2, (byte)0xe6, (byte)0x70, (byte)0xe0, + (byte)0x89, (byte)0xce, (byte)0xa0, (byte)0x7a, + (byte)0xa8, (byte)0x84, (byte)0x28, (byte)0x85, + (byte)0x32, (byte)0x37, (byte)0x08, (byte)0xb0, + (byte)0xcf, (byte)0xb1, (byte)0x7f, (byte)0x5f, + (byte)0xbc, (byte)0x1f, (byte)0xa5, (byte)0x3d, + (byte)0xef, (byte)0xd6, (byte)0x68, (byte)0xa8, + (byte)0x17, (byte)0x21, (byte)0x5f, (byte)0x87, + (byte)0xd5, (byte)0x4b, (byte)0xb5, (byte)0xcc, + (byte)0xee, (byte)0x78, (byte)0x8d, (byte)0xdd, + (byte)0xb1, (byte)0x28, (byte)0x6a, (byte)0xc0, + (byte)0xfb, (byte)0x64, (byte)0xbd, (byte)0xb7, + (byte)0x70, (byte)0x02, (byte)0x33, (byte)0x03, + (byte)0x0b, (byte)0xb8, (byte)0xb8, (byte)0xbb, + (byte)0x08, (byte)0x82, (byte)0xf6, (byte)0x8e, + (byte)0x05, (byte)0x27, (byte)0xd1, (byte)0x3b, + (byte)0xe6, (byte)0xc5, (byte)0xac, (byte)0x4d, + (byte)0x85, (byte)0x5b, (byte)0xa1, (byte)0x1d, + (byte)0xa3, (byte)0x48, (byte)0x5d, (byte)0x03, + (byte)0x15, (byte)0x76, (byte)0x63, (byte)0x6c, + (byte)0x71, (byte)0x21, (byte)0x3e, (byte)0x98, + (byte)0xcd }; static byte clientPrivateExponent[] = { - (byte)0x11, (byte)0xb7, (byte)0x6a, (byte)0x36, - (byte)0x3d, (byte)0x30, (byte)0x37, (byte)0xce, - (byte)0x61, (byte)0x9d, (byte)0x6c, (byte)0x84, - (byte)0x8b, (byte)0xf3, (byte)0x9b, (byte)0x25, - (byte)0x4f, (byte)0x14, (byte)0xc8, (byte)0xa4, - (byte)0xdd, (byte)0x2f, (byte)0xd7, (byte)0x9a, - (byte)0x17, (byte)0xbd, (byte)0x90, (byte)0x19, - (byte)0xf7, (byte)0x05, (byte)0xfd, (byte)0xf2, - (byte)0xd2, (byte)0xc5, (byte)0xf7, (byte)0x77, - (byte)0xbe, (byte)0xea, (byte)0xe2, (byte)0x84, - (byte)0x87, (byte)0x97, (byte)0x3a, (byte)0x41, - (byte)0x96, (byte)0xb6, (byte)0x99, (byte)0xf8, - (byte)0x94, (byte)0x8c, (byte)0x58, (byte)0x71, - (byte)0x51, (byte)0x8c, (byte)0xf4, (byte)0x2a, - (byte)0x20, (byte)0x9e, (byte)0x1a, (byte)0xa0, - (byte)0x26, (byte)0x99, (byte)0x75, (byte)0xd6, - (byte)0x31, (byte)0x53, (byte)0x43, (byte)0x39, - (byte)0xf5, (byte)0x2a, (byte)0xa6, (byte)0x7e, - (byte)0x34, (byte)0x42, (byte)0x51, (byte)0x2a, - (byte)0x40, (byte)0x87, (byte)0x03, (byte)0x88, - (byte)0x43, (byte)0x69, (byte)0xb2, (byte)0x89, - (byte)0x6d, (byte)0x20, (byte)0xbd, (byte)0x7d, - (byte)0x71, (byte)0xef, (byte)0x47, (byte)0x0a, - (byte)0xdf, (byte)0x06, (byte)0xc1, (byte)0x69, - (byte)0x66, (byte)0xa8, (byte)0x22, (byte)0x37, - (byte)0x1a, (byte)0x77, (byte)0x1e, (byte)0xc7, - (byte)0x94, (byte)0x4e, (byte)0x2c, (byte)0x27, - (byte)0x69, (byte)0x45, (byte)0x5e, (byte)0xc8, - (byte)0xf8, (byte)0x0c, (byte)0xb7, (byte)0xf8, - (byte)0xc0, (byte)0x8f, (byte)0x99, (byte)0xc1, - (byte)0xe5, (byte)0x28, (byte)0x9b, (byte)0xf9, - (byte)0x4c, (byte)0x94, (byte)0xc6, (byte)0xb1 + (byte)0x62, (byte)0xb2, (byte)0xd6, (byte)0x63, + (byte)0xb6, (byte)0x2b, (byte)0xe2, (byte)0x26, + (byte)0x5a, (byte)0x31, (byte)0x2b, (byte)0x37, + (byte)0x8c, (byte)0x35, (byte)0x60, (byte)0xe2, + (byte)0x03, (byte)0xce, (byte)0x93, (byte)0x09, + (byte)0x3e, (byte)0xf8, (byte)0xc9, (byte)0xfe, + (byte)0xbb, (byte)0xa2, (byte)0xc8, (byte)0x32, + (byte)0x0e, (byte)0x6c, (byte)0x8a, (byte)0x7e, + (byte)0x0a, (byte)0xc2, (byte)0x13, (byte)0x3b, + (byte)0xb8, (byte)0x25, (byte)0xfa, (byte)0xec, + (byte)0x19, (byte)0x95, (byte)0x8e, (byte)0x34, + (byte)0x46, (byte)0xcf, (byte)0x0e, (byte)0x7b, + (byte)0xe4, (byte)0x25, (byte)0x82, (byte)0x1a, + (byte)0x7f, (byte)0x21, (byte)0x48, (byte)0x16, + (byte)0x44, (byte)0x58, (byte)0x3f, (byte)0x35, + (byte)0xd8, (byte)0xeb, (byte)0xd8, (byte)0x1a, + (byte)0x45, (byte)0x53, (byte)0x0f, (byte)0x9b, + (byte)0x84, (byte)0x8a, (byte)0x54, (byte)0x13, + (byte)0x33, (byte)0xe4, (byte)0x97, (byte)0x97, + (byte)0xf0, (byte)0x48, (byte)0x37, (byte)0xfb, + (byte)0x5d, (byte)0x4f, (byte)0x8c, (byte)0x8f, + (byte)0x35, (byte)0x63, (byte)0xe1, (byte)0xd9, + (byte)0x62, (byte)0x73, (byte)0x1c, (byte)0x8e, + (byte)0xd8, (byte)0xcd, (byte)0x2e, (byte)0x1a, + (byte)0xe5, (byte)0x4c, (byte)0xb5, (byte)0x05, + (byte)0x59, (byte)0x7a, (byte)0xdf, (byte)0xf1, + (byte)0x68, (byte)0xeb, (byte)0x1c, (byte)0x5c, + (byte)0xc6, (byte)0x10, (byte)0x44, (byte)0x8c, + (byte)0x7d, (byte)0x42, (byte)0xc5, (byte)0x71, + (byte)0x8a, (byte)0xe7, (byte)0x1b, (byte)0xaa, + (byte)0x17, (byte)0x03, (byte)0x6a, (byte)0xa0, + (byte)0xc0, (byte)0x6b, (byte)0x97, (byte)0x50, + (byte)0x17, (byte)0xad, (byte)0x6e, (byte)0x5e, + (byte)0xd9, (byte)0xdb, (byte)0x6f, (byte)0x3e, + (byte)0xe9, (byte)0x3f, (byte)0x35, (byte)0xc3, + (byte)0x45, (byte)0xbc, (byte)0xe8, (byte)0x3d, + (byte)0x5a, (byte)0xb4, (byte)0xb9, (byte)0x3f, + (byte)0x53, (byte)0x80, (byte)0x64, (byte)0xdc, + (byte)0x12, (byte)0x24, (byte)0x35, (byte)0x35, + (byte)0xbd, (byte)0x98, (byte)0xbb, (byte)0x8d, + (byte)0xfa, (byte)0x19, (byte)0xa3, (byte)0x5e, + (byte)0x9e, (byte)0xac, (byte)0x70, (byte)0x4a, + (byte)0xfc, (byte)0x8d, (byte)0xae, (byte)0x55, + (byte)0x8b, (byte)0x71, (byte)0x81, (byte)0x0e, + (byte)0x4d, (byte)0xc8, (byte)0x2f, (byte)0x87, + (byte)0xb0, (byte)0x44, (byte)0xf7, (byte)0x4f, + (byte)0xdc, (byte)0xa8, (byte)0xc8, (byte)0x50, + (byte)0xb5, (byte)0x95, (byte)0x24, (byte)0x63, + (byte)0x74, (byte)0x13, (byte)0x54, (byte)0x58, + (byte)0xde, (byte)0xfc, (byte)0xe0, (byte)0x75, + (byte)0xeb, (byte)0xf4, (byte)0x06, (byte)0x58, + (byte)0x83, (byte)0x12, (byte)0x4c, (byte)0x56, + (byte)0xc4, (byte)0xc4, (byte)0x18, (byte)0x0c, + (byte)0xea, (byte)0xa3, (byte)0xe7, (byte)0x25, + (byte)0xa3, (byte)0xde, (byte)0x19, (byte)0x23, + (byte)0xa2, (byte)0x5a, (byte)0x2a, (byte)0xb6, + (byte)0x56, (byte)0x04, (byte)0xbc, (byte)0x65, + (byte)0xba, (byte)0x7c, (byte)0x0a, (byte)0xf4, + (byte)0x91, (byte)0x10, (byte)0x22, (byte)0x88, + (byte)0x3f, (byte)0x9d, (byte)0xbe, (byte)0x58, + (byte)0x43, (byte)0x4c, (byte)0x2e, (byte)0xad, + (byte)0xdb, (byte)0xd6, (byte)0x32, (byte)0xcf, + (byte)0x8e, (byte)0xb5, (byte)0x05, (byte)0x55, + (byte)0x39, (byte)0x8b, (byte)0xe1, (byte)0x01 }; static byte clientModulus[] = { - (byte)0x00, - (byte)0xbb, (byte)0xf0, (byte)0x40, (byte)0x36, - (byte)0xac, (byte)0x26, (byte)0x54, (byte)0x4e, - (byte)0xf4, (byte)0xa3, (byte)0x5a, (byte)0x00, - (byte)0x2f, (byte)0x69, (byte)0x21, (byte)0x6f, - (byte)0xb9, (byte)0x7a, (byte)0x3a, (byte)0x93, - (byte)0xec, (byte)0xa2, (byte)0xf6, (byte)0xe1, - (byte)0x8e, (byte)0xc7, (byte)0x63, (byte)0xd8, - (byte)0x2f, (byte)0x12, (byte)0x30, (byte)0x99, - (byte)0x2e, (byte)0xb0, (byte)0xf2, (byte)0x8f, - (byte)0xf8, (byte)0x27, (byte)0x2d, (byte)0x24, - (byte)0x78, (byte)0x28, (byte)0x84, (byte)0xf7, - (byte)0x01, (byte)0xbf, (byte)0x8d, (byte)0x44, - (byte)0x79, (byte)0xdd, (byte)0x3b, (byte)0xd2, - (byte)0x55, (byte)0xf3, (byte)0xce, (byte)0x3c, - (byte)0xb2, (byte)0x5b, (byte)0x21, (byte)0x7d, - (byte)0xef, (byte)0xfd, (byte)0x33, (byte)0x4a, - (byte)0xb1, (byte)0xa3, (byte)0xff, (byte)0xc6, - (byte)0xc8, (byte)0x9b, (byte)0xb9, (byte)0x0f, - (byte)0x7c, (byte)0x41, (byte)0x35, (byte)0x97, - (byte)0xf9, (byte)0xdb, (byte)0x3a, (byte)0x05, - (byte)0x60, (byte)0x05, (byte)0x15, (byte)0xaf, - (byte)0x59, (byte)0x17, (byte)0x92, (byte)0xa3, - (byte)0x10, (byte)0xad, (byte)0x16, (byte)0x1c, - (byte)0xe4, (byte)0x07, (byte)0x53, (byte)0xaf, - (byte)0xa8, (byte)0x76, (byte)0xa2, (byte)0x56, - (byte)0x2a, (byte)0x92, (byte)0xd3, (byte)0xf9, - (byte)0x28, (byte)0xe0, (byte)0x78, (byte)0xcf, - (byte)0x5e, (byte)0x1f, (byte)0x48, (byte)0xab, - (byte)0x5c, (byte)0x19, (byte)0xdd, (byte)0xe1, - (byte)0x67, (byte)0x43, (byte)0xba, (byte)0x75, - (byte)0x8d, (byte)0xf5, (byte)0x82, (byte)0xac, - (byte)0x43, (byte)0x92, (byte)0x44, (byte)0x1b + (byte)0x00, (byte)0xcc, (byte)0xbf, (byte)0x92, + (byte)0x3c, (byte)0xa6, (byte)0x57, (byte)0x74, + (byte)0x1f, (byte)0x58, (byte)0xad, (byte)0xc7, + (byte)0x69, (byte)0x88, (byte)0x6f, (byte)0x59, + (byte)0x32, (byte)0x47, (byte)0x50, (byte)0x60, + (byte)0x22, (byte)0xe4, (byte)0x98, (byte)0x49, + (byte)0x0e, (byte)0x3e, (byte)0x1d, (byte)0xb8, + (byte)0xba, (byte)0xe2, (byte)0x3b, (byte)0xb6, + (byte)0x71, (byte)0x5b, (byte)0xfd, (byte)0x64, + (byte)0x02, (byte)0x6d, (byte)0x0d, (byte)0x50, + (byte)0x77, (byte)0x72, (byte)0x6e, (byte)0xa8, + (byte)0x3d, (byte)0x5d, (byte)0xd4, (byte)0xbd, + (byte)0x1f, (byte)0x76, (byte)0x51, (byte)0xdc, + (byte)0x9a, (byte)0xd0, (byte)0xd6, (byte)0x3e, + (byte)0xd0, (byte)0x31, (byte)0xa5, (byte)0x24, + (byte)0x5a, (byte)0x2c, (byte)0xbe, (byte)0x77, + (byte)0xfa, (byte)0x88, (byte)0xa1, (byte)0xfa, + (byte)0x06, (byte)0x41, (byte)0xc8, (byte)0x0f, + (byte)0x47, (byte)0x70, (byte)0x47, (byte)0x24, + (byte)0x99, (byte)0x50, (byte)0x52, (byte)0x44, + (byte)0x5b, (byte)0x30, (byte)0x62, (byte)0x5b, + (byte)0x65, (byte)0x35, (byte)0xc4, (byte)0x28, + (byte)0xb0, (byte)0x5c, (byte)0xee, (byte)0xd0, + (byte)0x1b, (byte)0xeb, (byte)0x39, (byte)0x2b, + (byte)0x0b, (byte)0xa1, (byte)0xac, (byte)0x96, + (byte)0x48, (byte)0xda, (byte)0x56, (byte)0x6c, + (byte)0xe0, (byte)0xe3, (byte)0xe6, (byte)0xe3, + (byte)0xdd, (byte)0x45, (byte)0xcb, (byte)0x51, + (byte)0x33, (byte)0x8d, (byte)0x40, (byte)0x43, + (byte)0xd7, (byte)0xf0, (byte)0xa4, (byte)0x31, + (byte)0xaa, (byte)0xb5, (byte)0xc0, (byte)0xdf, + (byte)0x4b, (byte)0xdf, (byte)0x2b, (byte)0x0a, + (byte)0xed, (byte)0x7e, (byte)0x10, (byte)0x0c, + (byte)0xae, (byte)0x1f, (byte)0x96, (byte)0xa2, + (byte)0x10, (byte)0x1e, (byte)0x6b, (byte)0xd0, + (byte)0xf9, (byte)0x37, (byte)0x8b, (byte)0xdf, + (byte)0x0d, (byte)0x0e, (byte)0x02, (byte)0x35, + (byte)0xf8, (byte)0x58, (byte)0xbc, (byte)0x6e, + (byte)0xb5, (byte)0x57, (byte)0x0e, (byte)0x2f, + (byte)0xea, (byte)0x20, (byte)0xe6, (byte)0x73, + (byte)0x9a, (byte)0xe5, (byte)0x6b, (byte)0x82, + (byte)0x70, (byte)0x25, (byte)0xbb, (byte)0x51, + (byte)0x9a, (byte)0x7c, (byte)0x9d, (byte)0xe2, + (byte)0x50, (byte)0x3d, (byte)0xcf, (byte)0x1e, + (byte)0x24, (byte)0x3e, (byte)0x92, (byte)0x55, + (byte)0xcf, (byte)0x2a, (byte)0xad, (byte)0x0d, + (byte)0x84, (byte)0x8f, (byte)0xa8, (byte)0x43, + (byte)0x24, (byte)0xcd, (byte)0xad, (byte)0x50, + (byte)0x64, (byte)0x74, (byte)0xc2, (byte)0x73, + (byte)0xb6, (byte)0xe1, (byte)0x92, (byte)0x1c, + (byte)0xb2, (byte)0x2b, (byte)0x8c, (byte)0x2d, + (byte)0x7b, (byte)0x96, (byte)0xa6, (byte)0x41, + (byte)0x61, (byte)0x5c, (byte)0x1b, (byte)0x8f, + (byte)0x78, (byte)0x28, (byte)0x51, (byte)0x40, + (byte)0xed, (byte)0x41, (byte)0x90, (byte)0xce, + (byte)0x1d, (byte)0xb8, (byte)0x26, (byte)0x81, + (byte)0x47, (byte)0x6b, (byte)0xe3, (byte)0x57, + (byte)0x41, (byte)0x74, (byte)0x4e, (byte)0x20, + (byte)0xf0, (byte)0x5a, (byte)0x1b, (byte)0x97, + (byte)0x37, (byte)0x91, (byte)0x86, (byte)0x19, + (byte)0xc5, (byte)0xf2, (byte)0x6d, (byte)0x04, + (byte)0xc9, (byte)0x78, (byte)0x2b, (byte)0x5a, + (byte)0x16, (byte)0xbc, (byte)0xfc, (byte)0x2b, + (byte)0x71, (byte)0x5b, (byte)0xd0, (byte)0x00, + (byte)0x4f }; static char passphrase[] = "passphrase".toCharArray(); @@ -808,26 +1090,26 @@ static class Test { } static Test[] tests = { - // MD5 is used in this test case, don't disable MD5 algorithm. + // SHA1 is used in this test case, don't disable SHA1 algorithm. new Test( "SSLv3, RC4, DH keySize < 768", "MD2, RSA keySize < 1024", false), - // Disable MD5 but only if cert chains back to public root CA, should - // pass because the MD5 cert in this test case is issued by test CA + // Disable SHA1 but only if cert chains back to public root CA, should + // pass because the SHA1 cert in this test case is issued by test CA new Test( "SSLv3, RC4, DH keySize < 768", - "MD2, MD5 jdkCA, RSA keySize < 1024", + "MD2, SHA1 jdkCA, RSA keySize < 1024", false), - // Disable MD5 alg via TLS property and expect failure + // Disable SHA1 alg via TLS property and expect failure new Test( - "SSLv3, MD5, RC4, DH keySize < 768", + "SSLv3, SHA1, RC4, DH keySize < 768", "MD2, RSA keySize < 1024", true), - // Disable MD5 alg via certpath property and expect failure + // Disable SHA1 alg via certpath property and expect failure new Test( "SSLv3, RC4, DH keySize < 768", - "MD2, MD5, RSA keySize < 1024", + "MD2, SHA1, RSA keySize < 1024", true), }; @@ -850,7 +1132,7 @@ public static void main(String args[]) throws Exception { try { new PKIXExtendedTM(); if (test.fail) { - throw new Exception("Expected MD5 certificate to be blocked"); + throw new Exception("Expected SHA1 certificate to be blocked"); } } catch (Exception e) { if (test.fail) { diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/SunX509ExtendedTM.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/SunX509ExtendedTM.java index ec893f90703cc..f95aee76dab49 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/SunX509ExtendedTM.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/SunX509ExtendedTM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, 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 @@ -52,357 +52,497 @@ * * TLS server certificate: * server private key: - * -----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,D9AE407F6D0E389A * - * WPrA7TFol/cQCcp9oHnXWNpYlvRbbIcQj0m+RKT2Iuzfus+DHt3Zadf8nJpKfX2e - * h2rnhlzCN9M7djRDooZKDOPCsdBn51Au7HlZF3S3Opgo7D8XFM1a8t1Je4ke14oI - * nw6QKYsBblRziPnP2PZ0zvX24nOv7bbY8beynlJHGs00VWSFdoH2DS0aE1p6D+3n - * ptJuJ75dVfZFK4X7162APlNXevX8D6PEQpSiRw1rjjGGcnvQ4HdWk3BxDVDcCNJb - * Y1aGNRxsjTDvPi3R9Qx2M+W03QzEPx4SR3ZHVskeSJHaetM0TM/w/45Paq4GokXP - * ZeTnbEx1xmjkA7h+t4doLL4watx5F6yLsJzu8xB3lt/1EtmkYtLz1t7X4BetPAXz - * zS69X/VwhKfsOI3qXBWuL2oHPyhDmT1gcaUQwEPSV6ogHEEQEDXdiUS8heNK13KF - * TCQYFkETvV2BLxUhV1hypPzRQ6tUpJiAbD5KmoK2lD9slshG2QtvKQq0/bgkDY5J - * LhDHV2dtcZ3kDPkkZXpbcJQvoeH3d09C5sIsuTFo2zgNR6oETHUc5TzP6FY2YYRa - * QcK5HcmtsRRiXFm01ac+aMejJUIujjFt84SiKWT/73vC8AmY4tYcJBLjCg4XIxSH - * fdDFLL1YZENNO5ivlp8mdiHqcawx+36L7DrEZQ8RZt6cqST5t/+XTdM74s6k81GT - * pNsa82P2K2zmIUZ/DL2mKjW1vfRByw1NQFEBkN3vdyZxYfM/JyUzX4hbjXBEkh9Q - * QYrcwLKLjis2QzSvK04B3bvRzRb+4ocWiso8ZPAXAIxZFBWDpTMM2A== - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICXAIBAAKBgQClrFscN6LdmYktsnm4j9VIpecchBeNaZzGrG358h0fORna03Ie - * buxEzHCk3LoAMPagTz1UemFqzFfQCn+VKBg/mtmU8hvIJIh+/p0PPftXUwizIDPU - * PxdHFNHN6gjYDnVOr77M0uyvqXpJ38LZrLgkQJCmA1Yq0DAFQCxPq9l0iQIDAQAB - * AoGAbqcbg1E1mkR99uOJoNeQYKFOJyGiiXTMnXV1TseC4+PDfQBU7Dax35GcesBi - * CtapIpFKKS5D+ozY6b7ZT8ojxuQ/uHLPAvz0WDR3ds4iRF8tyu71Q1ZHcQsJa17y - * yO7UbkSSKn/Mp9Rb+/dKqftUGNXVFLqgHBOzN2s3We3bbbECQQDYBPKOg3hkaGHo - * OhpHKqtQ6EVkldihG/3i4WejRonelXN+HRh1KrB2HBx0M8D/qAzP1i3rNSlSHer4 - * 59YRTJnHAkEAxFX/sVYSn07BHv9Zhn6XXct/Cj43z/tKNbzlNbcxqQwQerw3IH51 - * 8UH2YOA+GD3lXbKp+MytoFLWv8zg4YT/LwJAfqan75Z1R6lLffRS49bIiq8jwE16 - * rTrUJ+kv8jKxMqc9B3vXkxpsS1M/+4E8bqgAmvpgAb8xcsvHsBd9ErdukQJBAKs2 - * j67W75BrPjBI34pQ1LEfp56IGWXOrq1kF8IbCjxv3+MYRT6Z6UJFkpRymNPNDjsC - * dgUYgITiGJHUGXuw3lMCQHEHqo9ZtXz92yFT+VhsNc29B8m/sqUJdtCcMd/jGpAF - * u6GHufjqIZBpQsk63wbwESAPZZ+kk1O1kS5GIRLX608= - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) + * Private-Key: (2048 bit, 2 primes) * modulus: - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 + * 00:9a:0c:e0:8f:a8:02:7e:5a:ef:ed:b2:42:ad:08: + * 4e:91:ba:c2:ad:9b:79:d7:9b:0f:fd:d2:f8:15:2f: + * 19:89:80:10:00:02:19:6d:27:c2:90:d7:a5:23:53: + * 74:6e:64:28:7c:24:aa:ed:ea:21:59:dc:a3:5c:b5: + * c9:42:31:4f:a2:de:fb:09:7c:73:ed:88:04:34:f1: + * 15:ad:3d:60:cd:ca:c5:13:99:d3:9f:9b:b2:92:70: + * cb:ba:4b:3d:20:96:ad:be:92:53:ed:54:3b:c5:14: + * bd:cf:d4:0f:cb:05:4f:fd:2b:9e:e0:50:bb:65:13: + * 92:c0:d6:bd:4d:02:0c:70:b6:65:d4:7d:b4:4d:c3: + * df:2c:08:9e:d2:3e:69:32:46:6f:6f:ca:d1:73:a4: + * 94:07:ef:14:e3:da:9e:2f:c0:ac:0e:10:33:4c:68: + * 79:f3:79:40:d6:e9:3c:c2:e6:70:e0:89:ce:a0:7a: + * a8:84:28:85:32:37:08:b0:cf:b1:7f:5f:bc:1f:a5: + * 3d:ef:d6:68:a8:17:21:5f:87:d5:4b:b5:cc:ee:78: + * 8d:dd:b1:28:6a:c0:fb:64:bd:b7:70:02:33:03:0b: + * b8:b8:bb:08:82:f6:8e:05:27:d1:3b:e6:c5:ac:4d: + * 85:5b:a1:1d:a3:48:5d:03:15:76:63:6c:71:21:3e: + * 98:cd * publicExponent: 65537 (0x10001) * privateExponent: - * 6e:a7:1b:83:51:35:9a:44:7d:f6:e3:89:a0:d7:90: - * 60:a1:4e:27:21:a2:89:74:cc:9d:75:75:4e:c7:82: - * e3:e3:c3:7d:00:54:ec:36:b1:df:91:9c:7a:c0:62: - * 0a:d6:a9:22:91:4a:29:2e:43:fa:8c:d8:e9:be:d9: - * 4f:ca:23:c6:e4:3f:b8:72:cf:02:fc:f4:58:34:77: - * 76:ce:22:44:5f:2d:ca:ee:f5:43:56:47:71:0b:09: - * 6b:5e:f2:c8:ee:d4:6e:44:92:2a:7f:cc:a7:d4:5b: - * fb:f7:4a:a9:fb:54:18:d5:d5:14:ba:a0:1c:13:b3: - * 37:6b:37:59:ed:db:6d:b1 + * 68:87:36:54:a3:c6:d5:5f:f5:0f:4f:76:c8:9c:2b: + * 5b:dc:e2:be:14:12:2f:c7:0a:a9:cb:5e:04:59:ca: + * 35:2f:8d:2b:c4:40:e6:7d:25:1b:4d:07:c3:99:9c: + * 16:4f:a5:dc:de:b0:90:f0:de:22:70:80:f4:a6:70: + * e2:96:3d:18:21:bf:2b:27:a4:2d:d7:ae:2b:12:2f: + * 08:36:ee:99:94:ed:f6:a7:d9:1d:a2:f3:1f:44:a4: + * 28:4b:67:35:d6:a8:1b:f8:84:34:34:84:bd:ec:9e: + * 03:08:3c:93:20:8e:af:15:cb:1f:20:08:97:c4:19: + * 3e:fa:36:c6:ab:0e:2f:e7:b3:c0:a7:bc:e4:e0:a6: + * 08:1c:69:20:4d:78:bd:7a:e5:25:48:60:9e:2e:50: + * 8d:36:1e:07:e9:d5:0d:39:67:41:42:24:db:87:e5: + * 77:76:fd:5e:d5:c6:e5:d3:b0:98:71:48:69:47:4f: + * 46:05:0c:9e:58:45:2e:e2:27:d0:f6:11:05:78:ad: + * 83:5a:5b:ec:d7:2e:26:5a:a5:4f:9e:52:84:2c:1f: + * 59:1a:78:56:0a:44:54:c6:37:64:01:ca:e4:a8:01: + * c7:86:c1:b4:d6:6c:7a:15:9a:65:69:46:9e:fd:f6: + * 08:17:0c:6c:ac:38:bd:c2:cd:da:ef:54:7a:48:92: + * 4d * prime1: - * 00:d8:04:f2:8e:83:78:64:68:61:e8:3a:1a:47:2a: - * ab:50:e8:45:64:95:d8:a1:1b:fd:e2:e1:67:a3:46: - * 89:de:95:73:7e:1d:18:75:2a:b0:76:1c:1c:74:33: - * c0:ff:a8:0c:cf:d6:2d:eb:35:29:52:1d:ea:f8:e7: - * d6:11:4c:99:c7 + * 00:e4:43:cc:51:25:aa:1d:90:41:95:2c:e8:9f:aa: + * 1c:9b:ea:bd:fd:29:e5:68:6b:28:00:ec:31:31:36: + * d0:3d:84:db:c5:5d:32:f6:38:b9:04:4f:45:cb:19: + * f5:88:cd:a8:fc:70:b8:6d:98:68:a6:b4:9e:c1:da: + * fd:db:eb:1a:53:3c:3b:e6:85:d2:6f:03:45:7a:ad: + * 49:8c:c3:96:a7:46:a4:bb:3b:48:d3:d7:1c:b4:3c: + * f7:04:0a:a3:85:9d:94:3e:bd:35:f5:34:21:3d:08: + * 89:df:c5:54:af:cf:90:f7:d8:5c:57:c5:77:5a:c8: + * d1:b3:8f:ee:01:5c:07:13:3f * prime2: - * 00:c4:55:ff:b1:56:12:9f:4e:c1:1e:ff:59:86:7e: - * 97:5d:cb:7f:0a:3e:37:cf:fb:4a:35:bc:e5:35:b7: - * 31:a9:0c:10:7a:bc:37:20:7e:75:f1:41:f6:60:e0: - * 3e:18:3d:e5:5d:b2:a9:f8:cc:ad:a0:52:d6:bf:cc: - * e0:e1:84:ff:2f + * 00:ac:c4:a0:cc:7c:51:db:65:0a:02:da:bc:d8:77: + * 21:8c:d3:30:ae:ec:50:60:4b:b9:39:c7:2d:bd:98: + * aa:4f:9b:44:74:ab:f8:86:de:e2:44:15:73:7a:cd: + * d5:46:f2:03:62:c5:87:9c:6d:91:d5:7a:9a:17:c2: + * c6:2f:29:0e:8a:a4:a9:f4:c2:63:a2:77:97:bf:c6: + * 90:e8:39:70:87:cc:fd:62:4f:d2:3d:e7:47:70:fb: + * f3:bd:bd:5c:9c:77:fe:23:33:7d:83:ef:cb:0e:4e: + * f1:dd:05:47:40:97:f4:da:b6:1f:b9:8d:e2:92:04: + * 09:be:fb:6a:97:29:27:ac:f3 * exponent1: - * 7e:a6:a7:ef:96:75:47:a9:4b:7d:f4:52:e3:d6:c8: - * 8a:af:23:c0:4d:7a:ad:3a:d4:27:e9:2f:f2:32:b1: - * 32:a7:3d:07:7b:d7:93:1a:6c:4b:53:3f:fb:81:3c: - * 6e:a8:00:9a:fa:60:01:bf:31:72:cb:c7:b0:17:7d: - * 12:b7:6e:91 + * 3f:08:1d:b6:56:b1:38:02:aa:a9:77:c2:30:bc:b7: + * b3:b2:49:8e:4b:f0:66:3a:18:cc:d0:6b:f1:0c:12: + * ca:ba:12:39:d8:b7:86:d8:38:f6:e0:b1:04:19:81: + * fc:a9:d5:bd:07:9f:55:dc:1d:21:d3:84:77:41:72: + * 92:34:c4:8b:31:79:d4:f9:25:17:b4:8e:8e:06:a5: + * e5:b1:e8:ba:fe:3d:e4:d9:c5:0d:82:3c:11:e5:37: + * cc:ac:e7:64:b1:13:cb:93:52:00:08:ca:18:e1:6f: + * b9:13:f3:83:ac:cc:7a:34:0b:a3:cd:0a:5d:4e:50: + * e1:c5:9f:d2:4e:48:41:df * exponent2: - * 00:ab:36:8f:ae:d6:ef:90:6b:3e:30:48:df:8a:50: - * d4:b1:1f:a7:9e:88:19:65:ce:ae:ad:64:17:c2:1b: - * 0a:3c:6f:df:e3:18:45:3e:99:e9:42:45:92:94:72: - * 98:d3:cd:0e:3b:02:76:05:18:80:84:e2:18:91:d4: - * 19:7b:b0:de:53 + * 02:c7:fb:8a:af:29:a6:2d:7f:36:c2:8c:ad:b3:65: + * 3f:de:1a:77:86:68:58:d4:7f:3b:d5:df:ff:a0:58: + * 85:85:8b:59:91:77:23:bc:ac:c9:c9:ca:9d:1c:79: + * 25:76:39:e5:ba:26:4f:b7:57:d4:a6:ef:9a:18:51: + * 96:6a:c3:c8:29:94:6e:d3:3e:45:5c:45:7e:19:d5: + * 35:57:cf:5e:f0:46:d7:f1:4f:02:1e:1a:01:50:9d: + * 00:dd:ee:82:ba:4f:c6:03:4b:2e:f7:8a:3e:45:b9: + * 11:04:c7:bb:db:76:5e:9a:f5:f1:c7:bd:f0:f9:cd: + * aa:5c:63:bf:e1:32:b9:4f * coefficient: - * 71:07:aa:8f:59:b5:7c:fd:db:21:53:f9:58:6c:35: - * cd:bd:07:c9:bf:b2:a5:09:76:d0:9c:31:df:e3:1a: - * 90:05:bb:a1:87:b9:f8:ea:21:90:69:42:c9:3a:df: - * 06:f0:11:20:0f:65:9f:a4:93:53:b5:91:2e:46:21: - * 12:d7:eb:4f - * + * 50:4c:e6:1e:23:f3:e2:2b:d6:3f:87:53:fb:19:53: + * 4b:84:21:0b:77:31:ed:8d:c3:0c:ea:31:b0:a6:38: + * a9:e6:44:6e:18:05:53:8f:4a:5f:75:e5:3e:b5:26: + * 9b:46:3d:73:e7:c1:2a:a6:3e:c3:cd:41:b1:a6:55: + * 57:84:11:13:ec:44:92:59:7f:dd:0d:67:30:d3:b7: + * 13:ee:9e:2d:ea:be:b3:ca:4a:f0:6e:4f:22:e8:be: + * 8b:8d:9b:2c:30:a5:ed:2c:2b:13:4c:f7:61:19:64: + * 35:9d:b0:c8:10:85:01:e7:2a:70:13:00:39:c5:73: + * 63:34:fd:28:2d:7f:8d:20 + * -----BEGIN PRIVATE KEY----- + * MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCaDOCPqAJ+Wu/t + * skKtCE6RusKtm3nXmw/90vgVLxmJgBAAAhltJ8KQ16UjU3RuZCh8JKrt6iFZ3KNc + * tclCMU+i3vsJfHPtiAQ08RWtPWDNysUTmdOfm7KScMu6Sz0glq2+klPtVDvFFL3P + * 1A/LBU/9K57gULtlE5LA1r1NAgxwtmXUfbRNw98sCJ7SPmkyRm9vytFzpJQH7xTj + * 2p4vwKwOEDNMaHnzeUDW6TzC5nDgic6geqiEKIUyNwiwz7F/X7wfpT3v1mioFyFf + * h9VLtczueI3dsShqwPtkvbdwAjMDC7i4uwiC9o4FJ9E75sWsTYVboR2jSF0DFXZj + * bHEhPpjNAgMBAAECggEAaIc2VKPG1V/1D092yJwrW9zivhQSL8cKqcteBFnKNS+N + * K8RA5n0lG00Hw5mcFk+l3N6wkPDeInCA9KZw4pY9GCG/KyekLdeuKxIvCDbumZTt + * 9qfZHaLzH0SkKEtnNdaoG/iENDSEveyeAwg8kyCOrxXLHyAIl8QZPvo2xqsOL+ez + * wKe85OCmCBxpIE14vXrlJUhgni5QjTYeB+nVDTlnQUIk24fld3b9XtXG5dOwmHFI + * aUdPRgUMnlhFLuIn0PYRBXitg1pb7NcuJlqlT55ShCwfWRp4VgpEVMY3ZAHK5KgB + * x4bBtNZsehWaZWlGnv32CBcMbKw4vcLN2u9UekiSTQKBgQDkQ8xRJaodkEGVLOif + * qhyb6r39KeVoaygA7DExNtA9hNvFXTL2OLkET0XLGfWIzaj8cLhtmGimtJ7B2v3b + * 6xpTPDvmhdJvA0V6rUmMw5anRqS7O0jT1xy0PPcECqOFnZQ+vTX1NCE9CInfxVSv + * z5D32FxXxXdayNGzj+4BXAcTPwKBgQCsxKDMfFHbZQoC2rzYdyGM0zCu7FBgS7k5 + * xy29mKpPm0R0q/iG3uJEFXN6zdVG8gNixYecbZHVepoXwsYvKQ6KpKn0wmOid5e/ + * xpDoOXCHzP1iT9I950dw+/O9vVycd/4jM32D78sOTvHdBUdAl/Tath+5jeKSBAm+ + * +2qXKSes8wKBgD8IHbZWsTgCqql3wjC8t7OySY5L8GY6GMzQa/EMEsq6EjnYt4bY + * OPbgsQQZgfyp1b0Hn1XcHSHThHdBcpI0xIsxedT5JRe0jo4GpeWx6Lr+PeTZxQ2C + * PBHlN8ys52SxE8uTUgAIyhjhb7kT84OszHo0C6PNCl1OUOHFn9JOSEHfAoGAAsf7 + * iq8ppi1/NsKMrbNlP94ad4ZoWNR/O9Xf/6BYhYWLWZF3I7ysycnKnRx5JXY55bom + * T7dX1KbvmhhRlmrDyCmUbtM+RVxFfhnVNVfPXvBG1/FPAh4aAVCdAN3ugrpPxgNL + * LveKPkW5EQTHu9t2Xpr18ce98PnNqlxjv+EyuU8CgYBQTOYeI/PiK9Y/h1P7GVNL + * hCELdzHtjcMM6jGwpjip5kRuGAVTj0pfdeU+tSabRj1z58Eqpj7DzUGxplVXhBET + * 7ESSWX/dDWcw07cT7p4t6r6zykrwbk8i6L6LjZssMKXtLCsTTPdhGWQ1nbDIEIUB + * 5ypwEwA5xXNjNP0oLX+NIA== + * -----END PRIVATE KEY----- * * server certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 8 (0x8) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:43:04 2008 GMT - * Not After : Aug 25 03:43:04 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Server, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * ED:6E:DB:F4:B5:56:C8:FB:1A:06:61:3F:0F:08:BB:A6:04:D8:16:54 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * DNS:localhost - * Signature Algorithm: md5WithRSAEncryption0 - * + * Data: + * Version: 3 (0x2) + * Serial Number: 106315679 (0x6563f9f) + * Signature Algorithm: sha1WithRSAEncryption + * Issuer: C=Us, ST=Some-State, L=Some-City, O=Some-Org + * Validity + * Not Before: Jul 1 04:16:55 2024 GMT + * Not After : Jul 2 04:16:55 2034 GMT + * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, CN=localhost ou=SSL-Server + * Subject Public Key Info: + * Public Key Algorithm: rsaEncryption + * Public-Key: (2048 bit) + * Modulus: + * 00:9a:0c:e0:8f:a8:02:7e:5a:ef:ed:b2:42:ad:08: + * 4e:91:ba:c2:ad:9b:79:d7:9b:0f:fd:d2:f8:15:2f: + * 19:89:80:10:00:02:19:6d:27:c2:90:d7:a5:23:53: + * 74:6e:64:28:7c:24:aa:ed:ea:21:59:dc:a3:5c:b5: + * c9:42:31:4f:a2:de:fb:09:7c:73:ed:88:04:34:f1: + * 15:ad:3d:60:cd:ca:c5:13:99:d3:9f:9b:b2:92:70: + * cb:ba:4b:3d:20:96:ad:be:92:53:ed:54:3b:c5:14: + * bd:cf:d4:0f:cb:05:4f:fd:2b:9e:e0:50:bb:65:13: + * 92:c0:d6:bd:4d:02:0c:70:b6:65:d4:7d:b4:4d:c3: + * df:2c:08:9e:d2:3e:69:32:46:6f:6f:ca:d1:73:a4: + * 94:07:ef:14:e3:da:9e:2f:c0:ac:0e:10:33:4c:68: + * 79:f3:79:40:d6:e9:3c:c2:e6:70:e0:89:ce:a0:7a: + * a8:84:28:85:32:37:08:b0:cf:b1:7f:5f:bc:1f:a5: + * 3d:ef:d6:68:a8:17:21:5f:87:d5:4b:b5:cc:ee:78: + * 8d:dd:b1:28:6a:c0:fb:64:bd:b7:70:02:33:03:0b: + * b8:b8:bb:08:82:f6:8e:05:27:d1:3b:e6:c5:ac:4d: + * 85:5b:a1:1d:a3:48:5d:03:15:76:63:6c:71:21:3e: + * 98:cd + * Exponent: 65537 (0x10001) + * X509v3 extensions: + * X509v3 Subject Key Identifier: + * 5C:AF:44:B1:48:B8:59:9A:64:53:9D:2E:A6:B2:09:D3:0A:92:04:83 + * X509v3 Key Usage: + * Digital Signature, Non Repudiation, Key Encipherment + * X509v3 Subject Alternative Name: critical + * DNS:localhost + * X509v3 Basic Constraints: + * CA:FALSE + * X509v3 Authority Key Identifier: + * E0:03:90:F6:4F:BB:57:E6:7E:AF:5C:94:25:B3:85:DA:16:0A:51:40 + * Signature Algorithm: sha1WithRSAEncryption + * Signature Value: + * 9d:22:49:5f:56:23:e6:80:35:cc:ab:44:1c:27:bd:c9:8d:89: + * 93:49:58:e8:c1:7a:68:dd:cf:bd:e0:12:76:06:54:cd:2f:62: + * 9b:54:84:f2:bb:90:a0:bb:37:e2:13:1d:f3:df:41:aa:e0:fe: + * c0:ef:46:78:8d:aa:f4:1b:70:ad:a9:16:24:fa:15:4a:c6:0a: + * 8d:e1:99:93:00:a9:d4:b6:08:5d:8e:65:03:dc:d0:95:fc:95: + * 61:a6:ad:b5:ab:4d:a6:e0:05:48:8c:db:42:42:8a:d6:5e:c0: + * 2a:a0:11:15:b8:07:69:5c:3f:99:a0:bd:53:65:db:4e:cf:46: + * 61:93:09:7b:81:40:ff:5c:fe:4c:eb:f4:ac:de:1f:38:ad:b2: + * 60:28:f6:0e:9f:46:e7:07:8f:20:9a:a4:e1:8f:ab:54:99:76: + * 82:d8:9e:70:c4:da:98:85:71:af:3b:54:e4:01:b4:9e:83:d0: + * 7b:c6:8d:1f:ed:25:08:89:05:e9:87:97:76:5a:a3:85:c3:f8: + * 59:d7:bb:3b:5a:db:cb:ed:5d:ff:ac:21:b9:9a:e2:65:0a:bc: + * de:d1:dc:53:94:98:44:97:91:b3:1b:6b:80:0b:9b:57:b3:ae: + * 5c:7c:35:ca:39:71:f7:4e:8f:4a:d7:eb:0b:25:da:b2:1e:17: + * 48:b8:eb:09 * -----BEGIN CERTIFICATE----- - * MIICpDCCAg2gAwIBAgIBCDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMDRaFw0yODA4MjUwMzQzMDRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3 - * ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6 - * YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS - * 7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjczBxMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh - * bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAoqVTciHtcvsUj+YaTct8tUh3aTCsKsac - * PHhfQ+ObjiXSgxsKYTX7ym/wk/wvlbUcbqLKxsu7qrcJitH+H9heV1hEHEu65Uoi - * nRugFruyOrwvAylV8Cm2af7ddilmYJ+sdJA6N2M3xJRxR0G2LFHEXDNEjYReyexn - * JqCpf5uZGOo= + * MIIDpTCCAo2gAwIBAgIEBlY/nzANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV + * czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD + * VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTVaFw0zNDA3MDIwNDE2NTVaMGsx + * CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l + * LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMSAwHgYDVQQDExdsb2NhbGhvc3Qgb3U9 + * U1NMLVNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJoM4I+o + * An5a7+2yQq0ITpG6wq2bedebD/3S+BUvGYmAEAACGW0nwpDXpSNTdG5kKHwkqu3q + * IVnco1y1yUIxT6Le+wl8c+2IBDTxFa09YM3KxROZ05+bspJwy7pLPSCWrb6SU+1U + * O8UUvc/UD8sFT/0rnuBQu2UTksDWvU0CDHC2ZdR9tE3D3ywIntI+aTJGb2/K0XOk + * lAfvFOPani/ArA4QM0xoefN5QNbpPMLmcOCJzqB6qIQohTI3CLDPsX9fvB+lPe/W + * aKgXIV+H1Uu1zO54jd2xKGrA+2S9t3ACMwMLuLi7CIL2jgUn0TvmxaxNhVuhHaNI + * XQMVdmNscSE+mM0CAwEAAaNzMHEwHQYDVR0OBBYEFFyvRLFIuFmaZFOdLqayCdMK + * kgSDMAsGA1UdDwQEAwIF4DAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwCQYDVR0T + * BAIwADAfBgNVHSMEGDAWgBTgA5D2T7tX5n6vXJQls4XaFgpRQDANBgkqhkiG9w0B + * AQUFAAOCAQEAnSJJX1Yj5oA1zKtEHCe9yY2Jk0lY6MF6aN3PveASdgZUzS9im1SE + * 8ruQoLs34hMd899BquD+wO9GeI2q9BtwrakWJPoVSsYKjeGZkwCp1LYIXY5lA9zQ + * lfyVYaattatNpuAFSIzbQkKK1l7AKqARFbgHaVw/maC9U2XbTs9GYZMJe4FA/1z+ + * TOv0rN4fOK2yYCj2Dp9G5wePIJqk4Y+rVJl2gtiecMTamIVxrztU5AG0noPQe8aN + * H+0lCIkF6YeXdlqjhcP4Wde7O1rby+1d/6whuZriZQq83tHcU5SYRJeRsxtrgAub + * V7OuXHw1yjlx906PStfrCyXash4XSLjrCQ== * -----END CERTIFICATE----- * * * TLS client certificate: * client private key: - * ----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,FA2A435CD35A9390 - * - * Z+Y2uaETbsUWIyJUyVu1UV2G4rgFYJyACZT6Tp1KjRtxflSh2kXkJ9MpuXMXA0V4 - * Yy3fDzPqCL9NJmQAYRlAx/W/+j4F5EyMWDIx8fUxzONRZyoiwF7jLm+KscAfv6Pf - * q7ItWOdj3z7IYrwlB8YIGd3F2cDKT3S+lYRk7rKb/qT7itbuHnY4Ardh3yl+MZak - * jBp+ELUlRsUqSr1V0LoM+0rCCykarpyfhpxEcqsrl0v9Cyi5uhU50/oKv5zql3SH - * l2ImgDjp3batAs8+Bd4NF2aqi0a7Hy44JUHxRm4caZryU/i/D9N1MbuM6882HLat - * 5N0G+NaIUfywa8mjwq2D5aiit18HqKA6XeRRYeJ5Dvu9DCO4GeFSwcUFIBMI0L46 - * 7s114+oDodg57pMgITi+04vmUxvqlN9aiyd7f5Fgd7PeHGeOdbMz1NaJLJaPI9++ - * NakK8eK9iwT/Gdq0Uap5/CHW7vCT5PO+h3HY0STH0lWStXhdWnFO04zTdywsbSp+ - * DLpHeFT66shfeUlxR0PsCbG9vPRt/QmGLeYQZITppWo/ylSq4j+pRIuXvuWHdBRN - * rTZ8QF4Y7AxQUXVz1j1++s6ZMHTzaK2i9HrhmDs1MbJl+QwWre3Xpv3LvTVz3k5U - * wX8kuY1m3STt71QCaRWENq5sRaMImLxZbxc/ivFl9RAzUqo4NCxLod/QgA4iLqtO - * ztnlpzwlC/F8HbQ1oqYWwnZAPhzU/cULtstl+Yrws2c2atO323LbPXZqbASySgig - * sNpFXQMObdfP6LN23bY+1SvtK7V4NUTNhpdIc6INQAQ= - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICWwIBAAKBgQC78EA2rCZUTvSjWgAvaSFvuXo6k+yi9uGOx2PYLxIwmS6w8o/4 - * Jy0keCiE9wG/jUR53TvSVfPOPLJbIX3v/TNKsaP/xsibuQ98QTWX+ds6BWAFFa9Z - * F5KjEK0WHOQHU6+odqJWKpLT+SjgeM9eH0irXBnd4WdDunWN9YKsQ5JEGwIDAQAB - * AoGAEbdqNj0wN85hnWyEi/ObJU8UyKTdL9eaF72QGfcF/fLSxfd3vurihIeXOkGW - * tpn4lIxYcVGM9CognhqgJpl11jFTQzn1KqZ+NEJRKkCHA4hDabKJbSC9fXHvRwrf - * BsFpZqgiNxp3HseUTiwnaUVeyPgMt/jAj5nB5Sib+UyUxrECQQDnNQBiF2aifEg6 - * zbJOOC7he5CHAdkFxSxWVFVHL6EfXfqdLVkUohMbgZv+XxyIeU2biOExSg49Kds3 - * FOKgTau1AkEA0Bd1haj6QuCo8I0AXm2WO+MMTZMTvtHD/bGjKNM+fT4I8rKYnQRX - * 1acHdqS9Xx2rNJqZgkMmpESIdPR2fc4yjwJALFeM6EMmqvj8/VIf5UJ/Mz14fXwM - * PEARfckUxd9LnnFutCBTWlKvKXJVEZb6KO5ixPaegc57Jp3Vbh3yTN44lQJADD/1 - * SSMDaIB1MYP7a5Oj7m6VQNPRq8AJe5vDcRnOae0G9dKRrVyeFxO4GsHj6/+BHp2j - * P8nYMn9eURQ7DXjf/QJAAQzMlWnKGSO8pyTDtnQx3hRMoUkOEhmNq4bQhLkYqtnY - * FcqpUQ2qMjW+NiNWk5HnTrMS3L9EdJobMUzaNZLy4w== - * -----END RSA PRIVATE KEY----- * - * Private-Key: (1024 bit) + * Private-Key: (2048 bit, 2 primes) * modulus: - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b + * 00:cc:bf:92:3c:a6:57:74:1f:58:ad:c7:69:88:6f: + * 59:32:47:50:60:22:e4:98:49:0e:3e:1d:b8:ba:e2: + * 3b:b6:71:5b:fd:64:02:6d:0d:50:77:72:6e:a8:3d: + * 5d:d4:bd:1f:76:51:dc:9a:d0:d6:3e:d0:31:a5:24: + * 5a:2c:be:77:fa:88:a1:fa:06:41:c8:0f:47:70:47: + * 24:99:50:52:44:5b:30:62:5b:65:35:c4:28:b0:5c: + * ee:d0:1b:eb:39:2b:0b:a1:ac:96:48:da:56:6c:e0: + * e3:e6:e3:dd:45:cb:51:33:8d:40:43:d7:f0:a4:31: + * aa:b5:c0:df:4b:df:2b:0a:ed:7e:10:0c:ae:1f:96: + * a2:10:1e:6b:d0:f9:37:8b:df:0d:0e:02:35:f8:58: + * bc:6e:b5:57:0e:2f:ea:20:e6:73:9a:e5:6b:82:70: + * 25:bb:51:9a:7c:9d:e2:50:3d:cf:1e:24:3e:92:55: + * cf:2a:ad:0d:84:8f:a8:43:24:cd:ad:50:64:74:c2: + * 73:b6:e1:92:1c:b2:2b:8c:2d:7b:96:a6:41:61:5c: + * 1b:8f:78:28:51:40:ed:41:90:ce:1d:b8:26:81:47: + * 6b:e3:57:41:74:4e:20:f0:5a:1b:97:37:91:86:19: + * c5:f2:6d:04:c9:78:2b:5a:16:bc:fc:2b:71:5b:d0: + * 00:4f * publicExponent: 65537 (0x10001) * privateExponent: - * 11:b7:6a:36:3d:30:37:ce:61:9d:6c:84:8b:f3:9b: - * 25:4f:14:c8:a4:dd:2f:d7:9a:17:bd:90:19:f7:05: - * fd:f2:d2:c5:f7:77:be:ea:e2:84:87:97:3a:41:96: - * b6:99:f8:94:8c:58:71:51:8c:f4:2a:20:9e:1a:a0: - * 26:99:75:d6:31:53:43:39:f5:2a:a6:7e:34:42:51: - * 2a:40:87:03:88:43:69:b2:89:6d:20:bd:7d:71:ef: - * 47:0a:df:06:c1:69:66:a8:22:37:1a:77:1e:c7:94: - * 4e:2c:27:69:45:5e:c8:f8:0c:b7:f8:c0:8f:99:c1: - * e5:28:9b:f9:4c:94:c6:b1 + * 62:b2:d6:63:b6:2b:e2:26:5a:31:2b:37:8c:35:60: + * e2:03:ce:93:09:3e:f8:c9:fe:bb:a2:c8:32:0e:6c: + * 8a:7e:0a:c2:13:3b:b8:25:fa:ec:19:95:8e:34:46: + * cf:0e:7b:e4:25:82:1a:7f:21:48:16:44:58:3f:35: + * d8:eb:d8:1a:45:53:0f:9b:84:8a:54:13:33:e4:97: + * 97:f0:48:37:fb:5d:4f:8c:8f:35:63:e1:d9:62:73: + * 1c:8e:d8:cd:2e:1a:e5:4c:b5:05:59:7a:df:f1:68: + * eb:1c:5c:c6:10:44:8c:7d:42:c5:71:8a:e7:1b:aa: + * 17:03:6a:a0:c0:6b:97:50:17:ad:6e:5e:d9:db:6f: + * 3e:e9:3f:35:c3:45:bc:e8:3d:5a:b4:b9:3f:53:80: + * 64:dc:12:24:35:35:bd:98:bb:8d:fa:19:a3:5e:9e: + * ac:70:4a:fc:8d:ae:55:8b:71:81:0e:4d:c8:2f:87: + * b0:44:f7:4f:dc:a8:c8:50:b5:95:24:63:74:13:54: + * 58:de:fc:e0:75:eb:f4:06:58:83:12:4c:56:c4:c4: + * 18:0c:ea:a3:e7:25:a3:de:19:23:a2:5a:2a:b6:56: + * 04:bc:65:ba:7c:0a:f4:91:10:22:88:3f:9d:be:58: + * 43:4c:2e:ad:db:d6:32:cf:8e:b5:05:55:39:8b:e1: + * 01 * prime1: - * 00:e7:35:00:62:17:66:a2:7c:48:3a:cd:b2:4e:38: - * 2e:e1:7b:90:87:01:d9:05:c5:2c:56:54:55:47:2f: - * a1:1f:5d:fa:9d:2d:59:14:a2:13:1b:81:9b:fe:5f: - * 1c:88:79:4d:9b:88:e1:31:4a:0e:3d:29:db:37:14: - * e2:a0:4d:ab:b5 + * 00:f1:da:c2:8a:e5:66:45:8a:14:fc:08:6e:fb:aa: + * 50:d2:8c:b1:c4:f4:88:26:d4:b8:c4:63:30:ca:e3: + * 0c:6c:50:d4:93:5c:1c:13:37:60:21:11:3b:d1:f1: + * 9f:4c:0d:7b:0e:53:3d:c9:a4:fb:fa:6b:9e:b4:0a: + * 5d:d3:50:88:d7:be:c3:88:b2:b1:8a:6e:7b:d6:70: + * 88:96:a4:fe:90:ef:d1:84:ad:a8:9e:9f:3a:68:3f: + * 3f:82:07:be:c2:44:1e:d5:a1:a9:1a:db:39:d7:7f: + * 0c:6e:35:5b:1d:33:1b:a9:cd:38:2a:64:d1:70:2a: + * fe:b9:c2:b6:ed:59:19:73:b1 * prime2: - * 00:d0:17:75:85:a8:fa:42:e0:a8:f0:8d:00:5e:6d: - * 96:3b:e3:0c:4d:93:13:be:d1:c3:fd:b1:a3:28:d3: - * 3e:7d:3e:08:f2:b2:98:9d:04:57:d5:a7:07:76:a4: - * bd:5f:1d:ab:34:9a:99:82:43:26:a4:44:88:74:f4: - * 76:7d:ce:32:8f + * 00:d8:b9:3a:38:6c:79:cd:0b:1f:2b:34:74:bf:7a: + * 3d:0c:21:5a:a6:ea:f2:9e:de:68:42:05:7f:ea:a5: + * 00:c9:10:f8:fd:c5:05:8d:03:45:5d:4f:6f:fa:6e: + * 9d:ef:ad:8a:ec:83:d4:ed:57:f3:86:73:15:2f:d2: + * 67:70:d1:62:ef:1d:25:08:59:47:20:62:47:16:35: + * e1:57:38:bf:39:dd:fc:b9:c8:d8:23:53:e2:02:7d: + * 22:31:4c:66:72:96:df:d8:7c:01:2c:71:00:89:18: + * e9:8c:08:44:8c:64:1f:93:9b:7a:97:26:c9:50:d0: + * 87:b2:48:a8:19:71:e1:b3:ff * exponent1: - * 2c:57:8c:e8:43:26:aa:f8:fc:fd:52:1f:e5:42:7f: - * 33:3d:78:7d:7c:0c:3c:40:11:7d:c9:14:c5:df:4b: - * 9e:71:6e:b4:20:53:5a:52:af:29:72:55:11:96:fa: - * 28:ee:62:c4:f6:9e:81:ce:7b:26:9d:d5:6e:1d:f2: - * 4c:de:38:95 + * 23:98:dd:35:70:5a:43:35:f5:ac:ba:d9:0a:f5:a0: + * 7b:bc:f5:95:55:a0:8c:86:96:c3:61:0e:17:6e:9f: + * af:79:9e:30:2a:48:7f:93:90:f4:8d:02:ce:fd:cf: + * 42:74:61:7e:54:46:2d:dd:b8:b0:bd:12:58:d1:85: + * c9:ca:7a:b9:b6:7c:35:2c:87:f1:26:1d:d8:0c:2c: + * 2e:70:0e:7f:ea:ac:5d:e8:e9:7e:9f:55:0b:6e:f3: + * bc:01:c3:d3:f8:0e:c9:c6:c7:8b:0a:65:53:10:82: + * 15:de:88:90:9d:ab:1e:ac:f3:ed:59:75:72:1b:01: + * ee:f9:77:cf:2b:64:11:a1 * exponent2: - * 0c:3f:f5:49:23:03:68:80:75:31:83:fb:6b:93:a3: - * ee:6e:95:40:d3:d1:ab:c0:09:7b:9b:c3:71:19:ce: - * 69:ed:06:f5:d2:91:ad:5c:9e:17:13:b8:1a:c1:e3: - * eb:ff:81:1e:9d:a3:3f:c9:d8:32:7f:5e:51:14:3b: - * 0d:78:df:fd + * 00:9e:29:6f:87:c6:02:8d:d5:54:05:df:de:63:ee: + * fd:a6:60:a1:1b:b7:d3:20:86:07:68:47:43:37:26: + * fc:0f:c0:c7:35:cc:17:64:f5:c2:25:7a:d7:a9:d8: + * 18:82:d6:0f:d0:d3:d5:0c:f1:66:d3:f4:20:be:29: + * bb:3b:e6:53:61:55:cf:b4:ec:12:b0:5b:88:ad:78: + * dc:df:1e:96:cf:d0:65:a3:e0:23:7c:84:b7:28:41: + * d2:36:50:1f:63:f9:1f:9b:89:c4:01:7e:e6:79:27: + * 29:29:fc:ce:a9:f6:57:e5:0d:4e:c6:08:94:5a:da: + * 14:6d:d4:00:79:b1:56:9a:59 * coefficient: - * 01:0c:cc:95:69:ca:19:23:bc:a7:24:c3:b6:74:31: - * de:14:4c:a1:49:0e:12:19:8d:ab:86:d0:84:b9:18: - * aa:d9:d8:15:ca:a9:51:0d:aa:32:35:be:36:23:56: - * 93:91:e7:4e:b3:12:dc:bf:44:74:9a:1b:31:4c:da: - * 35:92:f2:e3 + * 6c:73:0d:fe:c7:22:15:5d:8c:a1:91:2b:d1:88:e8: + * 91:f9:d0:3e:d0:ba:c4:74:88:ce:14:20:4e:1e:4b: + * c5:91:8f:c1:56:e9:74:e0:f6:cf:71:91:ed:2c:f5: + * 90:9d:d6:c8:cd:f5:79:dc:6e:b3:83:3e:fa:d6:b4: + * 60:d9:3a:52:12:76:9d:92:fb:db:26:ee:43:33:c4: + * 0b:84:74:1b:91:e0:41:8b:cc:cc:24:da:52:af:2d: + * 42:e7:11:57:0d:aa:66:af:1a:ba:c2:8e:6a:ee:8f: + * 2c:e6:5b:76:38:96:bb:7a:2f:59:fe:de:a1:02:fc: + * 12:3a:aa:9f:3c:0e:a4:78 + * writing RSA key + * -----BEGIN PRIVATE KEY----- + * MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMv5I8pld0H1it + * x2mIb1kyR1BgIuSYSQ4+Hbi64ju2cVv9ZAJtDVB3cm6oPV3UvR92Udya0NY+0DGl + * JFosvnf6iKH6BkHID0dwRySZUFJEWzBiW2U1xCiwXO7QG+s5KwuhrJZI2lZs4OPm + * 491Fy1EzjUBD1/CkMaq1wN9L3ysK7X4QDK4flqIQHmvQ+TeL3w0OAjX4WLxutVcO + * L+og5nOa5WuCcCW7UZp8neJQPc8eJD6SVc8qrQ2Ej6hDJM2tUGR0wnO24ZIcsiuM + * LXuWpkFhXBuPeChRQO1BkM4duCaBR2vjV0F0TiDwWhuXN5GGGcXybQTJeCtaFrz8 + * K3Fb0ABPAgMBAAECggEAYrLWY7Yr4iZaMSs3jDVg4gPOkwk++Mn+u6LIMg5sin4K + * whM7uCX67BmVjjRGzw575CWCGn8hSBZEWD812OvYGkVTD5uEilQTM+SXl/BIN/td + * T4yPNWPh2WJzHI7YzS4a5Uy1BVl63/Fo6xxcxhBEjH1CxXGK5xuqFwNqoMBrl1AX + * rW5e2dtvPuk/NcNFvOg9WrS5P1OAZNwSJDU1vZi7jfoZo16erHBK/I2uVYtxgQ5N + * yC+HsET3T9yoyFC1lSRjdBNUWN784HXr9AZYgxJMVsTEGAzqo+clo94ZI6JaKrZW + * BLxlunwK9JEQIog/nb5YQ0wurdvWMs+OtQVVOYvhAQKBgQDx2sKK5WZFihT8CG77 + * qlDSjLHE9Igm1LjEYzDK4wxsUNSTXBwTN2AhETvR8Z9MDXsOUz3JpPv6a560Cl3T + * UIjXvsOIsrGKbnvWcIiWpP6Q79GEraienzpoPz+CB77CRB7Voaka2znXfwxuNVsd + * MxupzTgqZNFwKv65wrbtWRlzsQKBgQDYuTo4bHnNCx8rNHS/ej0MIVqm6vKe3mhC + * BX/qpQDJEPj9xQWNA0VdT2/6bp3vrYrsg9TtV/OGcxUv0mdw0WLvHSUIWUcgYkcW + * NeFXOL853fy5yNgjU+ICfSIxTGZylt/YfAEscQCJGOmMCESMZB+Tm3qXJslQ0Iey + * SKgZceGz/wKBgCOY3TVwWkM19ay62Qr1oHu89ZVVoIyGlsNhDhdun695njAqSH+T + * kPSNAs79z0J0YX5URi3duLC9EljRhcnKerm2fDUsh/EmHdgMLC5wDn/qrF3o6X6f + * VQtu87wBw9P4DsnGx4sKZVMQghXeiJCdqx6s8+1ZdXIbAe75d88rZBGhAoGBAJ4p + * b4fGAo3VVAXf3mPu/aZgoRu30yCGB2hHQzcm/A/AxzXMF2T1wiV616nYGILWD9DT + * 1QzxZtP0IL4puzvmU2FVz7TsErBbiK143N8els/QZaPgI3yEtyhB0jZQH2P5H5uJ + * xAF+5nknKSn8zqn2V+UNTsYIlFraFG3UAHmxVppZAoGAbHMN/sciFV2MoZEr0Yjo + * kfnQPtC6xHSIzhQgTh5LxZGPwVbpdOD2z3GR7Sz1kJ3WyM31edxus4M++ta0YNk6 + * UhJ2nZL72ybuQzPEC4R0G5HgQYvMzCTaUq8tQucRVw2qZq8ausKOau6PLOZbdjiW + * u3ovWf7eoQL8EjqqnzwOpHg= + * -----END PRIVATE KEY----- * * client certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 9 (0x9) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:43:24 2008 GMT - * Not After : Aug 25 03:43:24 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * DNS:localhost - * Signature Algorithm: md5WithRSAEncryption - * + * Data: + * Version: 3 (0x2) + * Serial Number: 1500699355 (0x5972dadb) + * Signature Algorithm: sha1WithRSAEncryption + * Issuer: C=Us, ST=Some-State, L=Some-City, O=Some-Org + * Validity + * Not Before: Jul 1 04:16:52 2024 GMT + * Not After : Jul 2 04:16:52 2034 GMT + * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, CN=localhost ou=SSL-Client + * Subject Public Key Info: + * Public Key Algorithm: rsaEncryption + * Public-Key: (2048 bit) + * Modulus: + * 00:cc:bf:92:3c:a6:57:74:1f:58:ad:c7:69:88:6f: + * 59:32:47:50:60:22:e4:98:49:0e:3e:1d:b8:ba:e2: + * 3b:b6:71:5b:fd:64:02:6d:0d:50:77:72:6e:a8:3d: + * 5d:d4:bd:1f:76:51:dc:9a:d0:d6:3e:d0:31:a5:24: + * 5a:2c:be:77:fa:88:a1:fa:06:41:c8:0f:47:70:47: + * 24:99:50:52:44:5b:30:62:5b:65:35:c4:28:b0:5c: + * ee:d0:1b:eb:39:2b:0b:a1:ac:96:48:da:56:6c:e0: + * e3:e6:e3:dd:45:cb:51:33:8d:40:43:d7:f0:a4:31: + * aa:b5:c0:df:4b:df:2b:0a:ed:7e:10:0c:ae:1f:96: + * a2:10:1e:6b:d0:f9:37:8b:df:0d:0e:02:35:f8:58: + * bc:6e:b5:57:0e:2f:ea:20:e6:73:9a:e5:6b:82:70: + * 25:bb:51:9a:7c:9d:e2:50:3d:cf:1e:24:3e:92:55: + * cf:2a:ad:0d:84:8f:a8:43:24:cd:ad:50:64:74:c2: + * 73:b6:e1:92:1c:b2:2b:8c:2d:7b:96:a6:41:61:5c: + * 1b:8f:78:28:51:40:ed:41:90:ce:1d:b8:26:81:47: + * 6b:e3:57:41:74:4e:20:f0:5a:1b:97:37:91:86:19: + * c5:f2:6d:04:c9:78:2b:5a:16:bc:fc:2b:71:5b:d0: + * 00:4f + * Exponent: 65537 (0x10001) + * X509v3 extensions: + * X509v3 Subject Key Identifier: + * CD:45:E2:05:92:88:A3:C7:49:28:E7:D3:37:B7:13:92:FB:B1:36:C4 + * X509v3 Key Usage: + * Digital Signature, Non Repudiation, Key Encipherment + * X509v3 Subject Alternative Name: critical + * DNS:localhost + * X509v3 Basic Constraints: + * CA:FALSE + * X509v3 Authority Key Identifier: + * E0:03:90:F6:4F:BB:57:E6:7E:AF:5C:94:25:B3:85:DA:16:0A:51:40 + * Signature Algorithm: sha1WithRSAEncryption + * Signature Value: + * 23:6e:e9:5d:80:0d:b3:86:c9:cd:17:81:33:bd:5b:aa:c0:65: + * 4c:6b:9f:fa:ee:32:e9:89:e1:d0:c7:1d:5c:43:7e:94:ac:83: + * af:91:90:4c:26:61:8d:fe:6b:1a:aa:6e:61:39:b3:24:4a:dc: + * 92:c8:ca:f2:80:b0:05:41:0c:b3:dd:ed:b7:81:42:9a:1e:4e: + * f2:80:6c:72:62:8b:bd:d4:cd:23:7d:7c:e8:6f:e3:67:89:6a: + * 79:19:dd:f6:57:62:12:fa:eb:cd:66:c3:d2:d8:40:5a:1c:dd: + * 7f:9f:b2:34:e9:2a:d6:14:52:ba:6e:a8:9b:0d:a9:a1:03:bf: + * c4:0d:92:3d:59:e4:a9:8e:20:41:39:99:81:70:9d:d0:68:98: + * fc:5f:49:4a:92:e5:a2:c1:51:61:f6:1e:49:56:0b:b6:8c:57: + * db:08:2a:f0:a3:04:dc:a1:04:a2:5c:d0:90:4f:13:8d:1c:e6: + * 2e:7a:63:9c:32:40:65:59:04:5d:71:90:5a:a8:db:6a:30:42: + * 57:5b:0b:df:ce:a1:1f:fa:23:71:f3:57:12:c4:1c:66:3b:37: + * 77:32:28:a7:fb:ad:ee:86:51:4c:80:2f:dd:c8:5b:9f:a7:15: + * 07:fa:2b:5a:ee:93:00:5f:a6:43:22:1b:40:52:15:66:01:84: + * 32:9e:71:21 * -----BEGIN CERTIFICATE----- - * MIICpDCCAg2gAwIBAgIBCTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMjRaFw0yODA4MjUwMzQzMjRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas - * JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV - * 8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq - * ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjczBxMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh - * bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAm25gJyqW1JznQ1EyOtTGswBVwfgBOf+F - * HJuBTcflYQLbTD/AETPQJGvZU9tdhuLtbG3OPhR7vSY8zeAbfM3dbH7QFr3r47Gj - * XEH7qM/MX+Z3ifVaC4MeJmrYQkYFSuKeyyKpdRVX4w4nnFHF6OsNASsYrMW6LpxN - * cl/epUcHL7E= + * MIIDpTCCAo2gAwIBAgIEWXLa2zANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV + * czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD + * VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTJaFw0zNDA3MDIwNDE2NTJaMGsx + * CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l + * LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMSAwHgYDVQQDExdsb2NhbGhvc3Qgb3U9 + * U1NMLUNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMy/kjym + * V3QfWK3HaYhvWTJHUGAi5JhJDj4duLriO7ZxW/1kAm0NUHdybqg9XdS9H3ZR3JrQ + * 1j7QMaUkWiy+d/qIofoGQcgPR3BHJJlQUkRbMGJbZTXEKLBc7tAb6zkrC6Gslkja + * Vmzg4+bj3UXLUTONQEPX8KQxqrXA30vfKwrtfhAMrh+WohAea9D5N4vfDQ4CNfhY + * vG61Vw4v6iDmc5rla4JwJbtRmnyd4lA9zx4kPpJVzyqtDYSPqEMkza1QZHTCc7bh + * khyyK4wte5amQWFcG494KFFA7UGQzh24JoFHa+NXQXROIPBaG5c3kYYZxfJtBMl4 + * K1oWvPwrcVvQAE8CAwEAAaNzMHEwHQYDVR0OBBYEFM1F4gWSiKPHSSjn0ze3E5L7 + * sTbEMAsGA1UdDwQEAwIF4DAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwCQYDVR0T + * BAIwADAfBgNVHSMEGDAWgBTgA5D2T7tX5n6vXJQls4XaFgpRQDANBgkqhkiG9w0B + * AQUFAAOCAQEAI27pXYANs4bJzReBM71bqsBlTGuf+u4y6Ynh0McdXEN+lKyDr5GQ + * TCZhjf5rGqpuYTmzJErcksjK8oCwBUEMs93tt4FCmh5O8oBscmKLvdTNI3186G/j + * Z4lqeRnd9ldiEvrrzWbD0thAWhzdf5+yNOkq1hRSum6omw2poQO/xA2SPVnkqY4g + * QTmZgXCd0GiY/F9JSpLlosFRYfYeSVYLtoxX2wgq8KME3KEEolzQkE8TjRzmLnpj + * nDJAZVkEXXGQWqjbajBCV1sL386hH/ojcfNXEsQcZjs3dzIop/ut7oZRTIAv3chb + * n6cVB/orWu6TAF+mQyIbQFIVZgGEMp5xIQ== * -----END CERTIFICATE----- * * - * * Trusted CA certificate: * Certificate: * Data: - * Version: 3 (0x2) - * Serial Number: 0 (0x0) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 02:43:36 2008 GMT - * Not After : Aug 25 02:43:36 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d: - * d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53: - * 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9: - * 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f: - * 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7: - * 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee: - * f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee: - * 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97: - * 89:2a:95:12:4c:d8:09:2a:e9 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Subject Key Identifier: - * FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org - * serial:00 - * - * X509v3 Basic Constraints: - * CA:TRUE - * Signature Algorithm: md5WithRSAEncryption - * + * Version: 3 (0x2) + * Serial Number: 1539881479 (0x5bc8ba07) + * Signature Algorithm: sha1WithRSAEncryption + * Issuer: C=Us, ST=Some-State, L=Some-City, O=Some-Org + * Validity + * Not Before: Jul 1 04:16:50 2024 GMT + * Not After : Jul 2 04:16:50 2034 GMT + * Subject: C=Us, ST=Some-State, L=Some-City, O=Some-Org + * Subject Public Key Info: + * Public Key Algorithm: rsaEncryption + * Public-Key: (2048 bit) + * Modulus: + * 00:bc:a6:55:60:3f:17:74:39:ba:71:8c:ef:11:3f: + * 9d:36:47:d5:02:d1:4d:9d:7e:b8:fe:59:b1:2b:f1: + * b7:b0:0c:31:57:eb:9c:9d:13:f5:4c:5f:fc:c4:9e: + * f9:75:09:0f:96:8f:05:77:30:a8:35:48:71:96:e4: + * a5:7d:1a:81:fb:e6:bf:90:80:60:5d:11:20:54:16: + * 0b:6d:df:64:de:18:d5:98:51:38:9d:c9:d6:5f:de: + * 9d:de:fe:a8:5f:d3:25:3d:ad:f3:2b:45:c8:4a:80: + * 97:14:7b:85:9d:cf:59:08:bb:c7:67:ac:8b:29:f3: + * 1e:93:bf:fb:82:53:c5:ae:b4:bc:55:30:15:a8:7e: + * 3f:82:22:59:43:cc:d2:62:e7:65:67:72:ec:10:8a: + * fc:05:90:91:72:dd:e9:6f:e2:9f:0c:ab:a1:83:55: + * 02:23:b7:a3:c3:50:ab:be:0b:bb:51:75:50:d1:a8: + * c9:e5:f5:06:fe:00:09:a6:1b:8a:16:29:0d:ab:00: + * 3e:bc:d2:73:d9:37:d7:d9:9a:58:6e:2d:2a:f6:76: + * ae:f4:ea:6d:70:de:7f:e3:04:43:c0:4f:91:3f:78: + * 58:d7:c2:ad:74:eb:04:9d:d0:7e:82:b8:7a:97:44: + * 61:fa:41:45:a6:ca:7d:a5:2e:fc:f9:a6:cf:61:cd: + * 75:bf + * Exponent: 65537 (0x10001) + * X509v3 extensions: + * X509v3 Subject Key Identifier: + * E0:03:90:F6:4F:BB:57:E6:7E:AF:5C:94:25:B3:85:DA:16:0A:51:40 + * X509v3 Basic Constraints: critical + * CA:TRUE + * Signature Algorithm: sha1WithRSAEncryption + * Signature Value: + * 1f:89:34:e3:ee:05:33:3b:18:ca:96:13:3d:ad:cd:5a:e6:24: + * 46:94:36:ad:37:a5:36:a9:92:37:f9:ed:07:dd:44:5b:c9:2e: + * 68:f7:82:f3:58:1c:64:ed:64:d0:ad:eb:30:15:e0:04:3a:d7: + * c8:c7:9d:65:76:ae:84:e4:2e:2d:0d:68:09:0d:e5:ae:cc:a7: + * 54:86:ad:ff:00:95:85:01:49:db:5b:8e:c2:6f:e7:19:10:17: + * f7:03:b9:a8:97:21:a2:fc:7f:c0:e0:7a:12:64:b8:70:f5:e8: + * b6:e1:25:f7:eb:32:3e:46:ce:43:55:fc:0b:62:59:90:61:63: + * f9:94:6c:95:63:31:1b:00:59:1f:72:9d:d0:0b:4f:cd:02:eb: + * de:20:4e:60:48:4e:ea:ad:3c:0f:1d:bf:1a:69:3d:a8:3d:8b: + * f5:a2:ae:8c:4f:d7:0e:b3:e1:9b:b3:2c:89:19:18:da:db:e1: + * 6d:d5:ab:c8:b8:48:57:d8:8b:33:01:d4:97:91:d9:da:34:a1: + * ef:36:00:e1:38:19:34:8f:0d:47:af:57:cf:59:d6:8b:0d:9e: + * 89:05:82:3d:3c:f3:45:1d:4a:3f:0e:0f:5a:28:6f:5c:e1:e9: + * 60:72:87:28:b6:97:44:8b:d7:c6:cd:cb:dc:5a:5d:60:f1:b4: + * 37:ee:44:db * -----BEGIN CERTIFICATE----- - * MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB - * gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX - * 4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj - * 7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G - * A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ - * hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt - * U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw - * DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA - * ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ - * LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P - * 6Mvf0r1PNTY2hwTJLJmKtg== + * MIIDQjCCAiqgAwIBAgIEW8i6BzANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV + * czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD + * VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTBaFw0zNDA3MDIwNDE2NTBaMEkx + * CzAJBgNVBAYTAlVzMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l + * LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A + * MIIBCgKCAQEAvKZVYD8XdDm6cYzvET+dNkfVAtFNnX64/lmxK/G3sAwxV+ucnRP1 + * TF/8xJ75dQkPlo8FdzCoNUhxluSlfRqB++a/kIBgXREgVBYLbd9k3hjVmFE4ncnW + * X96d3v6oX9MlPa3zK0XISoCXFHuFnc9ZCLvHZ6yLKfMek7/7glPFrrS8VTAVqH4/ + * giJZQ8zSYudlZ3LsEIr8BZCRct3pb+KfDKuhg1UCI7ejw1Crvgu7UXVQ0ajJ5fUG + * /gAJphuKFikNqwA+vNJz2TfX2ZpYbi0q9nau9OptcN5/4wRDwE+RP3hY18KtdOsE + * ndB+grh6l0Rh+kFFpsp9pS78+abPYc11vwIDAQABozIwMDAdBgNVHQ4EFgQU4AOQ + * 9k+7V+Z+r1yUJbOF2hYKUUAwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUF + * AAOCAQEAH4k04+4FMzsYypYTPa3NWuYkRpQ2rTelNqmSN/ntB91EW8kuaPeC81gc + * ZO1k0K3rMBXgBDrXyMedZXauhOQuLQ1oCQ3lrsynVIat/wCVhQFJ21uOwm/nGRAX + * 9wO5qJchovx/wOB6EmS4cPXotuEl9+syPkbOQ1X8C2JZkGFj+ZRslWMxGwBZH3Kd + * 0AtPzQLr3iBOYEhO6q08Dx2/Gmk9qD2L9aKujE/XDrPhm7MsiRkY2tvhbdWryLhI + * V9iLMwHUl5HZ2jSh7zYA4TgZNI8NR69Xz1nWiw2eiQWCPTzzRR1KPw4PWihvXOHp + * YHKHKLaXRIvXxs3L3FpdYPG0N+5E2w== * -----END CERTIFICATE--- */ - public class SunX509ExtendedTM { /* @@ -423,201 +563,342 @@ public class SunX509ExtendedTM { */ static String trusedCertStr = "-----BEGIN CERTIFICATE-----\n" + - "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + - "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" + - "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" + - "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" + - "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" + - "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" + - "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" + - "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" + - "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" + - "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" + - "6Mvf0r1PNTY2hwTJLJmKtg==\n" + + "MIIDQjCCAiqgAwIBAgIEW8i6BzANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV\n" + + "czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD\n" + + "VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTBaFw0zNDA3MDIwNDE2NTBaMEkx\n" + + "CzAJBgNVBAYTAlVzMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l\n" + + "LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + + "MIIBCgKCAQEAvKZVYD8XdDm6cYzvET+dNkfVAtFNnX64/lmxK/G3sAwxV+ucnRP1\n" + + "TF/8xJ75dQkPlo8FdzCoNUhxluSlfRqB++a/kIBgXREgVBYLbd9k3hjVmFE4ncnW\n" + + "X96d3v6oX9MlPa3zK0XISoCXFHuFnc9ZCLvHZ6yLKfMek7/7glPFrrS8VTAVqH4/\n" + + "giJZQ8zSYudlZ3LsEIr8BZCRct3pb+KfDKuhg1UCI7ejw1Crvgu7UXVQ0ajJ5fUG\n" + + "/gAJphuKFikNqwA+vNJz2TfX2ZpYbi0q9nau9OptcN5/4wRDwE+RP3hY18KtdOsE\n" + + "ndB+grh6l0Rh+kFFpsp9pS78+abPYc11vwIDAQABozIwMDAdBgNVHQ4EFgQU4AOQ\n" + + "9k+7V+Z+r1yUJbOF2hYKUUAwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUF\n" + + "AAOCAQEAH4k04+4FMzsYypYTPa3NWuYkRpQ2rTelNqmSN/ntB91EW8kuaPeC81gc\n" + + "ZO1k0K3rMBXgBDrXyMedZXauhOQuLQ1oCQ3lrsynVIat/wCVhQFJ21uOwm/nGRAX\n" + + "9wO5qJchovx/wOB6EmS4cPXotuEl9+syPkbOQ1X8C2JZkGFj+ZRslWMxGwBZH3Kd\n" + + "0AtPzQLr3iBOYEhO6q08Dx2/Gmk9qD2L9aKujE/XDrPhm7MsiRkY2tvhbdWryLhI\n" + + "V9iLMwHUl5HZ2jSh7zYA4TgZNI8NR69Xz1nWiw2eiQWCPTzzRR1KPw4PWihvXOHp\n" + + "YHKHKLaXRIvXxs3L3FpdYPG0N+5E2w==\n" + "-----END CERTIFICATE-----"; static String serverCertStr = "-----BEGIN CERTIFICATE-----\n" + - "MIICpDCCAg2gAwIBAgIBCDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMDRaFw0yODA4MjUwMzQzMDRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3\n" + - "ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6\n" + - "YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS\n" + - "7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjczBxMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh\n" + - "bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAoqVTciHtcvsUj+YaTct8tUh3aTCsKsac\n" + - "PHhfQ+ObjiXSgxsKYTX7ym/wk/wvlbUcbqLKxsu7qrcJitH+H9heV1hEHEu65Uoi\n" + - "nRugFruyOrwvAylV8Cm2af7ddilmYJ+sdJA6N2M3xJRxR0G2LFHEXDNEjYReyexn\n" + - "JqCpf5uZGOo=\n" + + "MIIDpTCCAo2gAwIBAgIEBlY/nzANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV\n" + + "czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD\n" + + "VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTVaFw0zNDA3MDIwNDE2NTVaMGsx\n" + + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l\n" + + "LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMSAwHgYDVQQDExdsb2NhbGhvc3Qgb3U9\n" + + "U1NMLVNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJoM4I+o\n" + + "An5a7+2yQq0ITpG6wq2bedebD/3S+BUvGYmAEAACGW0nwpDXpSNTdG5kKHwkqu3q\n" + + "IVnco1y1yUIxT6Le+wl8c+2IBDTxFa09YM3KxROZ05+bspJwy7pLPSCWrb6SU+1U\n" + + "O8UUvc/UD8sFT/0rnuBQu2UTksDWvU0CDHC2ZdR9tE3D3ywIntI+aTJGb2/K0XOk\n" + + "lAfvFOPani/ArA4QM0xoefN5QNbpPMLmcOCJzqB6qIQohTI3CLDPsX9fvB+lPe/W\n" + + "aKgXIV+H1Uu1zO54jd2xKGrA+2S9t3ACMwMLuLi7CIL2jgUn0TvmxaxNhVuhHaNI\n" + + "XQMVdmNscSE+mM0CAwEAAaNzMHEwHQYDVR0OBBYEFFyvRLFIuFmaZFOdLqayCdMK\n" + + "kgSDMAsGA1UdDwQEAwIF4DAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwCQYDVR0T\n" + + "BAIwADAfBgNVHSMEGDAWgBTgA5D2T7tX5n6vXJQls4XaFgpRQDANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEAnSJJX1Yj5oA1zKtEHCe9yY2Jk0lY6MF6aN3PveASdgZUzS9im1SE\n" + + "8ruQoLs34hMd899BquD+wO9GeI2q9BtwrakWJPoVSsYKjeGZkwCp1LYIXY5lA9zQ\n" + + "lfyVYaattatNpuAFSIzbQkKK1l7AKqARFbgHaVw/maC9U2XbTs9GYZMJe4FA/1z+\n" + + "TOv0rN4fOK2yYCj2Dp9G5wePIJqk4Y+rVJl2gtiecMTamIVxrztU5AG0noPQe8aN\n" + + "H+0lCIkF6YeXdlqjhcP4Wde7O1rby+1d/6whuZriZQq83tHcU5SYRJeRsxtrgAub\n" + + "V7OuXHw1yjlx906PStfrCyXash4XSLjrCQ==\n" + "-----END CERTIFICATE-----"; static String clientCertStr = "-----BEGIN CERTIFICATE-----\n" + - "MIICpDCCAg2gAwIBAgIBCTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMjRaFw0yODA4MjUwMzQzMjRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" + - "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" + - "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" + - "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjczBxMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh\n" + - "bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAm25gJyqW1JznQ1EyOtTGswBVwfgBOf+F\n" + - "HJuBTcflYQLbTD/AETPQJGvZU9tdhuLtbG3OPhR7vSY8zeAbfM3dbH7QFr3r47Gj\n" + - "XEH7qM/MX+Z3ifVaC4MeJmrYQkYFSuKeyyKpdRVX4w4nnFHF6OsNASsYrMW6LpxN\n" + - "cl/epUcHL7E=\n" + + "MIIDpTCCAo2gAwIBAgIEWXLa2zANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJV\n" + + "czETMBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYD\n" + + "VQQKEwhTb21lLU9yZzAeFw0yNDA3MDEwNDE2NTJaFw0zNDA3MDIwNDE2NTJaMGsx\n" + + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21l\n" + + "LUNpdHkxETAPBgNVBAoTCFNvbWUtT3JnMSAwHgYDVQQDExdsb2NhbGhvc3Qgb3U9\n" + + "U1NMLUNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMy/kjym\n" + + "V3QfWK3HaYhvWTJHUGAi5JhJDj4duLriO7ZxW/1kAm0NUHdybqg9XdS9H3ZR3JrQ\n" + + "1j7QMaUkWiy+d/qIofoGQcgPR3BHJJlQUkRbMGJbZTXEKLBc7tAb6zkrC6Gslkja\n" + + "Vmzg4+bj3UXLUTONQEPX8KQxqrXA30vfKwrtfhAMrh+WohAea9D5N4vfDQ4CNfhY\n" + + "vG61Vw4v6iDmc5rla4JwJbtRmnyd4lA9zx4kPpJVzyqtDYSPqEMkza1QZHTCc7bh\n" + + "khyyK4wte5amQWFcG494KFFA7UGQzh24JoFHa+NXQXROIPBaG5c3kYYZxfJtBMl4\n" + + "K1oWvPwrcVvQAE8CAwEAAaNzMHEwHQYDVR0OBBYEFM1F4gWSiKPHSSjn0ze3E5L7\n" + + "sTbEMAsGA1UdDwQEAwIF4DAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwCQYDVR0T\n" + + "BAIwADAfBgNVHSMEGDAWgBTgA5D2T7tX5n6vXJQls4XaFgpRQDANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEAI27pXYANs4bJzReBM71bqsBlTGuf+u4y6Ynh0McdXEN+lKyDr5GQ\n" + + "TCZhjf5rGqpuYTmzJErcksjK8oCwBUEMs93tt4FCmh5O8oBscmKLvdTNI3186G/j\n" + + "Z4lqeRnd9ldiEvrrzWbD0thAWhzdf5+yNOkq1hRSum6omw2poQO/xA2SPVnkqY4g\n" + + "QTmZgXCd0GiY/F9JSpLlosFRYfYeSVYLtoxX2wgq8KME3KEEolzQkE8TjRzmLnpj\n" + + "nDJAZVkEXXGQWqjbajBCV1sL386hH/ojcfNXEsQcZjs3dzIop/ut7oZRTIAv3chb\n" + + "n6cVB/orWu6TAF+mQyIbQFIVZgGEMp5xIQ==\n" + "-----END CERTIFICATE-----"; static byte serverPrivateExponent[] = { - (byte)0x6e, (byte)0xa7, (byte)0x1b, (byte)0x83, - (byte)0x51, (byte)0x35, (byte)0x9a, (byte)0x44, - (byte)0x7d, (byte)0xf6, (byte)0xe3, (byte)0x89, - (byte)0xa0, (byte)0xd7, (byte)0x90, (byte)0x60, - (byte)0xa1, (byte)0x4e, (byte)0x27, (byte)0x21, - (byte)0xa2, (byte)0x89, (byte)0x74, (byte)0xcc, - (byte)0x9d, (byte)0x75, (byte)0x75, (byte)0x4e, - (byte)0xc7, (byte)0x82, (byte)0xe3, (byte)0xe3, - (byte)0xc3, (byte)0x7d, (byte)0x00, (byte)0x54, - (byte)0xec, (byte)0x36, (byte)0xb1, (byte)0xdf, - (byte)0x91, (byte)0x9c, (byte)0x7a, (byte)0xc0, - (byte)0x62, (byte)0x0a, (byte)0xd6, (byte)0xa9, - (byte)0x22, (byte)0x91, (byte)0x4a, (byte)0x29, - (byte)0x2e, (byte)0x43, (byte)0xfa, (byte)0x8c, - (byte)0xd8, (byte)0xe9, (byte)0xbe, (byte)0xd9, - (byte)0x4f, (byte)0xca, (byte)0x23, (byte)0xc6, - (byte)0xe4, (byte)0x3f, (byte)0xb8, (byte)0x72, - (byte)0xcf, (byte)0x02, (byte)0xfc, (byte)0xf4, - (byte)0x58, (byte)0x34, (byte)0x77, (byte)0x76, - (byte)0xce, (byte)0x22, (byte)0x44, (byte)0x5f, - (byte)0x2d, (byte)0xca, (byte)0xee, (byte)0xf5, - (byte)0x43, (byte)0x56, (byte)0x47, (byte)0x71, - (byte)0x0b, (byte)0x09, (byte)0x6b, (byte)0x5e, - (byte)0xf2, (byte)0xc8, (byte)0xee, (byte)0xd4, - (byte)0x6e, (byte)0x44, (byte)0x92, (byte)0x2a, - (byte)0x7f, (byte)0xcc, (byte)0xa7, (byte)0xd4, - (byte)0x5b, (byte)0xfb, (byte)0xf7, (byte)0x4a, - (byte)0xa9, (byte)0xfb, (byte)0x54, (byte)0x18, - (byte)0xd5, (byte)0xd5, (byte)0x14, (byte)0xba, - (byte)0xa0, (byte)0x1c, (byte)0x13, (byte)0xb3, - (byte)0x37, (byte)0x6b, (byte)0x37, (byte)0x59, - (byte)0xed, (byte)0xdb, (byte)0x6d, (byte)0xb1 + (byte)0x68, (byte)0x87, (byte)0x36, (byte)0x54, + (byte)0xa3, (byte)0xc6, (byte)0xd5, (byte)0x5f, + (byte)0xf5, (byte)0x0f, (byte)0x4f, (byte)0x76, + (byte)0xc8, (byte)0x9c, (byte)0x2b, (byte)0x5b, + (byte)0xdc, (byte)0xe2, (byte)0xbe, (byte)0x14, + (byte)0x12, (byte)0x2f, (byte)0xc7, (byte)0x0a, + (byte)0xa9, (byte)0xcb, (byte)0x5e, (byte)0x04, + (byte)0x59, (byte)0xca, (byte)0x35, (byte)0x2f, + (byte)0x8d, (byte)0x2b, (byte)0xc4, (byte)0x40, + (byte)0xe6, (byte)0x7d, (byte)0x25, (byte)0x1b, + (byte)0x4d, (byte)0x07, (byte)0xc3, (byte)0x99, + (byte)0x9c, (byte)0x16, (byte)0x4f, (byte)0xa5, + (byte)0xdc, (byte)0xde, (byte)0xb0, (byte)0x90, + (byte)0xf0, (byte)0xde, (byte)0x22, (byte)0x70, + (byte)0x80, (byte)0xf4, (byte)0xa6, (byte)0x70, + (byte)0xe2, (byte)0x96, (byte)0x3d, (byte)0x18, + (byte)0x21, (byte)0xbf, (byte)0x2b, (byte)0x27, + (byte)0xa4, (byte)0x2d, (byte)0xd7, (byte)0xae, + (byte)0x2b, (byte)0x12, (byte)0x2f, (byte)0x08, + (byte)0x36, (byte)0xee, (byte)0x99, (byte)0x94, + (byte)0xed, (byte)0xf6, (byte)0xa7, (byte)0xd9, + (byte)0x1d, (byte)0xa2, (byte)0xf3, (byte)0x1f, + (byte)0x44, (byte)0xa4, (byte)0x28, (byte)0x4b, + (byte)0x67, (byte)0x35, (byte)0xd6, (byte)0xa8, + (byte)0x1b, (byte)0xf8, (byte)0x84, (byte)0x34, + (byte)0x34, (byte)0x84, (byte)0xbd, (byte)0xec, + (byte)0x9e, (byte)0x03, (byte)0x08, (byte)0x3c, + (byte)0x93, (byte)0x20, (byte)0x8e, (byte)0xaf, + (byte)0x15, (byte)0xcb, (byte)0x1f, (byte)0x20, + (byte)0x08, (byte)0x97, (byte)0xc4, (byte)0x19, + (byte)0x3e, (byte)0xfa, (byte)0x36, (byte)0xc6, + (byte)0xab, (byte)0x0e, (byte)0x2f, (byte)0xe7, + (byte)0xb3, (byte)0xc0, (byte)0xa7, (byte)0xbc, + (byte)0xe4, (byte)0xe0, (byte)0xa6, (byte)0x08, + (byte)0x1c, (byte)0x69, (byte)0x20, (byte)0x4d, + (byte)0x78, (byte)0xbd, (byte)0x7a, (byte)0xe5, + (byte)0x25, (byte)0x48, (byte)0x60, (byte)0x9e, + (byte)0x2e, (byte)0x50, (byte)0x8d, (byte)0x36, + (byte)0x1e, (byte)0x07, (byte)0xe9, (byte)0xd5, + (byte)0x0d, (byte)0x39, (byte)0x67, (byte)0x41, + (byte)0x42, (byte)0x24, (byte)0xdb, (byte)0x87, + (byte)0xe5, (byte)0x77, (byte)0x76, (byte)0xfd, + (byte)0x5e, (byte)0xd5, (byte)0xc6, (byte)0xe5, + (byte)0xd3, (byte)0xb0, (byte)0x98, (byte)0x71, + (byte)0x48, (byte)0x69, (byte)0x47, (byte)0x4f, + (byte)0x46, (byte)0x05, (byte)0x0c, (byte)0x9e, + (byte)0x58, (byte)0x45, (byte)0x2e, (byte)0xe2, + (byte)0x27, (byte)0xd0, (byte)0xf6, (byte)0x11, + (byte)0x05, (byte)0x78, (byte)0xad, (byte)0x83, + (byte)0x5a, (byte)0x5b, (byte)0xec, (byte)0xd7, + (byte)0x2e, (byte)0x26, (byte)0x5a, (byte)0xa5, + (byte)0x4f, (byte)0x9e, (byte)0x52, (byte)0x84, + (byte)0x2c, (byte)0x1f, (byte)0x59, (byte)0x1a, + (byte)0x78, (byte)0x56, (byte)0x0a, (byte)0x44, + (byte)0x54, (byte)0xc6, (byte)0x37, (byte)0x64, + (byte)0x01, (byte)0xca, (byte)0xe4, (byte)0xa8, + (byte)0x01, (byte)0xc7, (byte)0x86, (byte)0xc1, + (byte)0xb4, (byte)0xd6, (byte)0x6c, (byte)0x7a, + (byte)0x15, (byte)0x9a, (byte)0x65, (byte)0x69, + (byte)0x46, (byte)0x9e, (byte)0xfd, (byte)0xf6, + (byte)0x08, (byte)0x17, (byte)0x0c, (byte)0x6c, + (byte)0xac, (byte)0x38, (byte)0xbd, (byte)0xc2, + (byte)0xcd, (byte)0xda, (byte)0xef, (byte)0x54, + (byte)0x7a, (byte)0x48, (byte)0x92, (byte)0x4d }; static byte serverModulus[] = { - (byte)0x00, - (byte)0xa5, (byte)0xac, (byte)0x5b, (byte)0x1c, - (byte)0x37, (byte)0xa2, (byte)0xdd, (byte)0x99, - (byte)0x89, (byte)0x2d, (byte)0xb2, (byte)0x79, - (byte)0xb8, (byte)0x8f, (byte)0xd5, (byte)0x48, - (byte)0xa5, (byte)0xe7, (byte)0x1c, (byte)0x84, - (byte)0x17, (byte)0x8d, (byte)0x69, (byte)0x9c, - (byte)0xc6, (byte)0xac, (byte)0x6d, (byte)0xf9, - (byte)0xf2, (byte)0x1d, (byte)0x1f, (byte)0x39, - (byte)0x19, (byte)0xda, (byte)0xd3, (byte)0x72, - (byte)0x1e, (byte)0x6e, (byte)0xec, (byte)0x44, - (byte)0xcc, (byte)0x70, (byte)0xa4, (byte)0xdc, - (byte)0xba, (byte)0x00, (byte)0x30, (byte)0xf6, - (byte)0xa0, (byte)0x4f, (byte)0x3d, (byte)0x54, - (byte)0x7a, (byte)0x61, (byte)0x6a, (byte)0xcc, - (byte)0x57, (byte)0xd0, (byte)0x0a, (byte)0x7f, - (byte)0x95, (byte)0x28, (byte)0x18, (byte)0x3f, - (byte)0x9a, (byte)0xd9, (byte)0x94, (byte)0xf2, - (byte)0x1b, (byte)0xc8, (byte)0x24, (byte)0x88, - (byte)0x7e, (byte)0xfe, (byte)0x9d, (byte)0x0f, - (byte)0x3d, (byte)0xfb, (byte)0x57, (byte)0x53, - (byte)0x08, (byte)0xb3, (byte)0x20, (byte)0x33, - (byte)0xd4, (byte)0x3f, (byte)0x17, (byte)0x47, - (byte)0x14, (byte)0xd1, (byte)0xcd, (byte)0xea, - (byte)0x08, (byte)0xd8, (byte)0x0e, (byte)0x75, - (byte)0x4e, (byte)0xaf, (byte)0xbe, (byte)0xcc, - (byte)0xd2, (byte)0xec, (byte)0xaf, (byte)0xa9, - (byte)0x7a, (byte)0x49, (byte)0xdf, (byte)0xc2, - (byte)0xd9, (byte)0xac, (byte)0xb8, (byte)0x24, - (byte)0x40, (byte)0x90, (byte)0xa6, (byte)0x03, - (byte)0x56, (byte)0x2a, (byte)0xd0, (byte)0x30, - (byte)0x05, (byte)0x40, (byte)0x2c, (byte)0x4f, - (byte)0xab, (byte)0xd9, (byte)0x74, (byte)0x89 + (byte)0x00, (byte)0x9a, (byte)0x0c, (byte)0xe0, + (byte)0x8f, (byte)0xa8, (byte)0x02, (byte)0x7e, + (byte)0x5a, (byte)0xef, (byte)0xed, (byte)0xb2, + (byte)0x42, (byte)0xad, (byte)0x08, (byte)0x4e, + (byte)0x91, (byte)0xba, (byte)0xc2, (byte)0xad, + (byte)0x9b, (byte)0x79, (byte)0xd7, (byte)0x9b, + (byte)0x0f, (byte)0xfd, (byte)0xd2, (byte)0xf8, + (byte)0x15, (byte)0x2f, (byte)0x19, (byte)0x89, + (byte)0x80, (byte)0x10, (byte)0x00, (byte)0x02, + (byte)0x19, (byte)0x6d, (byte)0x27, (byte)0xc2, + (byte)0x90, (byte)0xd7, (byte)0xa5, (byte)0x23, + (byte)0x53, (byte)0x74, (byte)0x6e, (byte)0x64, + (byte)0x28, (byte)0x7c, (byte)0x24, (byte)0xaa, + (byte)0xed, (byte)0xea, (byte)0x21, (byte)0x59, + (byte)0xdc, (byte)0xa3, (byte)0x5c, (byte)0xb5, + (byte)0xc9, (byte)0x42, (byte)0x31, (byte)0x4f, + (byte)0xa2, (byte)0xde, (byte)0xfb, (byte)0x09, + (byte)0x7c, (byte)0x73, (byte)0xed, (byte)0x88, + (byte)0x04, (byte)0x34, (byte)0xf1, (byte)0x15, + (byte)0xad, (byte)0x3d, (byte)0x60, (byte)0xcd, + (byte)0xca, (byte)0xc5, (byte)0x13, (byte)0x99, + (byte)0xd3, (byte)0x9f, (byte)0x9b, (byte)0xb2, + (byte)0x92, (byte)0x70, (byte)0xcb, (byte)0xba, + (byte)0x4b, (byte)0x3d, (byte)0x20, (byte)0x96, + (byte)0xad, (byte)0xbe, (byte)0x92, (byte)0x53, + (byte)0xed, (byte)0x54, (byte)0x3b, (byte)0xc5, + (byte)0x14, (byte)0xbd, (byte)0xcf, (byte)0xd4, + (byte)0x0f, (byte)0xcb, (byte)0x05, (byte)0x4f, + (byte)0xfd, (byte)0x2b, (byte)0x9e, (byte)0xe0, + (byte)0x50, (byte)0xbb, (byte)0x65, (byte)0x13, + (byte)0x92, (byte)0xc0, (byte)0xd6, (byte)0xbd, + (byte)0x4d, (byte)0x02, (byte)0x0c, (byte)0x70, + (byte)0xb6, (byte)0x65, (byte)0xd4, (byte)0x7d, + (byte)0xb4, (byte)0x4d, (byte)0xc3, (byte)0xdf, + (byte)0x2c, (byte)0x08, (byte)0x9e, (byte)0xd2, + (byte)0x3e, (byte)0x69, (byte)0x32, (byte)0x46, + (byte)0x6f, (byte)0x6f, (byte)0xca, (byte)0xd1, + (byte)0x73, (byte)0xa4, (byte)0x94, (byte)0x07, + (byte)0xef, (byte)0x14, (byte)0xe3, (byte)0xda, + (byte)0x9e, (byte)0x2f, (byte)0xc0, (byte)0xac, + (byte)0x0e, (byte)0x10, (byte)0x33, (byte)0x4c, + (byte)0x68, (byte)0x79, (byte)0xf3, (byte)0x79, + (byte)0x40, (byte)0xd6, (byte)0xe9, (byte)0x3c, + (byte)0xc2, (byte)0xe6, (byte)0x70, (byte)0xe0, + (byte)0x89, (byte)0xce, (byte)0xa0, (byte)0x7a, + (byte)0xa8, (byte)0x84, (byte)0x28, (byte)0x85, + (byte)0x32, (byte)0x37, (byte)0x08, (byte)0xb0, + (byte)0xcf, (byte)0xb1, (byte)0x7f, (byte)0x5f, + (byte)0xbc, (byte)0x1f, (byte)0xa5, (byte)0x3d, + (byte)0xef, (byte)0xd6, (byte)0x68, (byte)0xa8, + (byte)0x17, (byte)0x21, (byte)0x5f, (byte)0x87, + (byte)0xd5, (byte)0x4b, (byte)0xb5, (byte)0xcc, + (byte)0xee, (byte)0x78, (byte)0x8d, (byte)0xdd, + (byte)0xb1, (byte)0x28, (byte)0x6a, (byte)0xc0, + (byte)0xfb, (byte)0x64, (byte)0xbd, (byte)0xb7, + (byte)0x70, (byte)0x02, (byte)0x33, (byte)0x03, + (byte)0x0b, (byte)0xb8, (byte)0xb8, (byte)0xbb, + (byte)0x08, (byte)0x82, (byte)0xf6, (byte)0x8e, + (byte)0x05, (byte)0x27, (byte)0xd1, (byte)0x3b, + (byte)0xe6, (byte)0xc5, (byte)0xac, (byte)0x4d, + (byte)0x85, (byte)0x5b, (byte)0xa1, (byte)0x1d, + (byte)0xa3, (byte)0x48, (byte)0x5d, (byte)0x03, + (byte)0x15, (byte)0x76, (byte)0x63, (byte)0x6c, + (byte)0x71, (byte)0x21, (byte)0x3e, (byte)0x98, + (byte)0xcd }; static byte clientPrivateExponent[] = { - (byte)0x11, (byte)0xb7, (byte)0x6a, (byte)0x36, - (byte)0x3d, (byte)0x30, (byte)0x37, (byte)0xce, - (byte)0x61, (byte)0x9d, (byte)0x6c, (byte)0x84, - (byte)0x8b, (byte)0xf3, (byte)0x9b, (byte)0x25, - (byte)0x4f, (byte)0x14, (byte)0xc8, (byte)0xa4, - (byte)0xdd, (byte)0x2f, (byte)0xd7, (byte)0x9a, - (byte)0x17, (byte)0xbd, (byte)0x90, (byte)0x19, - (byte)0xf7, (byte)0x05, (byte)0xfd, (byte)0xf2, - (byte)0xd2, (byte)0xc5, (byte)0xf7, (byte)0x77, - (byte)0xbe, (byte)0xea, (byte)0xe2, (byte)0x84, - (byte)0x87, (byte)0x97, (byte)0x3a, (byte)0x41, - (byte)0x96, (byte)0xb6, (byte)0x99, (byte)0xf8, - (byte)0x94, (byte)0x8c, (byte)0x58, (byte)0x71, - (byte)0x51, (byte)0x8c, (byte)0xf4, (byte)0x2a, - (byte)0x20, (byte)0x9e, (byte)0x1a, (byte)0xa0, - (byte)0x26, (byte)0x99, (byte)0x75, (byte)0xd6, - (byte)0x31, (byte)0x53, (byte)0x43, (byte)0x39, - (byte)0xf5, (byte)0x2a, (byte)0xa6, (byte)0x7e, - (byte)0x34, (byte)0x42, (byte)0x51, (byte)0x2a, - (byte)0x40, (byte)0x87, (byte)0x03, (byte)0x88, - (byte)0x43, (byte)0x69, (byte)0xb2, (byte)0x89, - (byte)0x6d, (byte)0x20, (byte)0xbd, (byte)0x7d, - (byte)0x71, (byte)0xef, (byte)0x47, (byte)0x0a, - (byte)0xdf, (byte)0x06, (byte)0xc1, (byte)0x69, - (byte)0x66, (byte)0xa8, (byte)0x22, (byte)0x37, - (byte)0x1a, (byte)0x77, (byte)0x1e, (byte)0xc7, - (byte)0x94, (byte)0x4e, (byte)0x2c, (byte)0x27, - (byte)0x69, (byte)0x45, (byte)0x5e, (byte)0xc8, - (byte)0xf8, (byte)0x0c, (byte)0xb7, (byte)0xf8, - (byte)0xc0, (byte)0x8f, (byte)0x99, (byte)0xc1, - (byte)0xe5, (byte)0x28, (byte)0x9b, (byte)0xf9, - (byte)0x4c, (byte)0x94, (byte)0xc6, (byte)0xb1 + (byte)0x62, (byte)0xb2, (byte)0xd6, (byte)0x63, + (byte)0xb6, (byte)0x2b, (byte)0xe2, (byte)0x26, + (byte)0x5a, (byte)0x31, (byte)0x2b, (byte)0x37, + (byte)0x8c, (byte)0x35, (byte)0x60, (byte)0xe2, + (byte)0x03, (byte)0xce, (byte)0x93, (byte)0x09, + (byte)0x3e, (byte)0xf8, (byte)0xc9, (byte)0xfe, + (byte)0xbb, (byte)0xa2, (byte)0xc8, (byte)0x32, + (byte)0x0e, (byte)0x6c, (byte)0x8a, (byte)0x7e, + (byte)0x0a, (byte)0xc2, (byte)0x13, (byte)0x3b, + (byte)0xb8, (byte)0x25, (byte)0xfa, (byte)0xec, + (byte)0x19, (byte)0x95, (byte)0x8e, (byte)0x34, + (byte)0x46, (byte)0xcf, (byte)0x0e, (byte)0x7b, + (byte)0xe4, (byte)0x25, (byte)0x82, (byte)0x1a, + (byte)0x7f, (byte)0x21, (byte)0x48, (byte)0x16, + (byte)0x44, (byte)0x58, (byte)0x3f, (byte)0x35, + (byte)0xd8, (byte)0xeb, (byte)0xd8, (byte)0x1a, + (byte)0x45, (byte)0x53, (byte)0x0f, (byte)0x9b, + (byte)0x84, (byte)0x8a, (byte)0x54, (byte)0x13, + (byte)0x33, (byte)0xe4, (byte)0x97, (byte)0x97, + (byte)0xf0, (byte)0x48, (byte)0x37, (byte)0xfb, + (byte)0x5d, (byte)0x4f, (byte)0x8c, (byte)0x8f, + (byte)0x35, (byte)0x63, (byte)0xe1, (byte)0xd9, + (byte)0x62, (byte)0x73, (byte)0x1c, (byte)0x8e, + (byte)0xd8, (byte)0xcd, (byte)0x2e, (byte)0x1a, + (byte)0xe5, (byte)0x4c, (byte)0xb5, (byte)0x05, + (byte)0x59, (byte)0x7a, (byte)0xdf, (byte)0xf1, + (byte)0x68, (byte)0xeb, (byte)0x1c, (byte)0x5c, + (byte)0xc6, (byte)0x10, (byte)0x44, (byte)0x8c, + (byte)0x7d, (byte)0x42, (byte)0xc5, (byte)0x71, + (byte)0x8a, (byte)0xe7, (byte)0x1b, (byte)0xaa, + (byte)0x17, (byte)0x03, (byte)0x6a, (byte)0xa0, + (byte)0xc0, (byte)0x6b, (byte)0x97, (byte)0x50, + (byte)0x17, (byte)0xad, (byte)0x6e, (byte)0x5e, + (byte)0xd9, (byte)0xdb, (byte)0x6f, (byte)0x3e, + (byte)0xe9, (byte)0x3f, (byte)0x35, (byte)0xc3, + (byte)0x45, (byte)0xbc, (byte)0xe8, (byte)0x3d, + (byte)0x5a, (byte)0xb4, (byte)0xb9, (byte)0x3f, + (byte)0x53, (byte)0x80, (byte)0x64, (byte)0xdc, + (byte)0x12, (byte)0x24, (byte)0x35, (byte)0x35, + (byte)0xbd, (byte)0x98, (byte)0xbb, (byte)0x8d, + (byte)0xfa, (byte)0x19, (byte)0xa3, (byte)0x5e, + (byte)0x9e, (byte)0xac, (byte)0x70, (byte)0x4a, + (byte)0xfc, (byte)0x8d, (byte)0xae, (byte)0x55, + (byte)0x8b, (byte)0x71, (byte)0x81, (byte)0x0e, + (byte)0x4d, (byte)0xc8, (byte)0x2f, (byte)0x87, + (byte)0xb0, (byte)0x44, (byte)0xf7, (byte)0x4f, + (byte)0xdc, (byte)0xa8, (byte)0xc8, (byte)0x50, + (byte)0xb5, (byte)0x95, (byte)0x24, (byte)0x63, + (byte)0x74, (byte)0x13, (byte)0x54, (byte)0x58, + (byte)0xde, (byte)0xfc, (byte)0xe0, (byte)0x75, + (byte)0xeb, (byte)0xf4, (byte)0x06, (byte)0x58, + (byte)0x83, (byte)0x12, (byte)0x4c, (byte)0x56, + (byte)0xc4, (byte)0xc4, (byte)0x18, (byte)0x0c, + (byte)0xea, (byte)0xa3, (byte)0xe7, (byte)0x25, + (byte)0xa3, (byte)0xde, (byte)0x19, (byte)0x23, + (byte)0xa2, (byte)0x5a, (byte)0x2a, (byte)0xb6, + (byte)0x56, (byte)0x04, (byte)0xbc, (byte)0x65, + (byte)0xba, (byte)0x7c, (byte)0x0a, (byte)0xf4, + (byte)0x91, (byte)0x10, (byte)0x22, (byte)0x88, + (byte)0x3f, (byte)0x9d, (byte)0xbe, (byte)0x58, + (byte)0x43, (byte)0x4c, (byte)0x2e, (byte)0xad, + (byte)0xdb, (byte)0xd6, (byte)0x32, (byte)0xcf, + (byte)0x8e, (byte)0xb5, (byte)0x05, (byte)0x55, + (byte)0x39, (byte)0x8b, (byte)0xe1, (byte)0x01 }; static byte clientModulus[] = { - (byte)0x00, - (byte)0xbb, (byte)0xf0, (byte)0x40, (byte)0x36, - (byte)0xac, (byte)0x26, (byte)0x54, (byte)0x4e, - (byte)0xf4, (byte)0xa3, (byte)0x5a, (byte)0x00, - (byte)0x2f, (byte)0x69, (byte)0x21, (byte)0x6f, - (byte)0xb9, (byte)0x7a, (byte)0x3a, (byte)0x93, - (byte)0xec, (byte)0xa2, (byte)0xf6, (byte)0xe1, - (byte)0x8e, (byte)0xc7, (byte)0x63, (byte)0xd8, - (byte)0x2f, (byte)0x12, (byte)0x30, (byte)0x99, - (byte)0x2e, (byte)0xb0, (byte)0xf2, (byte)0x8f, - (byte)0xf8, (byte)0x27, (byte)0x2d, (byte)0x24, - (byte)0x78, (byte)0x28, (byte)0x84, (byte)0xf7, - (byte)0x01, (byte)0xbf, (byte)0x8d, (byte)0x44, - (byte)0x79, (byte)0xdd, (byte)0x3b, (byte)0xd2, - (byte)0x55, (byte)0xf3, (byte)0xce, (byte)0x3c, - (byte)0xb2, (byte)0x5b, (byte)0x21, (byte)0x7d, - (byte)0xef, (byte)0xfd, (byte)0x33, (byte)0x4a, - (byte)0xb1, (byte)0xa3, (byte)0xff, (byte)0xc6, - (byte)0xc8, (byte)0x9b, (byte)0xb9, (byte)0x0f, - (byte)0x7c, (byte)0x41, (byte)0x35, (byte)0x97, - (byte)0xf9, (byte)0xdb, (byte)0x3a, (byte)0x05, - (byte)0x60, (byte)0x05, (byte)0x15, (byte)0xaf, - (byte)0x59, (byte)0x17, (byte)0x92, (byte)0xa3, - (byte)0x10, (byte)0xad, (byte)0x16, (byte)0x1c, - (byte)0xe4, (byte)0x07, (byte)0x53, (byte)0xaf, - (byte)0xa8, (byte)0x76, (byte)0xa2, (byte)0x56, - (byte)0x2a, (byte)0x92, (byte)0xd3, (byte)0xf9, - (byte)0x28, (byte)0xe0, (byte)0x78, (byte)0xcf, - (byte)0x5e, (byte)0x1f, (byte)0x48, (byte)0xab, - (byte)0x5c, (byte)0x19, (byte)0xdd, (byte)0xe1, - (byte)0x67, (byte)0x43, (byte)0xba, (byte)0x75, - (byte)0x8d, (byte)0xf5, (byte)0x82, (byte)0xac, - (byte)0x43, (byte)0x92, (byte)0x44, (byte)0x1b + (byte)0x00, (byte)0xcc, (byte)0xbf, (byte)0x92, + (byte)0x3c, (byte)0xa6, (byte)0x57, (byte)0x74, + (byte)0x1f, (byte)0x58, (byte)0xad, (byte)0xc7, + (byte)0x69, (byte)0x88, (byte)0x6f, (byte)0x59, + (byte)0x32, (byte)0x47, (byte)0x50, (byte)0x60, + (byte)0x22, (byte)0xe4, (byte)0x98, (byte)0x49, + (byte)0x0e, (byte)0x3e, (byte)0x1d, (byte)0xb8, + (byte)0xba, (byte)0xe2, (byte)0x3b, (byte)0xb6, + (byte)0x71, (byte)0x5b, (byte)0xfd, (byte)0x64, + (byte)0x02, (byte)0x6d, (byte)0x0d, (byte)0x50, + (byte)0x77, (byte)0x72, (byte)0x6e, (byte)0xa8, + (byte)0x3d, (byte)0x5d, (byte)0xd4, (byte)0xbd, + (byte)0x1f, (byte)0x76, (byte)0x51, (byte)0xdc, + (byte)0x9a, (byte)0xd0, (byte)0xd6, (byte)0x3e, + (byte)0xd0, (byte)0x31, (byte)0xa5, (byte)0x24, + (byte)0x5a, (byte)0x2c, (byte)0xbe, (byte)0x77, + (byte)0xfa, (byte)0x88, (byte)0xa1, (byte)0xfa, + (byte)0x06, (byte)0x41, (byte)0xc8, (byte)0x0f, + (byte)0x47, (byte)0x70, (byte)0x47, (byte)0x24, + (byte)0x99, (byte)0x50, (byte)0x52, (byte)0x44, + (byte)0x5b, (byte)0x30, (byte)0x62, (byte)0x5b, + (byte)0x65, (byte)0x35, (byte)0xc4, (byte)0x28, + (byte)0xb0, (byte)0x5c, (byte)0xee, (byte)0xd0, + (byte)0x1b, (byte)0xeb, (byte)0x39, (byte)0x2b, + (byte)0x0b, (byte)0xa1, (byte)0xac, (byte)0x96, + (byte)0x48, (byte)0xda, (byte)0x56, (byte)0x6c, + (byte)0xe0, (byte)0xe3, (byte)0xe6, (byte)0xe3, + (byte)0xdd, (byte)0x45, (byte)0xcb, (byte)0x51, + (byte)0x33, (byte)0x8d, (byte)0x40, (byte)0x43, + (byte)0xd7, (byte)0xf0, (byte)0xa4, (byte)0x31, + (byte)0xaa, (byte)0xb5, (byte)0xc0, (byte)0xdf, + (byte)0x4b, (byte)0xdf, (byte)0x2b, (byte)0x0a, + (byte)0xed, (byte)0x7e, (byte)0x10, (byte)0x0c, + (byte)0xae, (byte)0x1f, (byte)0x96, (byte)0xa2, + (byte)0x10, (byte)0x1e, (byte)0x6b, (byte)0xd0, + (byte)0xf9, (byte)0x37, (byte)0x8b, (byte)0xdf, + (byte)0x0d, (byte)0x0e, (byte)0x02, (byte)0x35, + (byte)0xf8, (byte)0x58, (byte)0xbc, (byte)0x6e, + (byte)0xb5, (byte)0x57, (byte)0x0e, (byte)0x2f, + (byte)0xea, (byte)0x20, (byte)0xe6, (byte)0x73, + (byte)0x9a, (byte)0xe5, (byte)0x6b, (byte)0x82, + (byte)0x70, (byte)0x25, (byte)0xbb, (byte)0x51, + (byte)0x9a, (byte)0x7c, (byte)0x9d, (byte)0xe2, + (byte)0x50, (byte)0x3d, (byte)0xcf, (byte)0x1e, + (byte)0x24, (byte)0x3e, (byte)0x92, (byte)0x55, + (byte)0xcf, (byte)0x2a, (byte)0xad, (byte)0x0d, + (byte)0x84, (byte)0x8f, (byte)0xa8, (byte)0x43, + (byte)0x24, (byte)0xcd, (byte)0xad, (byte)0x50, + (byte)0x64, (byte)0x74, (byte)0xc2, (byte)0x73, + (byte)0xb6, (byte)0xe1, (byte)0x92, (byte)0x1c, + (byte)0xb2, (byte)0x2b, (byte)0x8c, (byte)0x2d, + (byte)0x7b, (byte)0x96, (byte)0xa6, (byte)0x41, + (byte)0x61, (byte)0x5c, (byte)0x1b, (byte)0x8f, + (byte)0x78, (byte)0x28, (byte)0x51, (byte)0x40, + (byte)0xed, (byte)0x41, (byte)0x90, (byte)0xce, + (byte)0x1d, (byte)0xb8, (byte)0x26, (byte)0x81, + (byte)0x47, (byte)0x6b, (byte)0xe3, (byte)0x57, + (byte)0x41, (byte)0x74, (byte)0x4e, (byte)0x20, + (byte)0xf0, (byte)0x5a, (byte)0x1b, (byte)0x97, + (byte)0x37, (byte)0x91, (byte)0x86, (byte)0x19, + (byte)0xc5, (byte)0xf2, (byte)0x6d, (byte)0x04, + (byte)0xc9, (byte)0x78, (byte)0x2b, (byte)0x5a, + (byte)0x16, (byte)0xbc, (byte)0xfc, (byte)0x2b, + (byte)0x71, (byte)0x5b, (byte)0xd0, (byte)0x00, + (byte)0x4f }; static char passphrase[] = "passphrase".toCharArray(); @@ -795,11 +1076,11 @@ private static SSLContext getSSLContext(String trusedCertStr, volatile Exception clientException = null; public static void main(String args[]) throws Exception { - // MD5 is used in this test case, don't disable MD5 algorithm. + // SHA1 is used in this test case, don't disable SHA1 algorithm. Security.setProperty("jdk.certpath.disabledAlgorithms", - "MD2, RSA keySize < 1024"); + "MD2, MD5, RSA keySize < 1024"); Security.setProperty("jdk.tls.disabledAlgorithms", - "SSLv3, RC4, DH keySize < 768"); + "SSLv3, RC4, MD5withRSA, DH keySize < 768"); if (debug) System.setProperty("javax.net.debug", "all"); diff --git a/test/jdk/sun/security/tools/jarsigner/PreserveRawManifestEntryAndDigest.java b/test/jdk/sun/security/tools/jarsigner/PreserveRawManifestEntryAndDigest.java index 1217788eef079..5d946945c15f4 100644 --- a/test/jdk/sun/security/tools/jarsigner/PreserveRawManifestEntryAndDigest.java +++ b/test/jdk/sun/security/tools/jarsigner/PreserveRawManifestEntryAndDigest.java @@ -243,9 +243,8 @@ String[] fromFirstToSecondEmptyLine(String[] lines) { * @see "concise_jarsigner.sh" */ String[] getExpectedJarSignerOutputUpdatedContentNotValidatedBySignerA( - String jarFilename, String digestalg, String firstAddedFilename, String secondAddedFilename) { - final String TS = ".{28,29}"; // matches a timestamp + final String TS = ".{28,34}"; // matches a timestamp List expLines = new ArrayList<>(); expLines.add("s k *\\d+ " + TS + " META-INF/MANIFEST[.]MF"); expLines.add(" *\\d+ " + TS + " META-INF/B[.]SF"); @@ -347,7 +346,6 @@ String test(String name, assertMatchByLines( fromFirstToSecondEmptyLine(o.getStdout().split("\\R")), getExpectedJarSignerOutputUpdatedContentNotValidatedBySignerA( - jarFilename4, digestalg, firstAddedFilename, secondAddedFilename)); // double-check reading the files with a verifying JarFile diff --git a/test/jdk/sun/security/tools/jarsigner/RemovedFiles.java b/test/jdk/sun/security/tools/jarsigner/RemovedFiles.java new file mode 100644 index 0000000000000..598e25a9a709b --- /dev/null +++ b/test/jdk/sun/security/tools/jarsigner/RemovedFiles.java @@ -0,0 +1,94 @@ +/* + * 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 8309841 + * @summary Jarsigner should print a warning if an entry is removed + * @library /test/lib + */ + +import jdk.test.lib.SecurityTools; +import jdk.test.lib.util.JarUtils; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +public class RemovedFiles { + + private static final String NONEXISTENT_ENTRIES_FOUND + = "This jar contains signed entries for files that do not exist. See the -verbose output for more details."; + + public static void main(String[] args) throws Exception { + JarUtils.createJarFile( + Path.of("a.jar"), + Path.of("."), + Files.writeString(Path.of("a"), "a"), + Files.writeString(Path.of("b"), "b")); + SecurityTools.keytool("-genkeypair -storepass changeit -keystore ks -alias x -dname CN=x -keyalg ed25519"); + SecurityTools.jarsigner("-storepass changeit -keystore ks a.jar x"); + + // All is fine at the beginning. + SecurityTools.jarsigner("-verify a.jar") + .shouldNotContain(NONEXISTENT_ENTRIES_FOUND); + + // Remove an entry after signing. There will be a warning. + JarUtils.deleteEntries(Path.of("a.jar"), "a"); + SecurityTools.jarsigner("-verify a.jar") + .shouldContain(NONEXISTENT_ENTRIES_FOUND); + SecurityTools.jarsigner("-verify -verbose a.jar") + .shouldContain(NONEXISTENT_ENTRIES_FOUND) + .shouldContain("Warning: nonexistent signed entries: [a]"); + + // Remove one more entry. + JarUtils.deleteEntries(Path.of("a.jar"), "b"); + SecurityTools.jarsigner("-verify a.jar") + .shouldContain(NONEXISTENT_ENTRIES_FOUND); + SecurityTools.jarsigner("-verify -verbose a.jar") + .shouldContain(NONEXISTENT_ENTRIES_FOUND) + .shouldContain("Warning: nonexistent signed entries: [a, b]"); + + // Re-sign will not clear the warning. + SecurityTools.jarsigner("-storepass changeit -keystore ks a.jar x"); + SecurityTools.jarsigner("-verify a.jar") + .shouldContain(NONEXISTENT_ENTRIES_FOUND); + + // Unfortunately, if there is a non-file entry in manifest, there will be + // a false alarm. See https://bugs.openjdk.org/browse/JDK-8334261. + var man = new Manifest(); + man.getMainAttributes().putValue("Manifest-Version", "1.0"); + man.getEntries().computeIfAbsent("Hello", _ -> new Attributes()) + .putValue("Foo", "Bar"); + JarUtils.createJarFile(Path.of("b.jar"), + man, + Path.of("."), + Path.of("a")); + SecurityTools.jarsigner("-storepass changeit -keystore ks b.jar x"); + SecurityTools.jarsigner("-verbose -verify b.jar") + .shouldContain("Warning: nonexistent signed entries: [Hello]") + .shouldContain(NONEXISTENT_ENTRIES_FOUND); + + } +} diff --git a/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java b/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java index 52ca1ead82c5a..84cfcd7cb17de 100644 --- a/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java +++ b/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,7 +84,7 @@ static void testSignerPKCS12() throws Exception { System.out.println("Generating an XDH cert with -signer option"); SecurityTools.keytool("-keystore ks -storepass changeit " + "-genkeypair -keyalg XDH -alias e1 -dname CN=E1 -signer ca") - .shouldContain("Generating 255 bit XDH key pair and a certificate (Ed25519) issued by with a validity of 90 days") + .shouldContain("Generating 255 bit X25519 key pair and a certificate (Ed25519) issued by with a validity of 90 days") .shouldContain("for: CN=E1") .shouldHaveExitValue(0); @@ -118,7 +118,7 @@ static void testSignerPKCS12() throws Exception { .shouldContain("Alias name: e1") .shouldContain("Certificate chain length: 2") .shouldContain("Signature algorithm name: Ed25519") - .shouldContain("Subject Public Key Algorithm: 255-bit XDH key") + .shouldContain("Subject Public Key Algorithm: 255-bit X25519 key") .shouldHaveExitValue(0); // check to make sure that cert's AKID is created from the SKID of the signing cert @@ -150,7 +150,7 @@ static void testSignerPKCS12() throws Exception { System.out.println("Generating an X448 cert with -signer option"); SecurityTools.keytool("-keystore ks -storepass changeit " + "-genkeypair -keyalg X448 -alias e2 -dname CN=E2 -sigalg SHA384withRSA -signer ca2") - .shouldContain("Generating 448 bit XDH key pair and a certificate (SHA384withRSA) issued by with a validity of 90 days") + .shouldContain("Generating 448 bit X448 key pair and a certificate (SHA384withRSA) issued by with a validity of 90 days") .shouldContain("for: CN=E2") .shouldHaveExitValue(0); @@ -177,7 +177,7 @@ static void testSignerPKCS12() throws Exception { "-list -v") .shouldContain("Alias name: e2") .shouldContain("Signature algorithm name: SHA384withRSA") - .shouldContain("Subject Public Key Algorithm: 448-bit XDH key") + .shouldContain("Subject Public Key Algorithm: 448-bit X448 key") .shouldHaveExitValue(0); kt("-genkeypair -keyalg DSA -alias ca3 -dname CN=CA3 -ext bc:c ", @@ -249,7 +249,7 @@ static void testSignerJKS() throws Exception { SecurityTools.keytool("-keystore ksjks -storepass changeit -storetype jks " + "-genkeypair -keyalg XDH -alias e1 -dname CN=E1 " + "-keypass e1keypass -signer ca1 -signerkeypass ca1keypass") - .shouldContain("Generating 255 bit XDH key pair and a certificate (SHA256withDSA) issued by with a validity of 90 days") + .shouldContain("Generating 255 bit X25519 key pair and a certificate (SHA256withDSA) issued by with a validity of 90 days") .shouldContain("for: CN=E1") .shouldContain("The generated certificate #2 of 3 uses a 1024-bit DSA key which is considered a security risk") .shouldContain("The generated certificate #3 of 3 uses a 1024-bit RSA key which is considered a security risk") @@ -285,7 +285,7 @@ static void testSignerJKS() throws Exception { .shouldContain("Alias name: e1") .shouldContain("Certificate chain length: 3") .shouldContain("Signature algorithm name: SHA256withDSA") - .shouldContain("Subject Public Key Algorithm: 255-bit XDH key") + .shouldContain("Subject Public Key Algorithm: 255-bit X25519 key") .shouldHaveExitValue(0); } diff --git a/test/jdk/sun/security/tools/keytool/KeyToolTest.java b/test/jdk/sun/security/tools/keytool/KeyToolTest.java index 7b5f4d5556eee..954951a1a78d8 100644 --- a/test/jdk/sun/security/tools/keytool/KeyToolTest.java +++ b/test/jdk/sun/security/tools/keytool/KeyToolTest.java @@ -68,6 +68,7 @@ import java.util.*; import java.security.cert.X509Certificate; import jdk.test.lib.util.FileUtils; +import jdk.test.lib.security.SecurityUtils; import sun.security.util.ObjectIdentifier; @@ -103,6 +104,8 @@ public class KeyToolTest { "-srcproviderName SunPKCS11-nzz " + "-addprovider SunPKCS11 " + "-providerArg p11-nzz.txt "; + private static final int KEY_LENGTH_DSA = SecurityUtils.getTestKeySize("DSA"); + private static final int KEY_LENGTH_RSA = SecurityUtils.getTestKeySize("RSA"); String p11Arg, srcP11Arg; @@ -192,7 +195,7 @@ void testOK(String input, String cmd) throws Exception { // SunPKCS11-NSS does not support SHA256withDSA yet. if (cmd.contains("p11-nss.txt") && cmd.contains("-genkey") && cmd.contains("DSA")) { - cmd += " -sigalg SHA1withDSA -keysize 1024"; + cmd += " -sigalg SHA256withDSA -keysize " + KEY_LENGTH_DSA; } test(input, cmd); } catch(Exception e) { @@ -955,6 +958,9 @@ void sqeSelfCertTest() throws Exception { // sig not compatible testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + "-keypass changeit -selfcert -sigalg MD5withRSA"); + // sig not compatible + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -selfcert -sigalg SHA256withRSA"); // bad pass testFail("", "-keystore x.jks -storetype JKS -storepass wrong " + "-keypass changeit -selfcert"); @@ -1062,10 +1068,10 @@ void sqeGenkeyTest() throws Exception { "-keypass changeit -genkeypair -keyalg DSA -dname CN=olala -keysize 999 " + "-alias n5"); testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + - "-keypass changeit -genkeypair -keyalg DSA -dname CN=olala -keysize 512 " + + "-keypass changeit -genkeypair -keyalg DSA -dname CN=olala -keysize 2048 " + "-alias n6"); testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + - "-keypass changeit -genkeypair -keyalg DSA -dname CN=olala -keysize 1024 " + + "-keypass changeit -genkeypair -keyalg DSA -dname CN=olala -keysize 3072 " + "-alias n7"); testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + "-keypass changeit -genkeypair -keyalg DSA -dname CN=olala " + @@ -1076,6 +1082,9 @@ void sqeGenkeyTest() throws Exception { testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " + "-sigalg MD5withRSA -alias n10"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " + + "-sigalg SHA256withRSA -alias n10-1"); testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " + "-sigalg SHA1withRSA -alias n11"); @@ -1152,16 +1161,20 @@ void sqeCsrTest() throws Exception { remove("csr1"); // PrivateKeyEntry can do certreq testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + - "-keypass changeit -genkeypair -keyalg DSA -dname CN=olala -keysize 1024"); + "-keypass changeit -genkeypair -keyalg DSA -dname CN=olala -keysize " + + KEY_LENGTH_DSA); testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + "-certreq -file csr1 -alias mykey"); testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + "-certreq -file csr1"); testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + - "-certreq -file csr1 -sigalg SHA1withDSA"); - // unmatched sigalg + "-certreq -file csr1 -sigalg SHA256withDSA"); + // unmatched md5 testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + "-certreq -file csr1 -sigalg MD5withRSA"); + // unmatched sha + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1 -sigalg SHA256withRSA"); // misc test // bad storepass testFail("", "-keystore x.jks -storetype JKS -storepass badstorepass " + @@ -1192,9 +1205,9 @@ void sqeCsrTest() throws Exception { "-certreq -file csr1"); // unmatched sigalg testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + - "-certreq -file csr1 -sigalg SHA1withDSA"); + "-certreq -file csr1 -sigalg SHA256withDSA"); testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + - "-certreq -file csr1 -sigalg MD5withRSA"); + "-certreq -file csr1 -sigalg SHA256withRSA"); // TrustedCertificateEntry cannot do certreq testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + "-exportcert -file x.jks.p1.cert"); @@ -1222,6 +1235,9 @@ void sqePrintcertTest() throws Exception { testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + "-keypass changeit -genkeypair -dname CN=weak -keyalg rsa " + "-keysize 512 -sigalg MD5withRSA -alias myweakkey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=weak -keyalg rsa -keysize " + + KEY_LENGTH_RSA + " -sigalg SHA256withRSA -alias myweakkey-sha"); testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + "-export -file myweakkey.cert -alias myweakkey"); testFail("", "-printcert -file badkeystore"); @@ -1673,31 +1689,32 @@ void i18nTest() throws Exception { remove("x.jks"); testOK("", "-help"); - // 2. keytool -genkey -keyalg DSA -v -keysize 512 Enter "a" for the keystore + // 2. keytool -genkey -keyalg DSA -v -keysize Enter "a" for the keystore // password. Check error (password too short). Enter "password" for // the keystore password. Hit 'return' for "first and last name", // "organizational unit", "City", "State", and "Country Code". // Type "yes" when they ask you if everything is correct. // Type 'return' for new key password. testOK("a\npassword\npassword\nMe\nHere\nNow\nPlace\nPlace\nUS\nyes\n\n", - "-genkey -keyalg DSA -v -keysize 512 -keystore x.jks -storetype JKS"); + "-genkey -keyalg DSA -v -keysize " + KEY_LENGTH_DSA + " -keystore x.jks " + + "-storetype JKS"); // 3. keytool -list -v -storepass password testOK("", "-list -v -storepass password -keystore x.jks -storetype JKS"); // 4. keytool -list -v Type "a" for the keystore password. // Check error (wrong keystore password). testFail("a\n", "-list -v -keystore x.jks -storetype JKS"); assertTrue(ex.indexOf("password was incorrect") != -1); - // 5. keytool - -keyalg DSA -v -keysize 512 Enter "password" as the password. + // 5. keytool - -keyalg DSA -v -keysize Enter "password" as the password. // Check error (alias 'mykey' already exists). - testFail("password\n", "-genkey -keyalg DSA -v -keysize 512" + + testFail("password\n", "-genkey -keyalg DSA -v -keysize " + KEY_LENGTH_DSA + " -keystore x.jks -storetype JKS"); assertTrue(ex.indexOf("alias already exists") != -1); - // 6. keytool -genkey -keyalg DSA -v -keysize 512 -alias mykey2 -storepass password + // 6. keytool -genkey -keyalg DSA -v -keysize -alias mykey2 -storepass password // Hit 'return' for "first and last name", "organizational unit", "City", // "State", and "Country Code". Type "yes" when they ask you if // everything is correct. Type 'return' for new key password. - testOK("\n\n\n\n\n\nyes\n\n", "-genkey -keyalg DSA -v -keysize 512 -alias mykey2" + - " -storepass password -keystore x.jks -storetype JKS"); + testOK("\n\n\n\n\n\nyes\n\n", "-genkey -keyalg DSA -v -keysize " + KEY_LENGTH_DSA + + " -alias mykey2 -storepass password -keystore x.jks -storetype JKS"); // 7. keytool -list -v Type 'password' for the store password. testOK("password\n", "-list -v -keystore x.jks -storetype JKS"); // 8. keytool -keypasswd -v -alias mykey2 -storepass password @@ -1777,7 +1794,7 @@ void i18nPKCS11Test() throws Exception { // 1. sccs edit cert8.db key3.db //Runtime.getRuntime().exec("/usr/bin/sccs edit cert8.db key3.db"); testOK("", p11Arg + ("-storepass test12 -genkey -alias genkey" + - " -dname cn=genkey -keysize 512 -keyalg rsa")); + " -dname cn=genkey -keysize " + KEY_LENGTH_RSA + " -keyalg rsa")); testOK("", p11Arg + "-storepass test12 -list"); testOK("", p11Arg + "-storepass test12 -list -alias genkey"); testOK("", p11Arg + diff --git a/test/jdk/sun/security/x509/AlgorithmId/NonStandardNames.java b/test/jdk/sun/security/x509/AlgorithmId/NonStandardNames.java index a8098561d4e76..f12e571768286 100644 --- a/test/jdk/sun/security/x509/AlgorithmId/NonStandardNames.java +++ b/test/jdk/sun/security/x509/AlgorithmId/NonStandardNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 7180907 8277224 + * @library /test/lib * @summary Jarsigner -verify fails if rsa file used sha-256 with authenticated attributes * @modules java.base/sun.security.pkcs * java.base/sun.security.tools.keytool @@ -36,6 +37,7 @@ import java.security.MessageDigest; import java.security.Signature; import java.security.cert.X509Certificate; +import jdk.test.lib.security.SecurityUtils; import sun.security.pkcs.ContentInfo; import sun.security.pkcs.PKCS7; import sun.security.pkcs.PKCS9Attribute; @@ -52,8 +54,9 @@ public static void main(String[] args) throws Exception { byte[] data = "Hello".getBytes(); X500Name n = new X500Name("cn=Me"); - CertAndKeyGen cakg = new CertAndKeyGen("RSA", "SHA256withRSA"); - cakg.generate(1024); + String kpgAlgorithm = "RSA"; + CertAndKeyGen cakg = new CertAndKeyGen(kpgAlgorithm, "SHA256withRSA"); + cakg.generate(SecurityUtils.getTestKeySize(kpgAlgorithm)); X509Certificate cert = cakg.getSelfCertificate(n, 1000); MessageDigest md = MessageDigest.getInstance("SHA-256"); diff --git a/test/jdk/sun/security/x509/X509CRLImpl/UnexpectedCCE.java b/test/jdk/sun/security/x509/X509CRLImpl/UnexpectedCCE.java new file mode 100644 index 0000000000000..85acf520b431b --- /dev/null +++ b/test/jdk/sun/security/x509/X509CRLImpl/UnexpectedCCE.java @@ -0,0 +1,83 @@ +/* + * 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 8336665 + * @summary Verify that generateCRLs method does not throw ClassCastException. + * It should throw CRLException instead. + * @library /test/lib + */ +import java.security.NoSuchProviderException; +import java.security.cert.*; +import java.io.ByteArrayInputStream; +import java.util.Base64; + +import jdk.test.lib.Utils; + +public class UnexpectedCCE { + static CertificateFactory cf = null; + + public static void main(String[] av ) throws CertificateException, + NoSuchProviderException { + + // Fuzzed data input stream looks like an x509.OIDName + // in the CertificateIssuerExtension. A CRLException is thrown + // because an X500Name is expected. + byte[] encoded_1 = Base64.getDecoder().decode(""" + MIIBljCCAVMCAQEwCwYHKoZIzjgEAwUAMC0xEzARBgoJkiaJk/IsZAEZEwNjb20xFjA\ + UBgoJkiaJjvIsZAEZEwZ0ZXN0Q0EXDTAzMDcxNTE2MjAwNVoXDTAzMDcyMDE2MjAwNV\ + owgdIwUwIBBBcNMDMwNzE1MTYyMDAzWjA/MD0GA1UdHQEB/wQzMDGILzETMBEGCgmSJ\ + omT8ixkARkMA2NvbTEYMBYGCgmSJomT8ixkARkTCGNlcnRzUlVTMBICAQMXDTAzMDcx\ + NTE2MjAwNFowUwIBAhcNMDMwNzE1MTYyMDA0WjA/MD0GA1UdIQEB/wQzMDEwGAYDVQQ\ + DExEwDyqGMDEUMgAwgDAuRQA1MRYGCgmSJomT8ixkARkTCG15VGVzdENBMBICAQEXDT\ + AzMDcxNTE2MjAwNFqgHzAdMA8GA1UdHAEB/wQFMAOEAf8wCgYDVR0UAwACAQIwCwYHK\ + oZIzjgEAwUAAzAAMC0CFBaZDryEEOr8Cw7sOAAAAKaDgtHcAhUAkUenJpwYZgS6IPjy\ + AjZG+RfHdO4="""); + + // Fuzzed data input stream looks like an x509.X400Address + // in the CertificateIssuerExtension. A CRLException is thrown + // because an X500Name is expected. + byte[] encoded_2 = Base64.getDecoder().decode(""" + MIIBljCCAVMCAQEwCwYHKoZIzjgEAwUAMC0xEzARBgoJkiaJk/IsZAEZEwNjb20xFjA\ + UBgoJkiaJk/IsZAEZEwZ0ZXN0J0EXDTAzMDcxNTE2MjAwNVoXDTAzMDcyMDE2MjAwNV\ + owgdIwUwIBBBcNMDMwNzE1MTYyMDA0WjA/MD0GA1UdHQEB/wQzMDGkLzETMBEGCgmSJ\ + omT8ixkARkTA2NvbTEYMBYGCgmSJomT8ixkARkTCGNlcnRzUlVTMBICAQMXDTAzMDcx\ + NTE2MjAwNFowUwIBAhcNMDMwNzE1MTYyMDA0WjA/MD0GA1UdHQEB/wQzMDGjLzETMBE\ + GCgmSJomT8ixkARkTA2NvGG0wMRYGCgmSJomT8ixkARkTCG15VGVzdENBMBICAQEXDT\ + AzMDcxNTE2MjAwNVqgHzAdMGAGA1UdHAEB/wQFMAOEAf8wCgYDVR0UBAMCAQIwCwYHK\ + oZIzjgEAwUAAzAAMC0CFBaZDryEEOr8Cw7sJa07gqaDgtHcAhUAkUenJpwYZgS6IPjy\ + AjZG+RfHdO4="""); + + cf = CertificateFactory.getInstance("X.509", "SUN"); + + run(encoded_1); + run(encoded_2); + } + + private static void run(byte[] buf) { + Utils.runAndCheckException( + () -> cf.generateCRLs(new ByteArrayInputStream(buf)), + CRLException.class); + } +} diff --git a/test/jdk/sun/security/x509/X509CRLImpl/Verify.java b/test/jdk/sun/security/x509/X509CRLImpl/Verify.java index ed92b6548ec1a..911f53f512075 100644 --- a/test/jdk/sun/security/x509/X509CRLImpl/Verify.java +++ b/test/jdk/sun/security/x509/X509CRLImpl/Verify.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 @@ -35,45 +35,61 @@ public class Verify { static String selfSignedCertStr = "-----BEGIN CERTIFICATE-----\n" + - "MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQQFADAfMQswCQYDVQQGEwJVUzEQ\n" + - "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA0MjcwMjI0MzJaFw0zMDA0MDcwMjI0MzJa\n" + - "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + - "AQUAA4GNADCBiQKBgQC4OTag24sTxL2tXTNuvpmUEtdxrYAZoFsslFQ60T+WD9wQ\n" + - "Jeiw87FSPsR2vxRuv0j8DNm2a4h7LNNIFcLurfNldbz5pvgZ7VqdbbUMPE9qP85n\n" + - "jgDl4woyRTSUeRI4A7O0CO6NpES21dtbdhroWQrEkHxpnrDPxsxrz5gf2m3gqwID\n" + - "AQABo4GJMIGGMB0GA1UdDgQWBBSCJd0hpl5PdAD9IZS+Hzng4lXLGzBHBgNVHSME\n" + - "QDA+gBSCJd0hpl5PdAD9IZS+Hzng4lXLG6EjpCEwHzELMAkGA1UEBhMCVVMxEDAO\n" + - "BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw\n" + - "DQYJKoZIhvcNAQEEBQADgYEAluy6HIjWcq009lTLmhp+Np6dxU78pInBK8RZkza0\n" + - "484qGaxFGD3UGyZkI5uWmsH2XuMbuox5khfIq6781gmkPBHXBIEtJN8eLusOHEye\n" + - "iE8h7WI+N3qa6Pj56WionMrioqC/3X+b06o147bbhx8U0vkYv/HyPaITOFfMXTdz\n" + - "Vjw=\n" + + "MIIDVzCCAj+gAwIBAgIUUM/RKxE2Rcc6zYLWLxNolpLnuiwwDQYJKoZIhvcNAQEL\n" + + "BQAwOzENMAsGA1UEAwwEUk9PVDEQMA4GA1UECgwHRXhhbXBsZTELMAkGA1UECAwC\n" + + "Q0ExCzAJBgNVBAYTAlVTMB4XDTI0MDYxOTA0NDc1N1oXDTM0MDYxOTA0NDc1N1ow\n" + + "OzENMAsGA1UEAwwEUk9PVDEQMA4GA1UECgwHRXhhbXBsZTELMAkGA1UECAwCQ0Ex\n" + + "CzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAohRG\n" + + "eq8/CniUqWEtpm1gBp+PWENpYgeaALAUgFdBBa6ao7mESjxRG8teaNRcszmoL3Rl\n" + + "TH5hLycHA00G5qsALXo4Cj9wAGfR3LbA0HlTurdw3NNk76twQXZpuE19YNYQonbR\n" + + "Mm2sgTd2YcrNWmGpthgNiUaT837Yt7RCuurPo4zi1y6g/NJwyLtn775S86NrV5PT\n" + + "4vaBCsB5+eCm01CBgzBq3I0OY5oosopNUjmFL4LYccZZ2YAOUY0fvxfsMZD5EDcj\n" + + "KrgKBspjmolfn5g5lA5vdVthG2/TxTIdLss69+NsGS1RBkSKGiQNKnRnAB9/gHwc\n" + + "2ryHKJRMQrV+JGMjrQIDAQABo1MwUTAdBgNVHQ4EFgQUW6jZ+mcCEMAQTUzJH2F0\n" + + "TwMTOMswHwYDVR0jBBgwFoAUW6jZ+mcCEMAQTUzJH2F0TwMTOMswDwYDVR0TAQH/\n" + + "BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAB8T/EfVh602S1GJD2tJ1ck9TwutF\n" + + "2VSoSRKajMOabbwjzKEAeJ9rNcWiy60rSvDuL8i4IL52R7fHhlJaDg9FVjmkiWSO\n" + + "VPiIZuOyvUtsc9++AM741RK9OrEMETvAtbtEMU6du7LiFk2KcnDTHfcNihtM/TNZ\n" + + "1bzEKuSfQydBNPkO3Ftmveygj7QGX+Kgppp7RXXUFzySYxrlA1usgNhVXY/qhFiJ\n" + + "jhTU33iZgwiKxpY+zj/Gmk5sdOCEk7e1P06IB3eIopdRTMGJCeCBKyFyXND38kNC\n" + + "bTIPnuOdE73M2AW0LWuPv6UQZVBv5A82WMT9f8Hq9H2cHbuhgL/ozyFSWw==\n" + "-----END CERTIFICATE-----"; static String crlIssuerCertStr = "-----BEGIN CERTIFICATE-----\n" + - "MIICKzCCAZSgAwIBAgIBAjANBgkqhkiG9w0BAQQFADAfMQswCQYDVQQGEwJVUzEQ\n" + - "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA0MjcwMjI0MzNaFw0yOTAxMTIwMjI0MzNa\n" + - "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + - "AQUAA4GNADCBiQKBgQDMJeBMBybHykI/YpwUJ4O9euqDSLb1kpWpceBS8TVqvgBC\n" + - "SgUJWtFZL0i6bdvF6mMdlbuBkGzhXqHiVAi96/zRLbUC9F8SMEJ6MuD+YhQ0ZFTQ\n" + - "atKy8zf8O9XzztelLJ26Gqb7QPV133WY3haAqHtCXOhEKkCN16NOYNC37DTaJwID\n" + - "AQABo3cwdTAdBgNVHQ4EFgQULXSWzXzUOIpOJpzbSCpW42IJUugwRwYDVR0jBEAw\n" + - "PoAUgiXdIaZeT3QA/SGUvh854OJVyxuhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + - "VQQKEwdFeGFtcGxlggEAMAsGA1UdDwQEAwIBAjANBgkqhkiG9w0BAQQFAAOBgQAY\n" + - "eMnf5AHSNlyUlzXk8o2S0h4gCuvKX6C3kFfKuZcWvFAbx4yQOWLS2s15/nzR4+AP\n" + - "FGX3lgJjROyAh7fGedTQK+NFWwkM2ag1g3hXktnlnT1qHohi0w31nVBJxXEDO/Ck\n" + - "uJTpJGt8XxxbFaw5v7cHy7XuTAeU/sekvjEiNHW00Q==\n" + + "MIIDeTCCAmGgAwIBAgIBATANBgkqhkiG9w0BAQUFADA7MQ0wCwYDVQQDDARST09U\n" + + "MRAwDgYDVQQKDAdFeGFtcGxlMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMwHhcN\n" + + "MjQwNjE5MDQ0NzU3WhcNMjYwNjE4MDQ0NzU3WjA5MQswCQYDVQQDDAJDQTELMAkG\n" + + "A1UECAwCQ0ExCzAJBgNVBAYTAlVTMRAwDgYDVQQKDAdFeGFtcGxlMIIBIjANBgkq\n" + + "hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn3wVMxoa3mgqk7fbg+UEj3vDfdR+o0dL\n" + + "UeDqtkM/KHQg2h16LTRsRM+bGcDAg8pz/8RNK+jiCq5lXylUtOYEIKzD2NTrycOH\n" + + "gAt92vt01cusZrnvdf+wKFNzDQea1q1fgNFbFdWZZ7Ia+BvR9dYdwbyX7LPKPth5\n" + + "aSmvwhKivETV6mTU17dMls/8OjQ+oUydBggVjhpjS+xYCBa09ie2dR+eGrluCaF5\n" + + "gspoTeQxAOOytBoL4+DECEPsAyr7/guMOdmWUbPDvfYL+97N6imXUh4XtQ7+xHTd\n" + + "OWWwAhS7JjqcalADSNUClU54VVGbZ9NmIjDiSPc1bvam4FxicuqrBQIDAQABo4GJ\n" + + "MIGGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFMPkRHT0w2v7Nx2SN/i+2hJIj/5x\n" + + "MB8GA1UdIwQYMBaAFFuo2fpnAhDAEE1MyR9hdE8DEzjLMAsGA1UdDwQEAwIBAjAp\n" + + "BgNVHR8EIjAgMB6gHKAahhhodHRwOi8vdGVzdC5jb20vcm9vdC5jcmwwDQYJKoZI\n" + + "hvcNAQEFBQADggEBAIsREfhopvEGrbVjbaRsBmGlMAblqiTWF3DklU4BfXGQ7u+2\n" + + "z/Dvl5rehGkWIU5GmBY/DFWN/Tgt6yJU+d1ismKj+zhWI8IT7dLKJnSP0Sei0zqr\n" + + "qsIj/y5Xzmd2XpQ52V3KtDy4t7YQJ+nRKUrqLzSKHvOXOQgScK2RL4FZx0gah/bJ\n" + + "YCKq6zonC59lZ6ftJ2j9Ny9wNulHBlgS0p8q+Z42IfdfVgrLmbXoHNmKjVKdrs1Z\n" + + "HCva3WKMOkVFdejOuvPSnSw4Iob479nC3V12YtFAgeYMoBMPgZHcuWce4IC9Ts7z\n" + + "w8Xo1Fv3aNOygWdXdVDL79jkOJo2wO8yIe+J6Ig=\n" + "-----END CERTIFICATE-----"; static String crlStr = "-----BEGIN X509 CRL-----\n" + - "MIIBGzCBhQIBATANBgkqhkiG9w0BAQQFADAfMQswCQYDVQQGEwJVUzEQMA4GA1UE\n" + - "ChMHRXhhbXBsZRcNMDkwNDI3MDIzODA0WhcNMjgwNjI2MDIzODA0WjAiMCACAQUX\n" + - "DTA5MDQyNzAyMzgwMFowDDAKBgNVHRUEAwoBBKAOMAwwCgYDVR0UBAMCAQIwDQYJ\n" + - "KoZIhvcNAQEEBQADgYEAoarfzXEtw3ZDi4f9U8eSvRIipHSyxOrJC7HR/hM5VhmY\n" + - "CErChny6x9lBVg9s57tfD/P9PSzBLusCcHwHMAbMOEcTltVVKUWZnnbumpywlYyg\n" + - "oKLrE9+yCOkYUOpiRlz43/3vkEL5hjIKMcDSZnPKBZi1h16Yj2hPe9GMibNip54=\n" + + "MIIBtjCBnwIBATANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQDDAJDQTELMAkGA1UE\n" + + "CAwCQ0ExCzAJBgNVBAYTAlVTMRAwDgYDVQQKDAdFeGFtcGxlFw0yNDA2MTkwNDQ3\n" + + "NThaFw0yNjA2MTgwNDQ3NThaMCIwIAIBAhcNMjQwNjE5MDQ0NzU4WjAMMAoGA1Ud\n" + + "FQQDCgEEoA4wDDAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQUFAAOCAQEAkN0owWtq\n" + + "We0SznF9rAAADLMfB/2GKBQpqsJXXwE9FnCm8emSDtHpud+NZL+PAy9g050et8nl\n" + + "CNey/FBMJJMN3b3SZKkHA2MR4qJmHfeFnlE5mHnUHg7gH0a1u7H7wf0Z/L6eZNWy\n" + + "dB905II7Ej0GBuPnLsKNMDBtGtDuSPXCvmaBsKDe8awaEA1VchZKVLzg+8hEC0vt\n" + + "60jz9HrDpFun99IKTTCxBT+9GrW38GbPMxj0rLAL4n75SrfPdeFPj0t5fksOC7a7\n" + + "SLO9t+UC89SMTsoIwVjHIFIUxw5FHpuUfgOQ7PtjhpLd2Pm5u5Pe2gv4Q41xVgVW\n" + + "hVMagRPmAQAniQ==\n" + "-----END X509 CRL-----"; private static X509CRL crl; @@ -87,7 +103,8 @@ public static void main(String[] args) throws Exception { * Verify CRL with its own public key. * Should pass. */ - verifyCRL(crlIssuerCertPubKey, "SunRsaSign"); + verifyCRL(crlIssuerCertPubKey, + System.getProperty("test.provider.name", "SunRsaSign")); /* * Try to verify CRL with a provider that does not have a Signature @@ -103,11 +120,12 @@ public static void main(String[] args) throws Exception { /* * Try to verify CRL with a provider that has a Signature implementation - * but not of the right algorithm (MD5withRSA). + * but not of the right algorithm (SHA1withRSA). * Should fail with NoSuchAlgorithmException. */ try { - verifyCRL(crlIssuerCertPubKey, "SUN"); + verifyCRL(crlIssuerCertPubKey, + System.getProperty("test.provider.name", "SUN")); throw new RuntimeException("Didn't catch the exception properly"); } catch (NoSuchAlgorithmException e) { System.out.println("Caught the correct exception."); @@ -118,7 +136,8 @@ public static void main(String[] args) throws Exception { * Should fail with SignatureException. */ try { - verifyCRL(selfSignedCertPubKey, "SunRsaSign"); + verifyCRL(selfSignedCertPubKey, + System.getProperty("test.provider.name","SunRsaSign")); throw new RuntimeException("Didn't catch the exception properly"); } catch (SignatureException e) { System.out.println("Caught the correct exception."); @@ -148,6 +167,7 @@ private static void verifyCRL(PublicKey key, String providerName) throws CRLException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { Provider provider = Security.getProvider(providerName); + System.out.println("Provider = " + provider.getName()); if (provider == null) { throw new RuntimeException("Provider " + providerName + " not found."); diff --git a/test/jdk/sun/security/x509/X509CertImpl/Verify.java b/test/jdk/sun/security/x509/X509CertImpl/Verify.java index cffee273e6f3d..0b98758ee4caf 100644 --- a/test/jdk/sun/security/x509/X509CertImpl/Verify.java +++ b/test/jdk/sun/security/x509/X509CertImpl/Verify.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 @@ -36,35 +36,47 @@ public class Verify { static String selfSignedCertStr = "-----BEGIN CERTIFICATE-----\n" + - "MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQQFADAfMQswCQYDVQQGEwJVUzEQ\n" + - "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA0MjcwMjI0MzJaFw0zMDA0MDcwMjI0MzJa\n" + - "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + - "AQUAA4GNADCBiQKBgQC4OTag24sTxL2tXTNuvpmUEtdxrYAZoFsslFQ60T+WD9wQ\n" + - "Jeiw87FSPsR2vxRuv0j8DNm2a4h7LNNIFcLurfNldbz5pvgZ7VqdbbUMPE9qP85n\n" + - "jgDl4woyRTSUeRI4A7O0CO6NpES21dtbdhroWQrEkHxpnrDPxsxrz5gf2m3gqwID\n" + - "AQABo4GJMIGGMB0GA1UdDgQWBBSCJd0hpl5PdAD9IZS+Hzng4lXLGzBHBgNVHSME\n" + - "QDA+gBSCJd0hpl5PdAD9IZS+Hzng4lXLG6EjpCEwHzELMAkGA1UEBhMCVVMxEDAO\n" + - "BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw\n" + - "DQYJKoZIhvcNAQEEBQADgYEAluy6HIjWcq009lTLmhp+Np6dxU78pInBK8RZkza0\n" + - "484qGaxFGD3UGyZkI5uWmsH2XuMbuox5khfIq6781gmkPBHXBIEtJN8eLusOHEye\n" + - "iE8h7WI+N3qa6Pj56WionMrioqC/3X+b06o147bbhx8U0vkYv/HyPaITOFfMXTdz\n" + - "Vjw=\n" + + "MIIDVzCCAj+gAwIBAgIUUM/RKxE2Rcc6zYLWLxNolpLnuiwwDQYJKoZIhvcNAQEL\n" + + "BQAwOzENMAsGA1UEAwwEUk9PVDEQMA4GA1UECgwHRXhhbXBsZTELMAkGA1UECAwC\n" + + "Q0ExCzAJBgNVBAYTAlVTMB4XDTI0MDYxOTA0NDc1N1oXDTM0MDYxOTA0NDc1N1ow\n" + + "OzENMAsGA1UEAwwEUk9PVDEQMA4GA1UECgwHRXhhbXBsZTELMAkGA1UECAwCQ0Ex\n" + + "CzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAohRG\n" + + "eq8/CniUqWEtpm1gBp+PWENpYgeaALAUgFdBBa6ao7mESjxRG8teaNRcszmoL3Rl\n" + + "TH5hLycHA00G5qsALXo4Cj9wAGfR3LbA0HlTurdw3NNk76twQXZpuE19YNYQonbR\n" + + "Mm2sgTd2YcrNWmGpthgNiUaT837Yt7RCuurPo4zi1y6g/NJwyLtn775S86NrV5PT\n" + + "4vaBCsB5+eCm01CBgzBq3I0OY5oosopNUjmFL4LYccZZ2YAOUY0fvxfsMZD5EDcj\n" + + "KrgKBspjmolfn5g5lA5vdVthG2/TxTIdLss69+NsGS1RBkSKGiQNKnRnAB9/gHwc\n" + + "2ryHKJRMQrV+JGMjrQIDAQABo1MwUTAdBgNVHQ4EFgQUW6jZ+mcCEMAQTUzJH2F0\n" + + "TwMTOMswHwYDVR0jBBgwFoAUW6jZ+mcCEMAQTUzJH2F0TwMTOMswDwYDVR0TAQH/\n" + + "BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAB8T/EfVh602S1GJD2tJ1ck9TwutF\n" + + "2VSoSRKajMOabbwjzKEAeJ9rNcWiy60rSvDuL8i4IL52R7fHhlJaDg9FVjmkiWSO\n" + + "VPiIZuOyvUtsc9++AM741RK9OrEMETvAtbtEMU6du7LiFk2KcnDTHfcNihtM/TNZ\n" + + "1bzEKuSfQydBNPkO3Ftmveygj7QGX+Kgppp7RXXUFzySYxrlA1usgNhVXY/qhFiJ\n" + + "jhTU33iZgwiKxpY+zj/Gmk5sdOCEk7e1P06IB3eIopdRTMGJCeCBKyFyXND38kNC\n" + + "bTIPnuOdE73M2AW0LWuPv6UQZVBv5A82WMT9f8Hq9H2cHbuhgL/ozyFSWw==\n" + "-----END CERTIFICATE-----"; static String crlIssuerCertStr = "-----BEGIN CERTIFICATE-----\n" + - "MIICKzCCAZSgAwIBAgIBAjANBgkqhkiG9w0BAQQFADAfMQswCQYDVQQGEwJVUzEQ\n" + - "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA0MjcwMjI0MzNaFw0yOTAxMTIwMjI0MzNa\n" + - "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + - "AQUAA4GNADCBiQKBgQDMJeBMBybHykI/YpwUJ4O9euqDSLb1kpWpceBS8TVqvgBC\n" + - "SgUJWtFZL0i6bdvF6mMdlbuBkGzhXqHiVAi96/zRLbUC9F8SMEJ6MuD+YhQ0ZFTQ\n" + - "atKy8zf8O9XzztelLJ26Gqb7QPV133WY3haAqHtCXOhEKkCN16NOYNC37DTaJwID\n" + - "AQABo3cwdTAdBgNVHQ4EFgQULXSWzXzUOIpOJpzbSCpW42IJUugwRwYDVR0jBEAw\n" + - "PoAUgiXdIaZeT3QA/SGUvh854OJVyxuhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + - "VQQKEwdFeGFtcGxlggEAMAsGA1UdDwQEAwIBAjANBgkqhkiG9w0BAQQFAAOBgQAY\n" + - "eMnf5AHSNlyUlzXk8o2S0h4gCuvKX6C3kFfKuZcWvFAbx4yQOWLS2s15/nzR4+AP\n" + - "FGX3lgJjROyAh7fGedTQK+NFWwkM2ag1g3hXktnlnT1qHohi0w31nVBJxXEDO/Ck\n" + - "uJTpJGt8XxxbFaw5v7cHy7XuTAeU/sekvjEiNHW00Q==\n" + + "MIIDeTCCAmGgAwIBAgIBATANBgkqhkiG9w0BAQUFADA7MQ0wCwYDVQQDDARST09U\n" + + "MRAwDgYDVQQKDAdFeGFtcGxlMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMwHhcN\n" + + "MjQwNjE5MDQ0NzU3WhcNMjYwNjE4MDQ0NzU3WjA5MQswCQYDVQQDDAJDQTELMAkG\n" + + "A1UECAwCQ0ExCzAJBgNVBAYTAlVTMRAwDgYDVQQKDAdFeGFtcGxlMIIBIjANBgkq\n" + + "hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn3wVMxoa3mgqk7fbg+UEj3vDfdR+o0dL\n" + + "UeDqtkM/KHQg2h16LTRsRM+bGcDAg8pz/8RNK+jiCq5lXylUtOYEIKzD2NTrycOH\n" + + "gAt92vt01cusZrnvdf+wKFNzDQea1q1fgNFbFdWZZ7Ia+BvR9dYdwbyX7LPKPth5\n" + + "aSmvwhKivETV6mTU17dMls/8OjQ+oUydBggVjhpjS+xYCBa09ie2dR+eGrluCaF5\n" + + "gspoTeQxAOOytBoL4+DECEPsAyr7/guMOdmWUbPDvfYL+97N6imXUh4XtQ7+xHTd\n" + + "OWWwAhS7JjqcalADSNUClU54VVGbZ9NmIjDiSPc1bvam4FxicuqrBQIDAQABo4GJ\n" + + "MIGGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFMPkRHT0w2v7Nx2SN/i+2hJIj/5x\n" + + "MB8GA1UdIwQYMBaAFFuo2fpnAhDAEE1MyR9hdE8DEzjLMAsGA1UdDwQEAwIBAjAp\n" + + "BgNVHR8EIjAgMB6gHKAahhhodHRwOi8vdGVzdC5jb20vcm9vdC5jcmwwDQYJKoZI\n" + + "hvcNAQEFBQADggEBAIsREfhopvEGrbVjbaRsBmGlMAblqiTWF3DklU4BfXGQ7u+2\n" + + "z/Dvl5rehGkWIU5GmBY/DFWN/Tgt6yJU+d1ismKj+zhWI8IT7dLKJnSP0Sei0zqr\n" + + "qsIj/y5Xzmd2XpQ52V3KtDy4t7YQJ+nRKUrqLzSKHvOXOQgScK2RL4FZx0gah/bJ\n" + + "YCKq6zonC59lZ6ftJ2j9Ny9wNulHBlgS0p8q+Z42IfdfVgrLmbXoHNmKjVKdrs1Z\n" + + "HCva3WKMOkVFdejOuvPSnSw4Iob479nC3V12YtFAgeYMoBMPgZHcuWce4IC9Ts7z\n" + + "w8Xo1Fv3aNOygWdXdVDL79jkOJo2wO8yIe+J6Ig=\n" + "-----END CERTIFICATE-----"; private static X509Certificate cert; @@ -78,7 +90,8 @@ public static void main(String[] args) throws Exception { * Verify certificate with its own public key. * Should pass. */ - verifyCert(selfSignedCertPubKey,"SunRsaSign"); + verifyCert(selfSignedCertPubKey, + System.getProperty("test.provider.name", "SunRsaSign")); /* * Try to verify certificate with a provider that does not have a @@ -86,7 +99,8 @@ public static void main(String[] args) throws Exception { * Should fail with NoSuchAlgorithmException. */ try { - verifyCert(selfSignedCertPubKey, "SunJCE"); + verifyCert(selfSignedCertPubKey, + System.getProperty("test.provider.name", "SunJCE")); throw new RuntimeException("Didn't catch the exception properly"); } catch (NoSuchAlgorithmException e) { System.out.println("Caught the correct exception."); @@ -94,11 +108,12 @@ public static void main(String[] args) throws Exception { /* * Try to verify certificate with a provider that has a Signature - * implementation but not of the right algorithm (MD5withRSA). + * implementation but not of the right algorithm (SHA1withRSA). * Should fail with NoSuchAlgorithmException. */ try { - verifyCert(selfSignedCertPubKey, "SUN"); + verifyCert(selfSignedCertPubKey, + System.getProperty("test.provider.name", "SUN")); throw new RuntimeException("Didn't catch the exception properly"); } catch (NoSuchAlgorithmException e) { System.out.println("Caught the correct exception."); @@ -109,7 +124,8 @@ public static void main(String[] args) throws Exception { * Should fail with SignatureException. */ try { - verifyCert(crlIssuerCertPubKey, "SunRsaSign"); + verifyCert(crlIssuerCertPubKey, + System.getProperty("test.provider.name", "SunRsaSign")); throw new RuntimeException("Didn't catch the exception properly"); } catch (SignatureException e) { System.out.println("Caught the correct exception."); diff --git a/test/jdk/sun/tools/jmap/BasicJMapTest.java b/test/jdk/sun/tools/jmap/BasicJMapTest.java index d8a24ef05facc..991648b96c2f3 100644 --- a/test/jdk/sun/tools/jmap/BasicJMapTest.java +++ b/test/jdk/sun/tools/jmap/BasicJMapTest.java @@ -87,8 +87,8 @@ */ /* - * @test id=ZSinglegen - * @requires vm.gc.ZSinglegen + * @test id=Z + * @requires vm.gc.Z * @summary Unit test for jmap utility (Z GC) * @key intermittent * @library /test/lib @@ -96,20 +96,7 @@ * @build jdk.test.lib.hprof.model.* * @build jdk.test.lib.hprof.parser.* * @build jdk.test.lib.hprof.util.* - * @run main/othervm/timeout=240 -XX:+UseZGC -XX:-ZGenerational BasicJMapTest - */ - -/* - * @test id=ZGenerational - * @requires vm.gc.ZGenerational - * @summary Unit test for jmap utility (Z GC) - * @key intermittent - * @library /test/lib - * @build jdk.test.lib.hprof.* - * @build jdk.test.lib.hprof.model.* - * @build jdk.test.lib.hprof.parser.* - * @build jdk.test.lib.hprof.util.* - * @run main/othervm/timeout=240 -XX:+UseZGC -XX:+ZGenerational BasicJMapTest + * @run main/othervm/timeout=240 -XX:+UseZGC BasicJMapTest */ public class BasicJMapTest { diff --git a/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java b/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java index 1ac4b01f1456c..0b6570b74dc73 100644 --- a/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java +++ b/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java @@ -280,5 +280,4 @@ private static ZoneInfoOld toZoneInfoOld(TimeZone tz) throws Exception { willGMTOffsetChange.getBoolean(tz)); } - } diff --git a/test/jdk/sun/util/calendar/zi/ZoneInfoOld.java b/test/jdk/sun/util/calendar/zi/ZoneInfoOld.java index 40f9cb9056cc9..300b7f13dddd7 100644 --- a/test/jdk/sun/util/calendar/zi/ZoneInfoOld.java +++ b/test/jdk/sun/util/calendar/zi/ZoneInfoOld.java @@ -85,17 +85,10 @@ public class ZoneInfoOld extends TimeZone { private static final long ABBR_MASK = 0xf00L; private static final int TRANSITION_NSHIFT = 12; - // Flag for supporting JDK backward compatible IDs, such as "EST". - static final boolean USE_OLDMAPPING; - static { - String oldmapping = System.getProperty("sun.timezone.ids.oldmapping", "false").toLowerCase(Locale.ROOT); - USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true")); - } - // IDs having conflicting data between Olson and JDK 1.1 - static final String[] conflictingIDs = { - "EST", "MST", "HST" - }; + static final Map conflictingIDs = Map.of( + "EST", "America/Panama", + "MST", "America/Phoenix"); private static final CalendarSystem gcal = CalendarSystem.getGregorianCalendar(); @@ -653,18 +646,6 @@ public static String[] getAvailableIDs(int rawOffset) { public static TimeZone getTimeZone(String ID) { String givenID = null; - /* - * If old JDK compatibility is specified, get the old alias - * name. - */ - if (USE_OLDMAPPING) { - String compatibleID = TzIDOldMapping.MAP.get(ID); - if (compatibleID != null) { - givenID = ID; - ID = compatibleID; - } - } - ZoneInfoOld zi = ZoneInfoFile.getZoneInfoOld(ID); if (zi == null) { // if we can't create an object for the ID, try aliases. @@ -842,12 +823,8 @@ public synchronized static Map getAliasTable() { if (aliases == null) { aliases = ZoneInfoFile.getZoneAliases(); if (aliases != null) { - if (!USE_OLDMAPPING) { - // Remove the conflicting IDs from the alias table. - for (String key : conflictingIDs) { - aliases.remove(key); - } - } + // Replace old mappings from `jdk11_backward` + aliases.putAll(conflictingIDs); aliasTable = new SoftReference>(aliases); } } diff --git a/test/jdk/sun/util/resources/TimeZone/Bug4848242.java b/test/jdk/sun/util/resources/TimeZone/Bug4848242.java index 99f66340316d9..68962f135d0d3 100644 --- a/test/jdk/sun/util/resources/TimeZone/Bug4848242.java +++ b/test/jdk/sun/util/resources/TimeZone/Bug4848242.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 @@ -35,7 +35,6 @@ public class Bug4848242 { public static void main(String[] args) { - getTzInfo("de", "DE"); getTzInfo("es", "ES"); getTzInfo("fr", "FR"); getTzInfo("it", "IT"); @@ -46,7 +45,6 @@ static void getTzInfo(String langName, String locName) { Locale tzLocale = Locale.of(langName, locName); TimeZone euroTz = TimeZone.getTimeZone("MET"); - System.out.println("Locale is " + langName + "_" + locName); if ( euroTz.getID().equalsIgnoreCase("GMT") ) { @@ -56,13 +54,13 @@ static void getTzInfo(String langName, String locName) // get the timezone info System.out.println(euroTz.getDisplayName(false, TimeZone.SHORT, tzLocale)); - if(!euroTz.getDisplayName(false, TimeZone.SHORT, tzLocale).equals("MET")) - throw new RuntimeException("Timezone name is incorrect (should be MET)\n"); + if (!euroTz.getDisplayName(false, TimeZone.SHORT, tzLocale).equals("CET")) + throw new RuntimeException("Timezone name is incorrect (should be CET)\n"); System.out.println(euroTz.getDisplayName(false, TimeZone.LONG, tzLocale)); System.out.println(euroTz.getDisplayName(true, TimeZone.SHORT, tzLocale)); - if(!euroTz.getDisplayName(true, TimeZone.SHORT, tzLocale).equals("MEST")) - throw new RuntimeException("Summer timezone name is incorrect (should be MEST)\n"); + if (!euroTz.getDisplayName(true, TimeZone.SHORT, tzLocale).equals("CEST")) + throw new RuntimeException("Summer timezone name is incorrect (should be CEST)\n"); System.out.println(euroTz.getDisplayName(true, TimeZone.LONG, tzLocale) + "\n"); } diff --git a/test/jdk/tools/jar/ExtractFilesTest.java b/test/jdk/tools/jar/ExtractFilesTest.java new file mode 100644 index 0000000000000..26e0d103d5123 --- /dev/null +++ b/test/jdk/tools/jar/ExtractFilesTest.java @@ -0,0 +1,269 @@ +/* + * 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 8335912 + * @summary test extract jar files overwrite existing files behavior + * @library /test/lib + * @modules jdk.jartool + * @build jdk.test.lib.Platform + * jdk.test.lib.util.FileUtils + * @run junit/othervm ExtractFilesTest + */ + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.spi.ToolProvider; +import java.util.stream.Stream; + +import jdk.test.lib.util.FileUtils; + + @TestInstance(Lifecycle.PER_CLASS) + public class ExtractFilesTest { + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> + new RuntimeException("jar tool not found") + ); + + private final String nl = System.lineSeparator(); + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + private final PrintStream out = new PrintStream(baos); + + @BeforeAll + public void setupJar() throws IOException { + mkdir("test1 test2"); + echo("testfile1", "test1/testfile1"); + echo("testfile2", "test2/testfile2"); + jar("cf test.jar -C test1 . -C test2 ."); + rm("test1 test2"); + } + + @AfterAll + public void cleanup() { + rm("test.jar"); + } + + /** + * Regular clean extract with expected output. + */ + @Test + public void testExtract() throws IOException { + jar("xvf test.jar"); + println(); + String output = " created: META-INF/" + nl + + " inflated: META-INF/MANIFEST.MF" + nl + + " inflated: testfile1" + nl + + " inflated: testfile2" + nl; + rm("META-INF testfile1 testfile2"); + assertOutputContains(output); + } + + /** + * Extract should overwrite existing file as default behavior. + */ + @Test + public void testOverwrite() throws IOException { + touch("testfile1"); + jar("xvf test.jar"); + println(); + String output = " created: META-INF/" + nl + + " inflated: META-INF/MANIFEST.MF" + nl + + " inflated: testfile1" + nl + + " inflated: testfile2" + nl; + Assertions.assertEquals("testfile1", cat("testfile1")); + rm("META-INF testfile1 testfile2"); + assertOutputContains(output); + } + + /** + * Extract with legacy style option `k` should preserve existing files. + */ + @Test + public void testKeptOldFile() throws IOException { + touch("testfile1"); + jar("xkvf test.jar"); + println(); + String output = " created: META-INF/" + nl + + " inflated: META-INF/MANIFEST.MF" + nl + + " skipped: testfile1 exists" + nl + + " inflated: testfile2" + nl; + Assertions.assertEquals("", cat("testfile1")); + Assertions.assertEquals("testfile2", cat("testfile2")); + rm("META-INF testfile1 testfile2"); + assertOutputContains(output); + } + + /** + * Extract with gnu style -k should preserve existing files. + */ + @Test + public void testGnuOptionsKeptOldFile() throws IOException { + touch("testfile1 testfile2"); + jar("-x -k -v -f test.jar"); + println(); + String output = " created: META-INF/" + nl + + " inflated: META-INF/MANIFEST.MF" + nl + + " skipped: testfile1 exists" + nl + + " skipped: testfile2 exists" + nl; + Assertions.assertEquals("", cat("testfile1")); + Assertions.assertEquals("", cat("testfile2")); + rm("META-INF testfile1 testfile2"); + assertOutputContains(output); + } + + /** + * Extract with gnu style long option --keep-old-files should preserve existing files. + */ + @Test + public void testGnuLongOptionsKeptOldFile() throws IOException { + touch("testfile2"); + jar("-x --keep-old-files -v -f test.jar"); + println(); + String output = " created: META-INF/" + nl + + " inflated: META-INF/MANIFEST.MF" + nl + + " inflated: testfile1" + nl + + " skipped: testfile2 exists" + nl; + Assertions.assertEquals("testfile1", cat("testfile1")); + Assertions.assertEquals("", cat("testfile2")); + rm("META-INF testfile1 testfile2"); + assertOutputContains(output); + } + + /** + * Test jar will issue warning when use keep option in non-extraction mode. + */ + @Test + public void testWarningOnInvalidKeepOption() throws IOException { + var err = jar("tkf test.jar"); + println(); + + String output = "META-INF/" + nl + + "META-INF/MANIFEST.MF" + nl + + "testfile1" + nl + + "testfile2" + nl; + + assertOutputContains(output); + Assertions.assertEquals("Warning: The --keep-old-files/-k/k option is not valid with current usage, will be ignored." + nl, err); + } + + private void assertOutputContains(String expected) { + Assertions.assertTrue(baos.toString().contains(expected)); + } + + private Stream mkpath(String... args) { + return Arrays.stream(args).map(d -> Path.of(".", d.split("/"))); + } + + private void mkdir(String cmdline) { + System.out.println("mkdir -p " + cmdline); + mkpath(cmdline.split(" +")).forEach(p -> { + try { + Files.createDirectories(p); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } + + private void touch(String cmdline) { + System.out.println("touch " + cmdline); + mkpath(cmdline.split(" +")).forEach(p -> { + try { + Files.createFile(p); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } + + private void echo(String text, String path) { + System.out.println("echo '" + text + "' > " + path); + try { + var p = Path.of(".", path.split("/")); + Files.writeString(p, text); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } + + private String cat(String path) { + System.out.println("cat " + path); + try { + return Files.readString(Path.of(path)); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } + + private void rm(String cmdline) { + System.out.println("rm -rf " + cmdline); + mkpath(cmdline.split(" +")).forEach(p -> { + try { + if (Files.isDirectory(p)) { + FileUtils.deleteFileTreeWithRetry(p); + } else { + FileUtils.deleteFileIfExistsWithRetry(p); + } + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } + + private String jar(String cmdline) throws IOException { + System.out.println("jar " + cmdline); + baos.reset(); + + // the run method catches IOExceptions, we need to expose them + ByteArrayOutputStream baes = new ByteArrayOutputStream(); + PrintStream err = new PrintStream(baes); + PrintStream saveErr = System.err; + System.setErr(err); + try { + int rc = JAR_TOOL.run(out, err, cmdline.split(" +")); + if (rc != 0) { + throw new IOException(baes.toString()); + } + } finally { + System.setErr(saveErr); + } + return baes.toString(); + } + + private void println() throws IOException { + System.out.println(new String(baos.toByteArray())); + } +} diff --git a/test/jdk/tools/jar/JarExtractTest.java b/test/jdk/tools/jar/JarExtractTest.java new file mode 100644 index 0000000000000..f1d30e678ae41 --- /dev/null +++ b/test/jdk/tools/jar/JarExtractTest.java @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.spi.ToolProvider; +import java.util.stream.Stream; + +import jdk.test.lib.util.JarBuilder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeEach; +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.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test + * @bug 8173970 + * @summary jar tool should allow extracting to specific directory + * @library /test/lib + * @comment The test relies on verification of error messages generated by jar tool, so we use + * a fixed en_US locale for this test. + * @run junit/othervm -Duser.language=en -Duser.country=US JarExtractTest + */ +public class JarExtractTest { + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> + new RuntimeException("jar tool not found") + ); + + private static final byte[] FILE_CONTENT = "Hello world!!!".getBytes(StandardCharsets.UTF_8); + // the jar that will get extracted in the tests + private Path testJarPath; + private static Collection filesToDelete = new ArrayList<>(); + + @BeforeEach + public void createTestJar() throws Exception { + final String tmpDir = Files.createTempDirectory("8173970-").toString(); + testJarPath = Path.of(tmpDir, "8173970-test.jar"); + final JarBuilder builder = new JarBuilder(testJarPath.toString()); + // d1 + // |--- d2 + // | |--- d3 + // | | |--- f2.txt + // | + // |--- d4 + // ... + // f1.txt + + builder.addEntry("d1/", new byte[0]); + builder.addEntry("f1.txt", FILE_CONTENT); + builder.addEntry("d1/d2/d3/f2.txt", FILE_CONTENT); + builder.addEntry("d1/d4/", new byte[0]); + builder.build(); + } + + @AfterEach + public void cleanup() { + for (final Path p : filesToDelete) { + try { + System.out.println("Deleting file/dir " + p); + Files.delete(p); + } catch (IOException ioe) { + //ignore + System.err.println("ignoring exception: " + ioe + + " that happened when deleting: " + p); + } + } + } + + /** + * Creates and returns various relative paths, to which the jar will be extracted in the tests + */ + static Stream provideRelativeExtractLocations() throws Exception { + // create some dirs so that they already exist when the jar is being extracted + final String existing1 = "." + File.separator + "8173970-existing-1"; + Files.createDirectories(Path.of(existing1)); + final String existing2 = "." + File.separator + "foo" + File.separator + "8173970-existing-2"; + Files.createDirectories(Path.of(existing2)); + final Path dirOutsideScratchDir = Files.createTempDirectory(Path.of(".."), "8173970"); + // we need to explicitly delete this dir after the tests end + filesToDelete.add(dirOutsideScratchDir); + final String existing3 = dirOutsideScratchDir.toString() + File.separator + "8173970-existing-3"; + Files.createDirectories(Path.of(existing3)); + + final String anotherDirOutsideScratchDir = ".." + File.separator + "8173970-non-existent"; + filesToDelete.add(Path.of(anotherDirOutsideScratchDir)); + + final List args = new ArrayList<>(); + args.add(Arguments.of(".")); // current dir + // (explicitly) relative to current dir + args.add(Arguments.of("." + File.separator + "8173970-extract-1")); + // (implicitly) relative to current dir + args.add(Arguments.of("8173970-extract-2")); + // sibling to current dir + args.add(Arguments.of(anotherDirOutsideScratchDir)); + // some existing dirs + args.add(Arguments.of(existing1)); + args.add(Arguments.of(existing2)); + args.add(Arguments.of(existing3)); + // a non-existent dir within an existing dir + args.add(Arguments.of(existing1 + File.separator + + "non-existing" + File.separator + "foo")); + return args.stream(); + } + + /** + * Creates and returns various absolute paths, to which the jar will be extracted in the tests + */ + static Stream provideAbsoluteExtractLocations() throws Exception { + final Stream relative = provideRelativeExtractLocations(); + return relative.map((arg) -> { + final String relPath = (String) arg.get()[0]; + return Arguments.of(Path.of(relPath).toAbsolutePath().toString()); + }); + } + + /** + * Creates and returns various normalized paths, to which the jar will be extracted in the tests + */ + static Stream provideAbsoluteNormalizedExtractLocations() throws Exception { + final Stream relative = provideRelativeExtractLocations(); + return relative.map((arg) -> { + final String relPath = (String) arg.get()[0]; + return Arguments.of(Path.of(relPath).toAbsolutePath().normalize().toString()); + }); + } + + /** + * Extracts a jar to various relative paths, using the -C/--dir option and then + * verifies that the extracted content is at the expected locations with the correct + * content + */ + @ParameterizedTest + @MethodSource("provideRelativeExtractLocations") + public void testExtractToRelativeDir(final String dest) throws Exception { + testLongFormExtract(dest); + testExtract(dest); + } + + /** + * Extracts a jar to various absolute paths, using the -C/--dir option and then + * verifies that the extracted content is at the expected locations with the correct + * content + */ + @ParameterizedTest + @MethodSource("provideAbsoluteExtractLocations") + public void testExtractToAbsoluteDir(final String dest) throws Exception { + testExtract(dest); + testLongFormExtract(dest); + } + + /** + * Extracts a jar to various normalized paths (i.e. no {@code .} or @{code ..} in the path components), + * using the -C/--dir option and then verifies that the extracted content is at the expected locations + * with the correct content + */ + @ParameterizedTest + @MethodSource("provideAbsoluteNormalizedExtractLocations") + public void testExtractToAbsoluteNormalizedDir(final String dest) throws Exception { + testExtract(dest); + testLongFormExtract(dest); + } + + /** + * Test that extracting a jar with {@code jar -x -f --dir} works as expected + */ + @Test + public void testExtractLongFormDir() throws Exception { + final String dest = "foo-bar"; + System.out.println("Extracting " + testJarPath + " to " + dest); + final int exitCode = JAR_TOOL.run(System.out, System.err, "-x", "-f", testJarPath.toString(), + "--dir", dest); + assertEquals(0, exitCode, "Failed to extract " + testJarPath + " to " + dest); + verifyExtractedContent(dest); + } + + /** + * Verifies that the {@code jar --help} output contains the --dir option + */ + @Test + public void testHelpOutput() { + final ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + final int exitCode = JAR_TOOL.run(new PrintStream(outStream), System.err, "--help"); + assertEquals(0, exitCode, "jar --help command failed"); + final String output = outStream.toString(); + // this message is expected to be the one from the jar --help output which is sourced from + // jar.properties + final String expectedMsg = "--dir Directory into which the jar will be extracted"; + assertTrue(output.contains(expectedMsg), "jar --help didn't contain --dir option"); + } + + /** + * Tests that {@code jar -x -f} command works fine even when the -C or --dir option + * isn't specified + */ + @Test + public void testExtractWithoutOutputDir() throws Exception { + final int exitCode = JAR_TOOL.run(System.out, System.err, "-x", "-f", testJarPath.toString()); + assertEquals(0, exitCode, "Failed to extract " + testJarPath); + // the content would have been extracted to current dir + verifyExtractedContent("."); + } + + /** + * Tests that {@code jar --extract -f} command works fine even when the -C or --dir option + * isn't specified + */ + @Test + public void testLongFormExtractWithoutOutputDir() throws Exception { + final int exitCode = JAR_TOOL.run(System.out, System.err, "--extract", "-f", testJarPath.toString()); + assertEquals(0, exitCode, "Failed to extract " + testJarPath); + // the content would have been extracted to current dir + verifyExtractedContent("."); + } + + /** + * Tests that when the destination directory specified for jar extract is actually a file + * or one of the path component in the specified destination path is a file, then the + * extraction fails. + */ + @Test + public void testExtractToNonDirectory() throws Exception { + final String expectedErrMsg = "could not create directory"; + final Path notADir1 = Files.createTempFile(Path.of("."), "8173970", ".txt"); + final Path notADir2 = notADir1.resolve("foobar"); + for (final Path dest : List.of(notADir1, notADir2)) { + final String[] args = {"-x", "-f", testJarPath.toString(), "-C", dest.toString()}; + final ByteArrayOutputStream err = new ByteArrayOutputStream(); + printJarCommand(args); + int exitCode = JAR_TOOL.run(System.out, new PrintStream(err), args); + assertNotEquals(0, exitCode, "jar extraction was expected to fail but didn't"); + // verify it did indeed fail due to the right reason + assertTrue(err.toString(StandardCharsets.UTF_8).contains(expectedErrMsg)); + } + } + + /** + * Tests that extracting a jar using {@code -P} flag and without any explicit destination + * directory works correctly if the jar contains entries with leading slashes and/or {@code ..} + * parts preserved. + */ + @Test + public void testExtractNoDestDirWithPFlag() throws Exception { + // run this test only on those systems where "/tmp" directory is available and we + // can write to it + Assumptions.assumeTrue(Files.isDirectory(Path.of("/tmp")), + "skipping test, since /tmp isn't a directory"); + // try and write into "/tmp" + final Path tmpDir; + try { + tmpDir = Files.createTempDirectory(Path.of("/tmp"), "8173970-").toAbsolutePath(); + } catch (IOException ioe) { + Assumptions.abort("skipping test, since /tmp cannot be written to: " + ioe); + return; + } + final String leadingSlashEntryName = tmpDir.toString() + "/foo/f1.txt"; + // create a jar which has leading slash (/) and dot-dot (..) preserved in entry names + final Path jarPath = createJarWithPFlagSemantics(leadingSlashEntryName); + final List cmdArgs = new ArrayList<>(); + cmdArgs.add(new String[]{"-xvfP", jarPath.toString()}); + cmdArgs.add(new String[]{"--extract", "-v", "-P", "-f", jarPath.toString()}); + try { + for (final String[] args : cmdArgs) { + printJarCommand(args); + final int exitCode = JAR_TOOL.run(System.out, System.err, args); + assertEquals(0, exitCode, "Failed to extract " + jarPath); + final String dest = "."; + assertTrue(Files.isDirectory(Path.of(dest)), dest + " is not a directory"); + final Path d1 = Path.of(dest, "d1"); + assertTrue(Files.isDirectory(d1), d1 + " directory is missing or not a directory"); + final Path d2 = Path.of(dest, "d1", "d2"); + assertTrue(Files.isDirectory(d2), d2 + " directory is missing or not a directory"); + final Path f1 = Path.of(leadingSlashEntryName); + assertTrue(Files.isRegularFile(f1), f1 + " is missing or not a file"); + assertArrayEquals(FILE_CONTENT, Files.readAllBytes(f1), + "Unexpected content in file " + f1); + final Path f2 = Path.of("d1/d2/../f2.txt"); + assertTrue(Files.isRegularFile(f2), f2 + " is missing or not a file"); + assertArrayEquals(FILE_CONTENT, Files.readAllBytes(f2), + "Unexpected content in file " + f2); + } + } finally { + // clean up the file that might have been extracted into "/tmp/...." directory + Files.deleteIfExists(Path.of(leadingSlashEntryName)); + } + } + + /** + * Tests that the {@code -P} option cannot be used during jar extraction when the {@code -C} and/or + * {@code --dir} option is used + */ + @Test + public void testExtractWithDirPFlagNotAllowed() throws Exception { + // this error message is expected to be the one from the jar --help output which is sourced from + // jar.properties + final String expectedErrMsg = "You may not specify '-Px' with the '-C' or '--dir' options"; + final String tmpDir = Files.createTempDirectory(Path.of("."), "8173970-").toString(); + final List cmdArgs = new ArrayList<>(); + cmdArgs.add(new String[]{"-x", "-f", testJarPath.toString(), "-P", "-C", tmpDir}); + cmdArgs.add(new String[]{"-x", "-f", testJarPath.toString(), "-P", "--dir", tmpDir}); + cmdArgs.add(new String[]{"-x", "-f", testJarPath.toString(), "-P", "-C", "."}); + cmdArgs.add(new String[]{"-x", "-f", testJarPath.toString(), "-P", "--dir", "."}); + cmdArgs.add(new String[]{"-xvfP", testJarPath.toString(), "-C", tmpDir}); + cmdArgs.add(new String[]{"--extract", "-f", testJarPath.toString(), "-P", "-C", tmpDir}); + cmdArgs.add(new String[]{"--extract", "-f", testJarPath.toString(), "-P", "--dir", tmpDir}); + cmdArgs.add(new String[]{"--extract", "-f", testJarPath.toString(), "-P", "-C", "."}); + cmdArgs.add(new String[]{"--extract", "-f", testJarPath.toString(), "-P", "--dir", "."}); + for (final String[] args : cmdArgs) { + final ByteArrayOutputStream err = new ByteArrayOutputStream(); + printJarCommand(args); + int exitCode = JAR_TOOL.run(System.out, new PrintStream(err), args); + assertNotEquals(0, exitCode, "jar extraction was expected to fail but didn't"); + // verify it did indeed fail due to the right reason + assertTrue(err.toString(StandardCharsets.UTF_8).contains(expectedErrMsg)); + } + } + + /** + * Tests that {@code jar -xvf -C } works fine too + */ + @Test + public void testLegacyCompatibilityMode() throws Exception { + final String tmpDir = Files.createTempDirectory(Path.of("."), "8173970-").toString(); + final String[] args = new String[]{"-xvf", testJarPath.toString(), "-C", tmpDir}; + printJarCommand(args); + final int exitCode = JAR_TOOL.run(System.out, System.err, args); + assertEquals(0, exitCode, "Failed to extract " + testJarPath); + verifyExtractedContent(tmpDir); + } + + /** + * Tests that when multiple directories are specified for extracting the jar, the jar extraction + * fails + */ + @Test + public void testExtractFailWithMultipleDir() throws Exception { + // this error message is expected to be the one from the jar --help output which is sourced from + // jar.properties + final String expectedErrMsg = "You may not specify the '-C' or '--dir' option more than once with the '-x' option"; + final String tmpDir = Files.createTempDirectory(Path.of("."), "8173970-").toString(); + final List cmdArgs = new ArrayList<>(); + cmdArgs.add(new String[]{"-x", "-f", testJarPath.toString(), "-C", tmpDir, "-C", tmpDir}); + cmdArgs.add(new String[]{"-x", "-f", testJarPath.toString(), "--dir", tmpDir, "--dir", tmpDir}); + cmdArgs.add(new String[]{"-x", "-f", testJarPath.toString(), "--dir", tmpDir, "-C", tmpDir}); + cmdArgs.add(new String[]{"--extract", "-f", testJarPath.toString(), "-C", tmpDir, "-C", tmpDir}); + cmdArgs.add(new String[]{"--extract", "-f", testJarPath.toString(), "--dir", tmpDir, "--dir", tmpDir}); + cmdArgs.add(new String[]{"--extract", "-f", testJarPath.toString(), "--dir", tmpDir, "-C", tmpDir}); + for (final String[] args : cmdArgs) { + final ByteArrayOutputStream err = new ByteArrayOutputStream(); + printJarCommand(args); + int exitCode = JAR_TOOL.run(System.out, new PrintStream(err), args); + assertNotEquals(0, exitCode, "jar extraction was expected to fail but didn't"); + // verify it did indeed fail due to the right reason + assertTrue(err.toString(StandardCharsets.UTF_8).contains(expectedErrMsg)); + } + } + + /** + * Tests that extracting only specific files from a jar, into a specific destination directory, + * works as expected + */ + @Test + public void testExtractPartialContent() throws Exception { + String tmpDir = Files.createTempDirectory(Path.of("."), "8173970-").toString(); + String[] cmdArgs = new String[]{"-x", "-f", testJarPath.toString(), "--dir", tmpDir, + "f1.txt", "d1/d2/d3/f2.txt"}; + testExtractPartialContent(tmpDir, cmdArgs); + + tmpDir = Files.createTempDirectory(Path.of("."), "8173970-").toString(); + cmdArgs = new String[]{"--extract", "-f", testJarPath.toString(), "--dir", tmpDir, + "f1.txt", "d1/d2/d3/f2.txt"}; + testExtractPartialContent(tmpDir, cmdArgs); + + } + + /** + * Extract to destDir using the passed command arguments and verify the extracted content + */ + private void testExtractPartialContent(final String destDir, final String[] extractArgs) throws Exception { + printJarCommand(extractArgs); + final int exitCode = JAR_TOOL.run(System.out, System.err, extractArgs); + assertEquals(0, exitCode, "Failed to extract " + testJarPath); + // make sure only the specific files were extracted + final Stream paths = Files.walk(Path.of(destDir)); + // files/dirs count expected to be found when the location to which the jar was extracted + // is walked. + // 1) The top level dir being walked 2) f1.txt file 3) d1 dir 4) d1/d2 dir + // 5) d1/d2/d3 dir 6) d1/d2/d3/f2.txt file + final int numExpectedFiles = 6; + assertEquals(numExpectedFiles, paths.count(), "Unexpected number of files/dirs in " + destDir); + final Path f1 = Path.of(destDir, "f1.txt"); + assertTrue(Files.isRegularFile(f1), f1.toString() + " wasn't extracted from " + testJarPath); + assertArrayEquals(FILE_CONTENT, Files.readAllBytes(f1), "Unexpected content in file " + f1); + final Path d1 = Path.of(destDir, "d1"); + assertTrue(Files.isDirectory(d1), d1.toString() + " wasn't extracted from " + testJarPath); + assertEquals(2, Files.walk(d1, 1).count(), "Unexpected number " + + "of files/dirs in " + d1); + final Path d2 = Path.of(d1.toString(), "d2"); + assertTrue(Files.isDirectory(d2), d2.toString() + " wasn't extracted from " + testJarPath); + assertEquals(2, Files.walk(d2, 1).count(), "Unexpected number " + + "of files/dirs in " + d2); + final Path d3 = Path.of(d2.toString(), "d3"); + assertTrue(Files.isDirectory(d3), d3.toString() + " wasn't extracted from " + testJarPath); + assertEquals(2, Files.walk(d3, 1).count(), "Unexpected number " + + "of files/dirs in " + d3); + final Path f2 = Path.of(d3.toString(), "f2.txt"); + assertTrue(Files.isRegularFile(f2), f2.toString() + " wasn't extracted from " + testJarPath); + assertArrayEquals(FILE_CONTENT, Files.readAllBytes(f2), "Unexpected content in file " + f2); + } + + /** + * Extracts the jar file using {@code jar -x -f -C } and verifies the extracted content + */ + private void testExtract(final String dest) throws Exception { + final String[] args = new String[]{"-x", "-f", testJarPath.toString(), "-C", dest}; + printJarCommand(args); + final int exitCode = JAR_TOOL.run(System.out, System.err, args); + assertEquals(0, exitCode, "Failed to extract " + testJarPath + " to " + dest); + verifyExtractedContent(dest); + } + + /** + * Extracts the jar file using {@code jar --extract -f -C } and verifies the + * extracted content + */ + private void testLongFormExtract(final String dest) throws Exception { + final String[] args = new String[]{"--extract", "-f", testJarPath.toString(), "-C", dest}; + printJarCommand(args); + final int exitCode = JAR_TOOL.run(System.out, System.err, args); + assertEquals(0, exitCode, "Failed to extract " + testJarPath + " to " + dest); + verifyExtractedContent(dest); + } + + /** + * Verifies that the extracted jar content matches what was present in the original jar + */ + private void verifyExtractedContent(final String dest) throws IOException { + assertTrue(Files.isDirectory(Path.of(dest)), dest + " is not a directory"); + final Path d1 = Path.of(dest, "d1"); + assertTrue(Files.isDirectory(d1), d1 + " directory is missing or not a directory"); + final Path d2 = Path.of(dest, "d1", "d2"); + assertTrue(Files.isDirectory(d2), d2 + " directory is missing or not a directory"); + final Path d3 = Path.of(dest, "d1", "d2", "d3"); + assertTrue(Files.isDirectory(d3), d3 + " directory is missing or not a directory"); + final Path d4 = Path.of(dest, "d1", "d4"); + assertTrue(Files.isDirectory(d4), d4 + " directory is missing or not a directory"); + // d1/d4 is expected to be empty directory + final List d4Children; + try (final Stream s = Files.walk(d4, 1)) { + d4Children = s.toList(); + } + assertEquals(1, d4Children.size(), "Directory " + d4 + + " has unexpected files/dirs: " + d4Children); + final Path f1 = Path.of(dest, "f1.txt"); + assertTrue(Files.isRegularFile(f1), f1 + " is missing or not a file"); + assertArrayEquals(FILE_CONTENT, Files.readAllBytes(f1), "Unexpected content in file " + f1); + final Path f2 = Path.of(d3.toString(), "f2.txt"); + assertTrue(Files.isRegularFile(f2), f2 + " is missing or not a file"); + assertArrayEquals(FILE_CONTENT, Files.readAllBytes(f2), "Unexpected content in file " + f2); + } + + /** + * Creates a jar whose entries have a leading slash and the dot-dot character preserved. + * This is the same as creating a jar using {@code jar -cfP somejar.jar ...} + */ + private static Path createJarWithPFlagSemantics(String leadingSlashEntryName) + throws IOException { + final Path tmpDir = Files.createTempDirectory(Path.of("."), "8173970-").toAbsolutePath(); + final Path jarPath = tmpDir.resolve("8173970-test-withpflag.jar"); + final JarBuilder builder = new JarBuilder(jarPath.toString()); + builder.addEntry("d1/", new byte[0]); + builder.addEntry("d1/d2/", new byte[0]); + builder.addEntry(leadingSlashEntryName, FILE_CONTENT); + builder.addEntry("d1/d2/../f2.txt", FILE_CONTENT); + builder.build(); + return jarPath; + } + + private static void printJarCommand(final String[] cmdArgs) { + System.out.println("Running 'jar " + String.join(" ", cmdArgs) + "'"); + } +} \ No newline at end of file diff --git a/test/jdk/tools/jar/MultipleManifestTest.java b/test/jdk/tools/jar/MultipleManifestTest.java new file mode 100644 index 0000000000000..231f6ba1ec656 --- /dev/null +++ b/test/jdk/tools/jar/MultipleManifestTest.java @@ -0,0 +1,228 @@ +/* + * 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 8335912 + * @summary test extract jar with multpile manifest files + * @library /test/lib + * @modules jdk.jartool + * @build jdk.test.lib.Platform + * jdk.test.lib.util.FileUtils + * @run junit/othervm MultipleManifestTest + */ + +import java.io.ByteArrayOutputStream; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; + +import java.io.IOException; +import java.io.PrintStream; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.spi.ToolProvider; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import jdk.test.lib.util.FileUtils; + +@TestInstance(Lifecycle.PER_CLASS) +class MultipleManifestTest { + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> + new RuntimeException("jar tool not found") + ); + + private final String nl = System.lineSeparator(); + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + private final PrintStream jarOut = new PrintStream(baos); + + static final Path zip = Path.of("MultipleManifestTest.jar"); + static final String jdkVendor = System.getProperty("java.vendor"); + static final String jdkVersion = System.getProperty("java.version"); + static final String MANIFEST1 = "Manifest-Version: 1.0" + + System.lineSeparator() + + "Created-By: " + jdkVersion + " (" + jdkVendor + ")"; + static final String MANIFEST2 = "Manifest-Version: 2.0" + + System.lineSeparator() + + "Created-By: " + jdkVersion + " (" + jdkVendor + ")"; + static final String MANIFEST3 = "Manifest-Version: 3.0" + + System.lineSeparator() + + "Created-By: " + jdkVersion + " (" + jdkVendor + ")"; + private static final String META_INF = "META-INF/"; + + /** + * Delete the ZIP file produced by this test + * + * @throws IOException if an unexpected IOException occurs + */ + @AfterAll + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + } + + /** + * Create a JAR with the Manifest as the 1st, 2nd and 4th entry + * + * @throws IOException if an error occurs + */ + @BeforeAll + public void writeManifestAsFirstSecondAndFourthEntry() throws IOException { + int locPosA, locPosB, cenPos; + System.out.printf("%n%n*****Creating Jar with the Manifest as the 1st, 2nd and 4th entry*****%n%n"); + var out = new ByteArrayOutputStream(1024); + try (var zos = new ZipOutputStream(out)) { + zos.putNextEntry(new ZipEntry(JarFile.MANIFEST_NAME)); + zos.write(MANIFEST1.getBytes(StandardCharsets.UTF_8)); + zos.closeEntry(); + locPosA = out.size(); + zos.putNextEntry(new ZipEntry(META_INF + "AANIFEST.MF")); + zos.write(MANIFEST2.getBytes(StandardCharsets.UTF_8)); + zos.putNextEntry(new ZipEntry("entry1.txt")); + zos.write("entry1".getBytes(StandardCharsets.UTF_8)); + zos.closeEntry(); + locPosB = out.size(); + zos.putNextEntry(new ZipEntry(META_INF + "BANIFEST.MF")); + zos.write(MANIFEST3.getBytes(StandardCharsets.UTF_8)); + zos.putNextEntry(new ZipEntry("entry2.txt")); + zos.write("hello entry2".getBytes(StandardCharsets.UTF_8)); + zos.flush(); + cenPos = out.size(); + } + var template = out.toByteArray(); + // ISO_8859_1 to keep the 8-bit value + var s = new String(template, StandardCharsets.ISO_8859_1); + // change META-INF/AANIFEST.MF to META-INF/MANIFEST.MF + var loc = s.indexOf("AANIFEST.MF", locPosA); + var cen = s.indexOf("AANIFEST.MF", cenPos); + template[loc] = template[cen] = (byte) 'M'; + // change META-INF/BANIFEST.MF to META-INF/MANIFEST.MF + loc = s.indexOf("BANIFEST.MF", locPosB); + cen = s.indexOf("BANIFEST.MF", cenPos); + template[loc] = template[cen] = (byte) 'M'; + Files.write(zip, template); + } + + @AfterEach + public void removeExtractedFiles() { + rm("META-INF entry1.txt entry2.txt"); + } + + /** + * Extract by default should have the last manifest. + */ + @Test + public void testOverwrite() throws IOException { + jar("xvf " + zip.toString()); + println(); + Assertions.assertEquals("3.0", getManifestVersion()); + String output = " inflated: META-INF/MANIFEST.MF" + nl + + " inflated: META-INF/MANIFEST.MF" + nl + + " inflated: entry1.txt" + nl + + " inflated: META-INF/MANIFEST.MF" + nl + + " inflated: entry2.txt" + nl; + assertOutputContains(output); + } + + /** + * Extract with k option should have first manifest. + */ + @Test + public void testKeptOldFile() throws IOException { + jar("xkvf " + zip.toString()); + println(); + Assertions.assertEquals("1.0", getManifestVersion()); + String output = " inflated: META-INF/MANIFEST.MF" + nl + + " skipped: META-INF/MANIFEST.MF exists" + nl + + " inflated: entry1.txt" + nl + + " skipped: META-INF/MANIFEST.MF exists" + nl + + " inflated: entry2.txt" + nl; + assertOutputContains(output); + } + + private String getManifestVersion() throws IOException { + try (var is = Files.newInputStream(Path.of(JarFile.MANIFEST_NAME))) { + var manifest = new Manifest(is); + return manifest.getMainAttributes().getValue(Attributes.Name.MANIFEST_VERSION); + } + } + + private void jar(String cmdline) throws IOException { + System.out.println("jar " + cmdline); + baos.reset(); + + // the run method catches IOExceptions, we need to expose them + ByteArrayOutputStream baes = new ByteArrayOutputStream(); + PrintStream err = new PrintStream(baes); + PrintStream saveErr = System.err; + System.setErr(err); + try { + int rc = JAR_TOOL.run(jarOut, err, cmdline.split(" +")); + if (rc != 0) { + throw new IOException(baes.toString()); + } + } finally { + System.setErr(saveErr); + } + } + + private void assertOutputContains(String expected) { + Assertions.assertTrue(baos.toString().contains(expected)); + } + + private void println() throws IOException { + System.out.println(new String(baos.toByteArray())); + } + + private Stream mkpath(String... args) { + return Arrays.stream(args).map(d -> Path.of(".", d.split("/"))); + } + + private void rm(String cmdline) { + System.out.println("rm -rf " + cmdline); + mkpath(cmdline.split(" +")).forEach(p -> { + try { + if (Files.isDirectory(p)) { + FileUtils.deleteFileTreeWithRetry(p); + } else { + FileUtils.deleteFileIfExistsWithRetry(p); + } + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } +} \ No newline at end of file diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java new file mode 100644 index 0000000000000..cf910445abf3b --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.BiConsumer; +import static java.util.stream.Collectors.toSet; +import java.util.stream.Stream; +import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.Test; +import static jdk.jpackage.test.DirectoryContentVerifierTest.AssertType.CONTAINS; +import static jdk.jpackage.test.DirectoryContentVerifierTest.AssertType.MATCH; +import jdk.jpackage.test.TKit.DirectoryContentVerifier; +import static jdk.jpackage.test.TKit.assertAssert; + +/* + * @test + * @summary Test TKit.DirectoryContentVerifier from jpackage test library + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @modules jdk.jpackage/jdk.jpackage.internal + * @compile DirectoryContentVerifierTest.java + * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=jdk.jpackage.test.DirectoryContentVerifierTest + */ +public class DirectoryContentVerifierTest { + + enum AssertType { + MATCH(DirectoryContentVerifier::match), + CONTAINS(DirectoryContentVerifier::contains), + ; + + AssertType(BiConsumer> assertFunc) { + this.assertFunc = assertFunc; + } + + private final BiConsumer> assertFunc; + } + + private static ArgsBuilder buildArgs() { + return new ArgsBuilder(); + } + + private static class ArgsBuilder { + + void applyTo(List data) { + data.add(new Object[]{expectedPaths, actualPaths, assertOp, success}); + } + + void applyVariantsTo(List data) { + applyTo(data); + boolean pathGroupsEqual = List.of(expectedPaths).equals(List.of(actualPaths)); + if (assertOp == MATCH) { + if (!pathGroupsEqual) { + data.add(new Object[]{actualPaths, expectedPaths, MATCH, success}); + } + if (success) { + data.add(new Object[]{expectedPaths, actualPaths, CONTAINS, success}); + if (!pathGroupsEqual) { + data.add(new Object[]{actualPaths, expectedPaths, CONTAINS, success}); + } + } + } + } + + ArgsBuilder expectedPaths(String... paths) { + expectedPaths = paths; + return this; + } + + ArgsBuilder actualPaths(String... paths) { + actualPaths = paths; + return this; + } + + ArgsBuilder assertOp(AssertType v) { + assertOp = v; + return this; + } + + ArgsBuilder expectFail() { + success = false; + return this; + } + + private String[] expectedPaths = new String[0]; + private String[] actualPaths = new String[0]; + private AssertType assertOp = MATCH; + private boolean success = true; + } + + @Parameters + public static Collection input() { + List data = new ArrayList<>(); + buildArgs().applyVariantsTo(data); + buildArgs().actualPaths("foo").assertOp(CONTAINS).applyTo(data); + buildArgs().actualPaths("zoo").expectFail().applyVariantsTo(data); + buildArgs().actualPaths("boo").expectedPaths("boo").applyVariantsTo(data); + if (TKit.isWindows()) { + buildArgs().actualPaths("moo").expectedPaths("Moo").applyVariantsTo(data); + } else { + buildArgs().actualPaths("moo").expectedPaths("Moo").expectFail().applyVariantsTo(data); + } + buildArgs().actualPaths("hello").expectedPaths().expectFail().applyVariantsTo(data); + buildArgs().actualPaths("123").expectedPaths("456").expectFail().applyVariantsTo(data); + buildArgs().actualPaths("a", "b", "c").expectedPaths("b", "a", "c").applyVariantsTo(data); + buildArgs().actualPaths("AA", "BB", "CC").expectedPaths("BB", "AA").expectFail().applyVariantsTo(data); + buildArgs().actualPaths("AA", "BB", "CC").expectedPaths("BB", "AA").assertOp(CONTAINS).applyTo(data); + buildArgs().actualPaths("AA", "BB", "CC").expectedPaths("BB", "DD", "AA").expectFail().assertOp(CONTAINS).applyTo(data); + buildArgs().actualPaths("AA", "BB", "CC").expectedPaths("BB", "DD", "AA").expectFail().applyTo(data); + return data; + } + + public DirectoryContentVerifierTest(String[] expectedPaths, String[] actualPaths, + AssertType assertOp, Boolean success) { + this.expectedPaths = conv(expectedPaths); + this.actualPaths = conv(actualPaths); + this.assertOp = assertOp; + this.success = success; + } + + @Test + public void test() { + TKit.withTempDirectory("basedir", this::test); + } + + private void test(Path basedir) throws IOException { + for (var path : actualPaths) { + Files.createFile(basedir.resolve(path)); + } + + var testee = TKit.assertDirectoryContent(basedir); + + assertAssert(success, () -> assertOp.assertFunc.accept(testee, expectedPaths)); + } + + private static Set conv(String... paths) { + return Stream.of(paths).map(Path::of).collect(toSet()); + } + + private final Set expectedPaths; + private final Set actualPaths; + private final AssertType assertOp; + private final boolean success; +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CommandArguments.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CommandArguments.java index 5b4cf3aef71c7..e594191893812 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CommandArguments.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CommandArguments.java @@ -34,30 +34,35 @@ public class CommandArguments { args = new ArrayList<>(); } - final public T addArgument(String v) { + public final T clearArguments() { + args.clear(); + return (T) this; + } + + public final T addArgument(String v) { args.add(v); return (T) this; } - final public T addArguments(List v) { + public final T addArguments(List v) { args.addAll(v); return (T) this; } - final public T addArgument(Path v) { + public final T addArgument(Path v) { return addArgument(v.toString()); } - final public T addArguments(String... v) { + public final T addArguments(String... v) { return addArguments(Arrays.asList(v)); } - final public T addPathArguments(List v) { + public final T addPathArguments(List v) { return addArguments(v.stream().map((p) -> p.toString()).collect( Collectors.toList())); } - final public List getAllArguments() { + public final List getAllArguments() { return List.copyOf(args); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index fd62d6c7d8820..99cb61b17d37d 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.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 @@ -52,6 +52,7 @@ import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingFunction; +import jdk.jpackage.test.Functional.ThrowingRunnable; import jdk.jpackage.test.Functional.ThrowingSupplier; /** @@ -76,6 +77,8 @@ public JPackageCommand(JPackageCommand cmd) { immutable = cmd.immutable; prerequisiteActions = new Actions(cmd.prerequisiteActions); verifyActions = new Actions(cmd.verifyActions); + appLayoutAsserts = cmd.appLayoutAsserts; + executeInDirectory = cmd.executeInDirectory; } JPackageCommand createImmutableCopy() { @@ -198,7 +201,10 @@ public PackageType packageType() { } public Path outputDir() { - return getArgumentValue("--dest", () -> Path.of("."), Path::of); + var path = getArgumentValue("--dest", () -> Path.of("."), Path::of); + return Optional.ofNullable(executeInDirectory).map(base -> { + return base.resolve(path); + }).orElse(path); } public Path inputDir() { @@ -402,12 +408,14 @@ public JPackageCommand setDefaultAppName() { public Path outputBundle() { final String bundleName; if (isImagePackageType()) { - if (TKit.isOSX() && hasArgument("--app-image")) { - return Path.of(getArgumentValue("--app-image", () -> null)); - } - String dirName = name(); - if (TKit.isOSX()) { - dirName = dirName + ".app"; + String dirName; + if (!TKit.isOSX()) { + dirName = name(); + } else if (hasArgument("--app-image") && hasArgument("--mac-sign")) { + // Request to sign external app image, not to build a new one + dirName = getArgumentValue("--app-image"); + } else { + dirName = name() + ".app"; } bundleName = dirName; } else if (TKit.isLinux()) { @@ -691,6 +699,12 @@ public JPackageCommand useToolProvider(boolean v) { return this; } + public JPackageCommand setDirectory(Path v) { + verifyMutable(); + executeInDirectory = v; + return this; + } + public JPackageCommand saveConsoleOutput(boolean v) { verifyMutable(); saveConsoleOutput = v; @@ -733,6 +747,7 @@ public JPackageCommand executeVerifyActions() { private Executor createExecutor() { Executor exec = new Executor() .saveOutput(saveConsoleOutput).dumpOutput(!suppressOutput) + .setDirectory(executeInDirectory) .addArguments(args); if (isWithToolProvider()) { @@ -755,18 +770,19 @@ public Executor.Result execute(int expectedExitCode) { executePrerequisiteActions(); if (hasArgument("--dest")) { - if (isImagePackageType()) { - TKit.deleteDirectoryContentsRecursive(outputDir()); - } else { - nullableOutputBundle().ifPresent(path -> { - if (ThrowingSupplier.toSupplier(() -> TKit.deleteIfExists( - path)).get()) { + nullableOutputBundle().ifPresent(path -> { + ThrowingRunnable.toRunnable(() -> { + if (Files.isDirectory(path)) { + TKit.deleteDirectoryRecursive(path, String.format( + "Delete [%s] folder before running jpackage", + path)); + } else if (TKit.deleteIfExists(path)) { TKit.trace(String.format( "Deleted [%s] file before running jpackage", path)); } - }); - } + }).run(); + }); } Path resourceDir = getArgumentValue("--resource-dir", () -> null, Path::of); @@ -816,22 +832,69 @@ public JPackageCommand assertImageCreated() { return this; } - JPackageCommand assertAppLayout() { - assertAppImageFile(); - assertPackageFile(); - - TKit.assertDirectoryExists(appRuntimeDirectory()); - - if (!isRuntime()) { - TKit.assertExecutableFileExists(appLauncherPath()); - TKit.assertFileExists(appLauncherCfgPath(null)); - + public static enum AppLayoutAssert { + APP_IMAGE_FILE(JPackageCommand::assertAppImageFile), + PACKAGE_FILE(JPackageCommand::assertPackageFile), + MAIN_LAUNCHER(cmd -> { + if (cmd.isRuntime()) { + TKit.assertPathExists(convertFromRuntime(cmd).appLauncherPath(), false); + } else { + TKit.assertExecutableFileExists(cmd.appLauncherPath()); + } + }), + MAIN_LAUNCHER_CFG_FILE(cmd -> { + if (cmd.isRuntime()) { + TKit.assertPathExists(convertFromRuntime(cmd).appLauncherCfgPath(null), false); + } else { + TKit.assertFileExists(cmd.appLauncherCfgPath(null)); + } + }), + RUNTIME_DIRECTORY(cmd -> { + TKit.assertDirectoryExists(cmd.appRuntimeDirectory()); if (TKit.isOSX()) { - TKit.assertFileExists(appRuntimeDirectory().resolve( - "Contents/MacOS/libjli.dylib")); + var libjliPath = cmd.appRuntimeDirectory().resolve("Contents/MacOS/libjli.dylib"); + if (cmd.isRuntime()) { + TKit.assertPathExists(libjliPath, false); + } else { + TKit.assertFileExists(libjliPath); + } } + }), + MAC_BUNDLE_STRUCTURE(cmd -> { + if (TKit.isOSX()) { + MacHelper.verifyBundleStructure(cmd); + } + }), + ; + + AppLayoutAssert(Consumer action) { + this.action = action; + } + + private static JPackageCommand convertFromRuntime(JPackageCommand cmd) { + var copy = new JPackageCommand(cmd); + copy.immutable = false; + copy.removeArgumentWithValue("--runtime-image"); + return copy; } + private final Consumer action; + } + + public JPackageCommand setAppLayoutAsserts(AppLayoutAssert ... asserts) { + appLayoutAsserts = Set.of(asserts); + return this; + } + + public JPackageCommand excludeAppLayoutAsserts(AppLayoutAssert... asserts) { + return setAppLayoutAsserts(Stream.of(asserts).filter(Predicate.not( + appLayoutAsserts::contains)).toArray(AppLayoutAssert[]::new)); + } + + JPackageCommand assertAppLayout() { + for (var appLayoutAssert : appLayoutAsserts.stream().sorted().toList()) { + appLayoutAssert.action.accept(this); + } return this; } @@ -1111,9 +1174,11 @@ public void run() { private boolean immutable; private final Actions prerequisiteActions; private final Actions verifyActions; + private Path executeInDirectory; + private Set appLayoutAsserts = Set.of(AppLayoutAssert.values()); private static boolean defaultWithToolProvider; - private final static Map PACKAGE_TYPES = Functional.identity( + private static final Map PACKAGE_TYPES = Functional.identity( () -> { Map reply = new HashMap<>(); for (PackageType type : PackageType.values()) { @@ -1122,7 +1187,7 @@ public void run() { return reply; }).get(); - public final static Path DEFAULT_RUNTIME_IMAGE = Functional.identity(() -> { + public static final Path DEFAULT_RUNTIME_IMAGE = Functional.identity(() -> { // Set the property to the path of run-time image to speed up // building app images and platform bundles by avoiding running jlink // The value of the property will be automativcally appended to @@ -1135,5 +1200,5 @@ public void run() { return null; }).get(); - private final static String UNPACKED_PATH_ARGNAME = "jpt-unpacked-folder"; + private static final String UNPACKED_PATH_ARGNAME = "jpt-unpacked-folder"; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java index 6a798012ca78a..5b49b01a443b0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -216,7 +216,9 @@ public static JavaAppDesc parse(final String javaAppDesc) { components[0].length() - 1); desc.setWithMainClass(true); } - desc.setClassName(components[0]); + if (!components[0].isEmpty()) { + desc.setClassName(components[0]); + } if (components.length == 2) { desc.setModuleVersion(components[1]); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index ded548aface4d..8068e1d858f48 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.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 @@ -35,6 +35,7 @@ import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -257,6 +258,20 @@ static PackageHandlers createPkgPackageHandlers() { return pkg; } + static void verifyBundleStructure(JPackageCommand cmd) { + Path bundleRoot; + if (cmd.isImagePackageType()) { + bundleRoot = cmd.outputBundle(); + } else { + bundleRoot = cmd.pathToUnpackedPackageFile( + cmd.appInstallationDirectory()); + } + + TKit.assertDirectoryContent(bundleRoot).match(Path.of("Contents")); + TKit.assertDirectoryContent(bundleRoot.resolve("Contents")).match( + cmd.isRuntime() ? RUNTIME_BUNDLE_CONTENTS : APP_BUNDLE_CONTENTS); + } + static String getBundleName(JPackageCommand cmd) { cmd.verifyIsOfType(PackageType.MAC); return String.format("%s-%s%s", getPackageName(cmd), cmd.version(), @@ -390,5 +405,19 @@ private static Method initGetServicePListFileName() { static final Set CRITICAL_RUNTIME_FILES = Set.of(Path.of( "Contents/Home/lib/server/libjvm.dylib")); - private final static Method getServicePListFileName = initGetServicePListFileName(); + private static final Method getServicePListFileName = initGetServicePListFileName(); + + private static final Set APP_BUNDLE_CONTENTS = Stream.of( + "Info.plist", + "MacOS", + "app", + "runtime", + "Resources", + "PkgInfo", + "_CodeSignature" + ).map(Path::of).collect(toSet()); + + private static final Set RUNTIME_BUNDLE_CONTENTS = Stream.of( + "Home" + ).map(Path::of).collect(toSet()); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index d597c62d83f17..7882d4cd92d09 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.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 @@ -127,6 +127,15 @@ public PackageTest setExpectedExitCode(int v) { return this; } + public PackageTest ignoreBundleOutputDir() { + return ignoreBundleOutputDir(true); + } + + public PackageTest ignoreBundleOutputDir(boolean v) { + ignoreBundleOutputDir = v; + return this; + } + private PackageTest addInitializer(ThrowingConsumer v, String id) { if (id != null) { @@ -368,7 +377,7 @@ protected void runAction(Action... action) { private final List> handlers; } - final static class PackageHandlers { + static final class PackageHandlers { Consumer installHandler; Consumer uninstallHandler; BiFunction unpackHandler; @@ -528,7 +537,7 @@ private void handleAction(Action action, T handler, private final JPackageCommand cmd = Functional.identity(() -> { JPackageCommand result = new JPackageCommand(); result.setDefaultInputOutput().setDefaultAppName(); - if (BUNDLE_OUTPUT_DIR != null) { + if (BUNDLE_OUTPUT_DIR != null && !ignoreBundleOutputDir) { result.setArgumentValue("--dest", BUNDLE_OUTPUT_DIR.toString()); } type.applyTo(result); @@ -777,8 +786,9 @@ private static Map createDefaultPackageHandlers() private Map handlers; private Set namedInitializers; private Map packageHandlers; + private boolean ignoreBundleOutputDir; - private final static File BUNDLE_OUTPUT_DIR; + private static final File BUNDLE_OUTPUT_DIR; static { final String propertyName = "output"; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index 297cf3ec36e47..ca1224aafd78c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.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 @@ -40,10 +40,12 @@ import java.nio.file.WatchService; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -57,13 +59,14 @@ import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; import jdk.jpackage.test.Functional.ExceptionBox; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingRunnable; import jdk.jpackage.test.Functional.ThrowingSupplier; -final public class TKit { +public final class TKit { private static final String OS = System.getProperty("os.name").toLowerCase(); @@ -84,7 +87,7 @@ final public class TKit { return TEST_SRC_ROOT.resolve("../../../../src/jdk.jpackage").normalize().toAbsolutePath(); }).get(); - public final static String ICON_SUFFIX = Functional.identity(() -> { + public static final String ICON_SUFFIX = Functional.identity(() -> { if (isOSX()) { return ".icns"; } @@ -273,7 +276,23 @@ public static void error(String v) { throw new AssertionError(v); } - private final static String TEMP_FILE_PREFIX = null; + static void assertAssert(boolean expectedSuccess, Runnable runnable) { + try { + runnable.run(); + } catch (AssertionError err) { + if (expectedSuccess) { + assertUnexpected("Assertion failed"); + } else { + return; + } + } + + if (!expectedSuccess) { + assertUnexpected("Assertion passed"); + } + } + + private static final String TEMP_FILE_PREFIX = null; private static Path createUniqueFileName(String defaultName) { final String[] nameComponents; @@ -296,7 +315,9 @@ private static Path createUniqueFileName(String defaultName) { if (!path.toFile().exists()) { return path; } - nameComponents[0] = String.format("%s.%d", baseName, i); + // Don't use period (.) as a separator. OSX codesign fails to sign folders + // with subfolders with names like "input.0". + nameComponents[0] = String.format("%s-%d", baseName, i); } throw new IllegalStateException(String.format( "Failed to create unique file name from [%s] basename after %d attempts", @@ -379,7 +400,7 @@ public void accept(Path root) { try { final List paths; if (contentsOnly) { - try (var pathStream = Files.walk(root, 0)) { + try (var pathStream = Files.list(root)) { paths = pathStream.collect(Collectors.toList()); } } else { @@ -673,26 +694,40 @@ public static void assertPathExists(Path path, boolean exists) { assertTrue(path.toFile().exists(), String.format( "Check [%s] path exists", path)); } else { - assertFalse(path.toFile().exists(), String.format( + assertTrue(!path.toFile().exists(), String.format( "Check [%s] path doesn't exist", path)); } } - public static void assertPathNotEmptyDirectory(Path path) { - if (Files.isDirectory(path)) { + public static void assertDirectoryNotEmpty(Path path) { + assertDirectoryExists(path, Optional.of(false)); + } + + public static void assertDirectoryEmpty(Path path) { + assertDirectoryExists(path, Optional.of(true)); + } + + public static void assertDirectoryExists(Path path, Optional isEmptyCheck) { + assertPathExists(path, true); + boolean isDirectory = Files.isDirectory(path); + if (isEmptyCheck.isEmpty() || !isDirectory) { + assertTrue(isDirectory, String.format("Check [%s] is a directory", path)); + } else { ThrowingRunnable.toRunnable(() -> { try (var files = Files.list(path)) { - TKit.assertFalse(files.findFirst().isEmpty(), String.format - ("Check [%s] is not an empty directory", path)); + boolean actualIsEmpty = files.findFirst().isEmpty(); + if (isEmptyCheck.get()) { + TKit.assertTrue(actualIsEmpty, String.format("Check [%s] is not an empty directory", path)); + } else { + TKit.assertTrue(!actualIsEmpty, String.format("Check [%s] is an empty directory", path)); + } } }).run(); - } + } } public static void assertDirectoryExists(Path path) { - assertPathExists(path, true); - assertTrue(path.toFile().isDirectory(), String.format( - "Check [%s] is a directory", path)); + assertDirectoryExists(path, Optional.empty()); } public static void assertSymbolicLinkExists(Path path) { @@ -724,6 +759,101 @@ public static void assertUnexpected(String msg) { error(concatMessages("Unexpected", msg)); } + public static DirectoryContentVerifier assertDirectoryContent(Path dir) { + return new DirectoryContentVerifier(dir); + } + + public static final class DirectoryContentVerifier { + public DirectoryContentVerifier(Path baseDir) { + this(baseDir, ThrowingSupplier.toSupplier(() -> { + try (var files = Files.list(baseDir)) { + return files.map(Path::getFileName).collect(toSet()); + } + }).get()); + } + + public void match(Path ... expected) { + DirectoryContentVerifier.this.match(Set.of(expected)); + } + + public void match(Set expected) { + currentTest.notifyAssert(); + + var comm = Comm.compare(content, expected); + if (!comm.unique1.isEmpty() && !comm.unique2.isEmpty()) { + error(String.format( + "assertDirectoryContentEquals(%s): Some expected %s. Unexpected %s. Missing %s", + baseDir, format(comm.common), format(comm.unique1), format(comm.unique2))); + } else if (!comm.unique1.isEmpty()) { + error(String.format( + "assertDirectoryContentEquals%s: Expected %s. Unexpected %s", + baseDir, format(comm.common), format(comm.unique1))); + } else if (!comm.unique2.isEmpty()) { + error(String.format( + "assertDirectoryContentEquals(%s): Some expected %s. Missing %s", + baseDir, format(comm.common), format(comm.unique2))); + } else { + traceAssert(String.format( + "assertDirectoryContentEquals(%s): Expected %s", + baseDir, format(expected))); + } + } + + public void contains(Path ... expected) { + contains(Set.of(expected)); + } + + public void contains(Set expected) { + currentTest.notifyAssert(); + + var comm = Comm.compare(content, expected); + if (!comm.unique2.isEmpty()) { + error(String.format( + "assertDirectoryContentContains(%s): Some expected %s. Missing %s", + baseDir, format(comm.common), format(comm.unique2))); + } else { + traceAssert(String.format( + "assertDirectoryContentContains(%s): Expected %s", + baseDir, format(expected))); + } + } + + public DirectoryContentVerifier removeAll(Path ... paths) { + Set newContent = new HashSet<>(content); + newContent.removeAll(List.of(paths)); + return new DirectoryContentVerifier(baseDir, newContent); + } + + private DirectoryContentVerifier(Path baseDir, Set contents) { + this.baseDir = baseDir; + this.content = contents; + } + + private static record Comm(Set common, Set unique1, Set unique2) { + static Comm compare(Set a, Set b) { + Set common = new HashSet<>(a); + common.retainAll(b); + + Set unique1 = new HashSet<>(a); + unique1.removeAll(common); + + Set unique2 = new HashSet<>(b); + unique2.removeAll(common); + + return new Comm(common, unique1, unique2); + } + } + + private static String format(Set paths) { + return Arrays.toString( + paths.stream().sorted().map(Path::toString).toArray( + String[]::new)); + } + + private final Path baseDir; + private final Set content; + } + public static void assertStringListEquals(List expected, List actual, String msg) { currentTest.notifyAssert(); @@ -801,7 +931,7 @@ public void close() throws IOException { }; } - public final static class TextStreamVerifier { + public static final class TextStreamVerifier { TextStreamVerifier(String value) { this.value = value; predicate(String::contains); @@ -864,7 +994,7 @@ public void apply(Stream lines) { private String label; private boolean negate; private Supplier createException; - final private String value; + private final String value; } public static TextStreamVerifier assertTextStream(String what) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java index 27da5a0a28cec..bb699ba3b9c9f 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java @@ -392,6 +392,9 @@ private static Stream toMethodCalls(Object[] ctorArgs, Method method } private static Object fromString(String value, Class toType) { + if (toType.isEnum()) { + return Enum.valueOf(toType, value); + } Function converter = conv.get(toType); if (converter == null) { throw new RuntimeException(String.format( diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java index 1a4dbd22897bf..b7fd904325d37 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -322,7 +322,7 @@ private void verifyStartMenuShortcut(Path shortcutsRoot, boolean exists) { Path shortcutPath = shortcutsRoot.resolve(startMenuShortcutPath); verifyShortcut(shortcutPath, exists); if (!exists) { - TKit.assertPathNotEmptyDirectory(shortcutPath.getParent()); + TKit.assertDirectoryNotEmpty(shortcutPath.getParent()); } } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java index 53fe04509b03c..18ca883679098 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,12 +22,9 @@ */ package jdk.jpackage.internal; -import java.nio.file.Path; -import java.io.IOException; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Rule; -import org.junit.Before; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; @@ -40,11 +37,6 @@ public class DeployParamsTest { @Rule public final ExpectedException thrown = ExpectedException.none(); - @Before - public void setUp() throws IOException { - testRoot = tempFolder.newFolder().toPath(); - } - @Test public void testValidAppName() throws PackagerException { initParamsAppName(); @@ -115,7 +107,6 @@ public void describeTo(Description d) { private void initParamsAppName() { params = new DeployParams(); - params.setOutput(testRoot); params.addBundleArgument(Arguments.CLIOptions.APPCLASS.getId(), "TestClass"); params.addBundleArgument(Arguments.CLIOptions.MAIN_JAR.getId(), @@ -128,6 +119,5 @@ private void setAppNameAndValidate(String appName) throws PackagerException { params.validate(); } - private Path testRoot = null; private DeployParams params; } diff --git a/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java index 9db836af99238..9d6cd6472ba73 100644 --- a/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java @@ -32,6 +32,11 @@ * @test * @summary Test jpackage signing options errors * @library ../helpers + * @library /test/lib + * @library base + * @build SigningBase + * @build SigningCheck + * @build jtreg.SkippedException * @build SigningOptionsTest * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") @@ -44,6 +49,11 @@ * @test * @summary Test jpackage signing options errors * @library ../helpers + * @library /test/lib + * @library base + * @build SigningBase + * @build SigningCheck + * @build jtreg.SkippedException * @build SigningOptionsTest * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") @@ -69,40 +79,59 @@ public static Collection input() { "--mac-signing-key-user-name", "test-key", "--mac-app-image-sign-identity", "test-identity"}, null, - "Mutually exclusive options"}, + "Mutually exclusive options", + Boolean.FALSE}, // --mac-signing-key-user-name and --mac-installer-sign-identity {"Hello", new String[]{"--mac-sign", "--mac-signing-key-user-name", "test-key", "--mac-installer-sign-identity", "test-identity"}, null, - "Mutually exclusive options"}, + "Mutually exclusive options", + Boolean.FALSE}, // --mac-installer-sign-identity and --type app-image {"Hello", new String[]{"--mac-sign", "--mac-installer-sign-identity", "test-identity"}, null, - "Option [--mac-installer-sign-identity] is not valid with type"}, + "Option [--mac-installer-sign-identity] is not valid with type", + Boolean.FALSE}, // --mac-installer-sign-identity and --type dmg {"Hello", new String[]{"--type", "dmg", "--mac-sign", "--mac-installer-sign-identity", "test-identity"}, new String[]{"--type"}, - "Option [--mac-installer-sign-identity] is not valid with type"}, + "Option [--mac-installer-sign-identity] is not valid with type", + Boolean.FALSE}, // --app-content and --type app-image + // JDK-8340802: "codesign" may or may not fail if additional + // content is specified based on macOS version. For example on + // macOS 15 aarch64 "codesign" will not fail with additional content. + // Since we only need to check that warning is displayed when + // "codesign" fails and "--app-content" is provided, lets fail + // "codesign" for some better reason like identity which does not + // exists. {"Hello", - new String[]{"--app-content", TEST_DUKE}, + new String[]{"--app-content", TEST_DUKE, + "--mac-sign", + "--mac-app-image-sign-identity", "test-identity"}, null, "\"codesign\" failed and additional application content" + - " was supplied via the \"--app-content\" parameter."}, + " was supplied via the \"--app-content\" parameter.", + Boolean.TRUE}, }); } public SigningOptionsTest(String javaAppDesc, String[] jpackageArgs, - String[] removeArgs, String expectedError) { + String[] removeArgs, String expectedError, + Boolean checkRequirements) { this.expectedError = expectedError; + if (checkRequirements) { + SigningCheck.isXcodeDevToolsInstalled(); + } + cmd = JPackageCommand.helloAppImage(javaAppDesc) .saveConsoleOutput(true).dumpOutput(true); if (jpackageArgs != null) { diff --git a/test/jdk/tools/jpackage/macosx/base/SigningCheck.java b/test/jdk/tools/jpackage/macosx/base/SigningCheck.java index fc8a274caf828..4ba2763804f06 100644 --- a/test/jdk/tools/jpackage/macosx/base/SigningCheck.java +++ b/test/jdk/tools/jpackage/macosx/base/SigningCheck.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 @@ -25,6 +25,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.io.IOException; import jdk.jpackage.test.TKit; import jdk.jpackage.test.Executor; @@ -89,4 +90,12 @@ private static void validateCertificateTrust(String name) { .apply(result.stream()); } + public static void isXcodeDevToolsInstalled() { + int code = Executor.of("/usr/bin/xcrun", "--help") + .executeWithoutExitCodeCheck().getExitCode(); + if (code != 0) { + TKit.throwSkippedException("Missing Xcode with command line developer tools"); + } + } + } diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index b31a6e637b292..943625307511a 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,22 +21,25 @@ * questions. */ -import java.nio.file.Path; +import java.io.IOException; import java.nio.file.Files; -import jdk.jpackage.internal.ApplicationLayout; +import java.nio.file.Path; import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Parameters; import java.util.Arrays; import java.util.Collection; import java.util.List; +import static java.util.stream.Collectors.joining; +import java.util.stream.Stream; +import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.test.Functional.ThrowingFunction; +import jdk.jpackage.test.JPackageCommand; /** - * Tests generation of packages with input folder containing empty folders. + * Tests generation of packages with additional content in app image. */ /* @@ -48,19 +51,24 @@ * @build jdk.jpackage.test.* * @build AppContentTest * @modules jdk.jpackage/jdk.jpackage.internal + * @modules java.base/jdk.internal.util * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppContentTest */ public class AppContentTest { - private static final String TEST_JAVA = TKit.TEST_SRC_ROOT.resolve( - "apps/PrintEnv.java").toString(); - private static final String TEST_DUKE = TKit.TEST_SRC_ROOT.resolve( - "apps/dukeplug.png").toString(); - private static final String TEST_DIR = TKit.TEST_SRC_ROOT.resolve( - "apps").toString(); - private static final String TEST_BAD = TKit.TEST_SRC_ROOT.resolve( - "non-existant").toString(); + private static final String TEST_JAVA = "apps/PrintEnv.java"; + private static final String TEST_DUKE = "apps/dukeplug.png"; + private static final String TEST_DIR = "apps"; + private static final String TEST_BAD = "non-existant"; + + // On OSX `--app-content` paths will be copied into the "Contents" folder + // of the output app image. + // "codesign" imposes restrictions on the directory structure of "Contents" folder. + // In particular, random files should be placed in "Contents/Resources" folder + // otherwise "codesign" will fail to sign. + // Need to prepare arguments for `--app-content` accordingly. + private final static boolean copyInResources = TKit.isOSX(); private final List testPathArgs; @@ -80,28 +88,90 @@ public AppContentTest(String... testPathArgs) { @Test public void test() throws Exception { + final int expectedJPackageExitCode; + if (testPathArgs.contains(TEST_BAD)) { + expectedJPackageExitCode = 1; + } else { + expectedJPackageExitCode = 0; + } + + var appContentInitializer = new AppContentInitializer(testPathArgs); new PackageTest().configureHelloApp() - .addInitializer(cmd -> { - for (String arg : testPathArgs) { - cmd.addArguments("--app-content", arg); - } - }) + .addRunOnceInitializer(appContentInitializer::initAppContent) + .addInitializer(appContentInitializer::applyTo) .addInstallVerifier(cmd -> { - ApplicationLayout appLayout = cmd.appLayout(); - Path contentDir = appLayout.contentDirectory(); + Path baseDir = getAppContentRoot(cmd); for (String arg : testPathArgs) { List paths = Arrays.asList(arg.split(",")); for (String p : paths) { Path name = Path.of(p).getFileName(); - TKit.assertPathExists(contentDir.resolve(name), true); + TKit.assertPathExists(baseDir.resolve(name), true); } } }) - // On macOS we always signing app image and signing will fail, since - // test produces invalid app bundle. - .setExpectedExitCode(testPathArgs.contains(TEST_BAD) || TKit.isOSX() ? 1 : 0) + .setExpectedExitCode(expectedJPackageExitCode) .run(); + } + + private static Path getAppContentRoot(JPackageCommand cmd) { + Path contentDir = cmd.appLayout().contentDirectory(); + if (copyInResources) { + return contentDir.resolve("Resources"); + } else { + return contentDir; + } + } + + private static final class AppContentInitializer { + AppContentInitializer(List appContentArgs) { + appContentPathGroups = appContentArgs.stream().map(arg -> { + return Stream.of(arg.split(",")).map(Path::of).toList(); + }).toList(); + } + + void initAppContent() { + jpackageArgs = appContentPathGroups.stream() + .map(AppContentInitializer::initAppContentPaths) + .mapMulti((appContentPaths, consumer) -> { + consumer.accept("--app-content"); + consumer.accept( + appContentPaths.stream().map(Path::toString).collect( + joining(","))); + }).toList(); + } + + void applyTo(JPackageCommand cmd) { + cmd.addArguments(jpackageArgs); + } + + private static Path copyAppContentPath(Path appContentPath) throws IOException { + var appContentArg = TKit.createTempDirectory("app-content").resolve("Resources"); + var srcPath = TKit.TEST_SRC_ROOT.resolve(appContentPath); + var dstPath = appContentArg.resolve(srcPath.getFileName()); + Files.createDirectories(dstPath.getParent()); + IOUtils.copyRecursive(srcPath, dstPath); + return appContentArg; + } + + private static List initAppContentPaths(List appContentPaths) { + if (copyInResources) { + return appContentPaths.stream().map(appContentPath -> { + if (appContentPath.endsWith(TEST_BAD)) { + return appContentPath; + } else { + return ThrowingFunction.toFunction( + AppContentInitializer::copyAppContentPath).apply( + appContentPath); + } + }).toList(); + } else { + return appContentPaths.stream().map(TKit.TEST_SRC_ROOT::resolve).toList(); + } } + + private List jpackageArgs; + private final List> appContentPathGroups; + } } diff --git a/test/jdk/tools/jpackage/share/EmptyFolderBase.java b/test/jdk/tools/jpackage/share/EmptyFolderBase.java deleted file mode 100644 index 092996ad03909..0000000000000 --- a/test/jdk/tools/jpackage/share/EmptyFolderBase.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import jdk.jpackage.test.TKit; - -public class EmptyFolderBase { - - // Note: To specify file use ".txt" extension. - // Note: createDirStrcture() will call mkdir() or createNewFile() for paths defined - // in dirStruct, so make sure paths are defined in order. - - // folder-empty - // folder-not-empty - // folder-not-empty/folder-empty - // folder-not-empty/another-folder-empty - // folder-not-empty/folder-non-empty2 - // folder-not-empty/folder-non-empty2/file.txt - private static final String [] DIR_STRUCT = { - "folder-empty", - "folder-not-empty", - "folder-not-empty" + File.separator + "folder-empty", - "folder-not-empty" + File.separator + "another-folder-empty", - "folder-not-empty" + File.separator + "folder-non-empty2", - "folder-not-empty" + File.separator + "folder-non-empty2" + File.separator + - "file.txt" - }; - - // See dirStruct - public static void createDirStrcture(Path inputPath) throws IOException { - File input = new File(inputPath.toString()); - input.mkdir(); - - for (String p : DIR_STRUCT) { - File f = new File(input, p); - if (p.endsWith(".txt")) { - f.createNewFile(); - } else { - f.mkdir(); - } - } - } - - public static void validateDirStrcture(Path appDirPath) { - for (String p : DIR_STRUCT) { - Path path = appDirPath.resolve(p); - TKit.assertPathExists(path, true); - } - } -} diff --git a/test/jdk/tools/jpackage/share/EmptyFolderPackageTest.java b/test/jdk/tools/jpackage/share/EmptyFolderPackageTest.java deleted file mode 100644 index c7af050c6850f..0000000000000 --- a/test/jdk/tools/jpackage/share/EmptyFolderPackageTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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.file.Path; -import jdk.jpackage.internal.ApplicationLayout; -import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.PackageType; -import jdk.jpackage.test.Annotations.Test; - -/** - * Tests generation of packages with input folder containing empty folders. - */ - -/* - * @test - * @summary jpackage with input containing empty folders - * @library ../helpers - * @library /test/lib - * @key jpackagePlatformPackage - * @build EmptyFolderBase - * @build jdk.jpackage.test.* - * @build EmptyFolderPackageTest - * @modules jdk.jpackage/jdk.jpackage.internal - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=EmptyFolderPackageTest - */ -public class EmptyFolderPackageTest { - - @Test - public static void test() throws Exception { - new PackageTest().configureHelloApp() - .addInitializer(cmd -> { - Path input = cmd.inputDir(); - EmptyFolderBase.createDirStrcture(input); - }) - .addInstallVerifier(cmd -> { - if (cmd.packageType() == PackageType.WIN_MSI) { - if (cmd.isPackageUnpacked("Not running file " - + "structure check for empty folders")) { - return; - } - } - - ApplicationLayout appLayout = cmd.appLayout(); - Path appDir = appLayout.appDirectory(); - EmptyFolderBase.validateDirStrcture(appDir); - }) - .run(); - } -} diff --git a/test/jdk/tools/jpackage/share/EmptyFolderTest.java b/test/jdk/tools/jpackage/share/EmptyFolderTest.java index a41c4a66702d1..230d8a039ea8d 100644 --- a/test/jdk/tools/jpackage/share/EmptyFolderTest.java +++ b/test/jdk/tools/jpackage/share/EmptyFolderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,44 +21,113 @@ * questions. */ +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; -import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.internal.ApplicationLayout; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.TKit; /** - * Tests generation of app image with input folder containing empty folders. + * Tests generation of packages and app image with input folder containing empty folders. + */ + +/* + * @test + * @summary jpackage for package with input containing empty folders + * @library ../helpers + * @library /test/lib + * @key jpackagePlatformPackage + * @build jdk.jpackage.test.* + * @build EmptyFolderTest + * @modules jdk.jpackage/jdk.jpackage.internal + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=EmptyFolderTest.testPackage */ /* * @test - * @summary jpackage with input containing empty folders + * @summary jpackage for app image with input containing empty folders * @library ../helpers * @library /test/lib - * @build EmptyFolderBase * @build jdk.jpackage.test.* * @build EmptyFolderTest * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm -Xmx512m jdk.jpackage.test.Main - * --jpt-run=EmptyFolderTest + * --jpt-run=EmptyFolderTest.testAppImage */ + public class EmptyFolderTest { @Test - public static void test() throws Exception { - JPackageCommand cmd = JPackageCommand.helloAppImage(); + public static void testPackage() { + new PackageTest() + .configureHelloApp() + .addInitializer(EmptyFolderTest::createDirTree) + .addInitializer(cmd -> { + cmd.setArgumentValue("--name", "EmptyFolderPackageTest"); + }) + .addInstallVerifier(EmptyFolderTest::validateDirTree) + .run(); + } + + @Test + public static void testAppImage() throws IOException { + var cmd = JPackageCommand.helloAppImage(); // Add more files into input folder - Path input = cmd.inputDir(); - EmptyFolderBase.createDirStrcture(input); + createDirTree(cmd); // Create app image cmd.executeAndAssertHelloAppImageCreated(); - // Verify directory strcture - ApplicationLayout appLayout = cmd.appLayout(); - Path appDir = appLayout.appDirectory(); - EmptyFolderBase.validateDirStrcture(appDir); + // Verify directory structure + validateDirTree(cmd); + } + + private static void createDirTree(JPackageCommand cmd) throws IOException { + var baseDir = cmd.inputDir(); + for (var path : DIR_STRUCT) { + path = baseDir.resolve(path); + if (isFile(path)) { + Files.createDirectories(path.getParent()); + Files.write(path, new byte[0]); + } else { + Files.createDirectories(path); + } + } + } + + private static void validateDirTree(JPackageCommand cmd) { + var outputBaseDir = cmd.appLayout().appDirectory(); + var inputBaseDir = cmd.inputDir(); + for (var path : DIR_STRUCT) { + Path outputPath = outputBaseDir.resolve(path); + if (isFile(outputPath)) { + TKit.assertFileExists(outputPath); + } else if (!PackageType.WINDOWS.contains(cmd.packageType())) { + TKit.assertDirectoryExists(outputPath); + } else if (inputBaseDir.resolve(path).toFile().list().length == 0) { + // MSI packages don't support empty folders + TKit.assertPathExists(outputPath, false); + } else { + TKit.assertDirectoryNotEmpty(outputPath); + } + } + } + + private static boolean isFile(Path path) { + return path.getFileName().toString().endsWith(".txt"); } + // Note: To specify file use ".txt" extension. + private static final Path [] DIR_STRUCT = { + Path.of("folder-empty"), + Path.of("folder-not-empty"), + Path.of("folder-not-empty", "folder-empty"), + Path.of("folder-not-empty", "another-folder-empty"), + Path.of("folder-not-empty", "folder-non-empty2", "file.txt") + }; } diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java new file mode 100644 index 0000000000000..699d88e318947 --- /dev/null +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -0,0 +1,266 @@ +/* + * 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.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import static java.util.stream.Collectors.toSet; +import java.util.stream.Stream; +import jdk.jpackage.internal.AppImageFile; +import jdk.jpackage.internal.ApplicationLayout; +import jdk.jpackage.internal.PackageFile; +import jdk.jpackage.test.Annotations; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Functional.ThrowingConsumer; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageCommand.AppLayoutAssert; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; +import jdk.jpackage.test.TKit; + +/* + * @test + * @summary Test jpackage command line with overlapping input and output paths + * @library ../helpers + * @build jdk.jpackage.test.* + * @modules jdk.jpackage/jdk.jpackage.internal + * @compile InOutPathTest.java + * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=InOutPathTest + */ +public final class InOutPathTest { + + @Annotations.Parameters + public static Collection input() { + List data = new ArrayList<>(); + + for (var packageTypes : List.of(PackageType.IMAGE.toString(), ALL_NATIVE_PACKAGE_TYPES)) { + data.addAll(List.of(new Object[][]{ + {packageTypes, wrap(InOutPathTest::outputDirInInputDir, "--dest in --input")}, + {packageTypes, wrap(InOutPathTest::outputDirSameAsInputDir, "--dest same as --input")}, + {packageTypes, wrap(InOutPathTest::tempDirInInputDir, "--temp in --input")}, + {packageTypes, wrap(cmd -> { + outputDirInInputDir(cmd); + tempDirInInputDir(cmd); + }, "--dest and --temp in --input")}, + })); + data.addAll(additionalContentInput(packageTypes, "--app-content")); + } + + data.addAll(List.of(new Object[][]{ + {PackageType.IMAGE.toString(), wrap(cmd -> { + additionalContent(cmd, "--app-content", cmd.outputBundle()); + }, "--app-content same as output bundle")}, + })); + + if (TKit.isOSX()) { + data.addAll(additionalContentInput(PackageType.MAC_DMG.toString(), + "--mac-dmg-content")); + } + + return data; + } + + private static List additionalContentInput(String packageTypes, String argName) { + List data = new ArrayList<>(); + + data.addAll(List.of(new Object[][]{ + {packageTypes, wrap(cmd -> { + additionalContent(cmd, argName, cmd.inputDir()); + }, argName + " same as --input")}, + })); + + if (!TKit.isOSX()) { + data.addAll(List.of(new Object[][]{ + {packageTypes, wrap(cmd -> { + additionalContent(cmd, argName, cmd.inputDir().resolve("foo")); + }, argName + " in --input")}, + {packageTypes, wrap(cmd -> { + additionalContent(cmd, argName, cmd.outputDir().resolve("bar")); + }, argName + " in --dest")}, + {packageTypes, wrap(cmd -> { + additionalContent(cmd, argName, cmd.outputDir()); + }, argName + " same as --dest")}, + {packageTypes, wrap(cmd -> { + tempDirInInputDir(cmd); + var tempDir = cmd.getArgumentValue("--temp"); + Files.createDirectories(Path.of(tempDir)); + cmd.addArguments(argName, tempDir); + }, argName + " as --temp; --temp in --input")}, + })); + } + + return data; + } + + public InOutPathTest(String packageTypes, Envelope configure) { + if (ALL_NATIVE_PACKAGE_TYPES.equals(packageTypes)) { + this.packageTypes = PackageType.NATIVE; + } else { + this.packageTypes = Stream.of(packageTypes.split(",")).map( + PackageType::valueOf).collect(toSet()); + } + this.configure = configure.value; + } + + @Test + public void test() throws Throwable { + runTest(packageTypes, configure); + } + + private static Envelope wrap(ThrowingConsumer v, String label) { + return new Envelope(v, label); + } + + private static boolean isAppImageValid(JPackageCommand cmd) { + return !cmd.hasArgument("--app-content") && !cmd.hasArgument("--mac-dmg-content"); + } + + private static void runTest(Set packageTypes, + ThrowingConsumer configure) throws Throwable { + ThrowingConsumer configureWrapper = cmd -> { + // Make sure the input directory is empty in every test run. + // This is needed because jpackage output directories in this test + // are subdirectories of the input directory. + cmd.setInputToEmptyDirectory(); + configure.accept(cmd); + if (cmd.hasArgument("--temp") && cmd.isImagePackageType()) { + // Request to build app image wit user supplied temp directory, + // ignore external runtime if any to make use of the temp directory + // for runtime generation. + cmd.ignoreDefaultRuntime(true); + } else { + cmd.setFakeRuntime(); + } + + if (!isAppImageValid(cmd)) { + // Standard asserts for .jpackage.xml fail in messed up app image. Disable them. + // Other standard asserts for app image contents should pass. + cmd.excludeAppLayoutAsserts(AppLayoutAssert.APP_IMAGE_FILE); + } + }; + + if (packageTypes.contains(PackageType.IMAGE)) { + JPackageCommand cmd = JPackageCommand.helloAppImage(JAR_PATH.toString() + ":"); + configureWrapper.accept(cmd); + cmd.executeAndAssertHelloAppImageCreated(); + if (isAppImageValid(cmd)) { + verifyAppImage(cmd); + } + } else { + new PackageTest() + .forTypes(packageTypes) + .configureHelloApp(JAR_PATH.toString() + ":") + .addInitializer(configureWrapper) + .addInstallVerifier(InOutPathTest::verifyAppImage) + .run(CREATE_AND_UNPACK); + } + } + + private static void outputDirInInputDir(JPackageCommand cmd) throws + IOException { + // Set output dir as a subdir of input dir + Path outputDir = cmd.inputDir().resolve("out"); + TKit.createDirectories(outputDir); + cmd.setArgumentValue("--dest", outputDir); + } + + private static void outputDirSameAsInputDir(JPackageCommand cmd) throws + IOException { + // Set output dir the same as the input dir + cmd.setArgumentValue("--dest", cmd.inputDir()); + } + + private static void tempDirInInputDir(JPackageCommand cmd) { + // Set temp dir as a subdir of input dir + Path tmpDir = cmd.inputDir().resolve("tmp"); + cmd.setArgumentValue("--temp", tmpDir); + } + + private static void additionalContent(JPackageCommand cmd, + String argName, Path base) throws IOException { + Path appContentFile = base.resolve(base.toString().replaceAll("[\\\\/]", + "-") + "-foo.txt"); + TKit.createDirectories(appContentFile.getParent()); + TKit.createTextFile(appContentFile, List.of("Hello Duke!")); + cmd.addArguments(argName, appContentFile.getParent()); + } + + private static void verifyAppImage(JPackageCommand cmd) throws IOException { + if (!isAppImageValid(cmd)) { + // Don't verify the contents of app image as it is invalid. + // jpackage exited without getting stuck in infinite spiral. + // No more expectations from the tool for the give arguments. + return; + } + + final Path rootDir = cmd.isImagePackageType() ? cmd.outputBundle() : cmd.pathToUnpackedPackageFile( + cmd.appInstallationDirectory()); + final Path appDir = ApplicationLayout.platformAppImage().resolveAt( + rootDir).appDirectory(); + + final var knownFiles = Set.of( + JAR_PATH.getName(0).toString(), + PackageFile.getPathInAppImage(Path.of("")).getFileName().toString(), + AppImageFile.getPathInAppImage(Path.of("")).getFileName().toString(), + cmd.name() + ".cfg" + ); + + TKit.assertFileExists(appDir.resolve(JAR_PATH)); + + try (Stream actualFilesStream = Files.list(appDir)) { + var unexpectedFiles = actualFilesStream.map(path -> { + return path.getFileName().toString(); + }).filter(Predicate.not(knownFiles::contains)).toList(); + TKit.assertStringListEquals(List.of(), unexpectedFiles, + "Check there are no unexpected files in `app` folder"); + } + } + + private static final record Envelope(ThrowingConsumer value, String label) { + @Override + public String toString() { + // Will produce the same test description for the same label every + // time it's executed. + // The test runner will keep the same test output directory. + return label; + } + } + + private final Set packageTypes; + private final ThrowingConsumer configure; + + // Placing jar file in the "Resources" subdir of the input directory would allow + // to use the input directory with `--app-content` on OSX. + // For other platforms it doesn't matter. Keep it the same across + // all platforms for simplicity. + private static final Path JAR_PATH = Path.of("Resources/duke.jar"); + + private static final String ALL_NATIVE_PACKAGE_TYPES = "NATIVE"; +} diff --git a/test/jdk/tools/jpackage/share/RuntimeImageTest.java b/test/jdk/tools/jpackage/share/RuntimeImageTest.java index 440887785891a..64908b6ac99e9 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ import java.nio.file.Path; import jdk.jpackage.test.TKit; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.Executor; @@ -45,10 +44,7 @@ public class RuntimeImageTest { @Test - @Parameter("0") - @Parameter("1") - @Parameter("2") - public static void test(String compression) throws Exception { + public static void test() throws Exception { final Path workDir = TKit.createTempDirectory("runtime").resolve("data"); final Path jlinkOutputDir = workDir.resolve("temp.runtime"); Files.createDirectories(jlinkOutputDir.getParent()); @@ -58,7 +54,6 @@ public static void test(String compression) throws Exception { .dumpOutput() .addArguments( "--output", jlinkOutputDir.toString(), - "--compress=" + compression, "--add-modules", "ALL-MODULE-PATH", "--strip-debug", "--no-header-files", diff --git a/test/jdk/tools/jpackage/share/RuntimePackageTest.java b/test/jdk/tools/jpackage/share/RuntimePackageTest.java index 12edff1cea5ca..da58ed3a73cfa 100644 --- a/test/jdk/tools/jpackage/share/RuntimePackageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimePackageTest.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 @@ -113,7 +113,6 @@ private static PackageTest init(Set types) { .dumpOutput() .addArguments( "--output", runtimeImageDir.toString(), - "--compress=0", "--add-modules", "ALL-MODULE-PATH", "--strip-debug", "--no-header-files", diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java index 7603264c4370e..5118600d341fb 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.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 @@ -28,9 +28,9 @@ import java.nio.file.Path; import java.util.List; import java.util.ArrayList; +import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.Supplier; import java.util.regex.Pattern; import java.util.stream.Stream; import jdk.jpackage.test.TKit; @@ -42,6 +42,8 @@ import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Functional.ThrowingConsumer; +import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; import static jdk.jpackage.test.WindowsHelper.getTempDirectory; @@ -250,6 +252,63 @@ public void testWhitespaceInPaths() { .executeAndAssertHelloAppImageCreated(); } + @Test + @Parameter("true") + @Parameter("false") + public void testNoOutputDir(boolean appImage) throws Throwable { + var cmd = JPackageCommand.helloAppImage(); + + final var execDir = cmd.outputDir(); + + final ThrowingConsumer initializer = cmdNoOutputDir -> { + cmd.executePrerequisiteActions(); + + final var pkgType = cmdNoOutputDir.packageType(); + + cmdNoOutputDir + .clearArguments() + .addArguments(cmd.getAllArguments()) + // Restore the value of `--type` parameter. + .setPackageType(pkgType) + .removeArgumentWithValue("--dest") + .setArgumentValue("--input", execDir.relativize(cmd.inputDir())) + .setDirectory(execDir) + // Force to use jpackage as executable because we need to + // change the current directory. + .useToolProvider(false); + + Optional.ofNullable(cmdNoOutputDir.getArgumentValue("--runtime-image", + () -> null, Path::of)).ifPresent(runtimePath -> { + if (!runtimePath.isAbsolute()) { + cmdNoOutputDir.setArgumentValue("--runtime-image", + execDir.relativize(runtimePath)); + } + }); + + // JPackageCommand.execute() will not do the cleanup if `--dest` parameter + // is not specified, do it manually. + TKit.createDirectories(execDir); + TKit.deleteDirectoryContentsRecursive(execDir); + }; + + if (appImage) { + var cmdNoOutputDir = new JPackageCommand() + .setPackageType(cmd.packageType()); + initializer.accept(cmdNoOutputDir); + cmdNoOutputDir.executeAndAssertHelloAppImageCreated(); + } else { + // Save time by packing non-functional runtime. + // Build the runtime in app image only. This is sufficient coverage. + cmd.setFakeRuntime(); + new PackageTest() + .addInitializer(initializer) + .addInstallVerifier(HelloApp::executeLauncherAndVerifyOutput) + // Prevent adding `--dest` parameter to jpackage command line. + .ignoreBundleOutputDir() + .run(CREATE_AND_UNPACK); + } + } + @Test @Parameter("ALL-MODULE-PATH") @Parameter("ALL-DEFAULT") @@ -265,49 +324,64 @@ public void testAddModules(String... addModulesArg) { cmd.executeAndAssertHelloAppImageCreated(); } + public static enum TestTempType { + TEMPDIR_EMPTY, + TEMPDIR_NOT_EMPTY, + TEMPDIR_NOT_EXIST, + } + /** * Test --temp option. Doesn't make much sense for app image as temporary * directory is used only on Windows. Test it in packaging mode. - * @throws IOException */ @Test - @Parameter("true") - @Parameter("false") - public void testTemp(boolean withExistingTempDir) throws IOException { + @Parameter("TEMPDIR_EMPTY") + @Parameter("TEMPDIR_NOT_EMPTY") + @Parameter("TEMPDIR_NOT_EXIST") + public void testTemp(TestTempType type) throws IOException { final Path tempRoot = TKit.createTempDirectory("tmp"); - Supplier createTest = () -> { - return new PackageTest() - .configureHelloApp() - // Force save of package bundle in test work directory. - .addInitializer(JPackageCommand::setDefaultInputOutput) - .addInitializer(cmd -> { - Path tempDir = getTempDirectory(cmd, tempRoot); - if (withExistingTempDir) { - Files.createDirectories(tempDir); - } else { - Files.createDirectories(tempDir.getParent()); + var pkgTest = new PackageTest() + .configureHelloApp() + // Force save of package bundle in test work directory. + .addInitializer(JPackageCommand::setDefaultInputOutput) + .addInitializer(cmd -> { + Path tempDir = getTempDirectory(cmd, tempRoot); + switch (type) { + case TEMPDIR_EMPTY -> Files.createDirectories(tempDir); + case TEMPDIR_NOT_EXIST -> Files.createDirectories(tempDir.getParent()); + case TEMPDIR_NOT_EMPTY -> { + Files.createDirectories(tempDir); + TKit.createTextFile(tempDir.resolve("foo.txt"), List.of( + "Hello Duke!")); + } } cmd.addArguments("--temp", tempDir); + } + ); + + if (TestTempType.TEMPDIR_NOT_EMPTY.equals(type)) { + pkgTest.setExpectedExitCode(1).addBundleVerifier(cmd -> { + // Check jpackage didn't use the supplied directory. + Path tempDir = getTempDirectory(cmd, tempRoot); + String[] tempDirContents = tempDir.toFile().list(); + TKit.assertStringListEquals(List.of("foo.txt"), List.of( + tempDirContents), String.format( + "Check the contents of the supplied temporary directory [%s]", + tempDir)); + TKit.assertStringListEquals(List.of("Hello Duke!"), + Files.readAllLines(tempDir.resolve(tempDirContents[0])), + "Check the contents of the file in the supplied temporary directory"); }); - }; + } else { + pkgTest.addBundleVerifier(cmd -> { + // Check jpackage used the supplied directory. + Path tempDir = getTempDirectory(cmd, tempRoot); + TKit.assertDirectoryNotEmpty(tempDir); + }); + } - createTest.get() - .addBundleVerifier(cmd -> { - // Check jpackage actually used the supplied directory. - Path tempDir = getTempDirectory(cmd, tempRoot); - TKit.assertNotEquals(0, tempDir.toFile().list().length, - String.format( - "Check jpackage wrote some data in the supplied temporary directory [%s]", - tempDir)); - }) - .run(PackageTest.Action.CREATE); - - createTest.get() - // Temporary directory should not be empty, - // jpackage should exit with error. - .setExpectedExitCode(1) - .run(PackageTest.Action.CREATE); + pkgTest.run(PackageTest.Action.CREATE); } @Test diff --git a/test/jdk/tools/launcher/HelpFlagsTest.java b/test/jdk/tools/launcher/HelpFlagsTest.java index 15c6c101dd0c1..0e8bc345ddc77 100644 --- a/test/jdk/tools/launcher/HelpFlagsTest.java +++ b/test/jdk/tools/launcher/HelpFlagsTest.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. * Copyright (c) 2018, 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -45,7 +45,6 @@ public class HelpFlagsTest extends TestHelper { // Tools that should not be tested because a usage message is pointless. static final String[] TOOLS_NOT_TO_TEST = { - "appletviewer", // deprecated, don't test "jaccessinspector", // gui, don't test, win only "jaccessinspector-32", // gui, don't test, win-32 only "jaccesswalker", // gui, don't test, win only diff --git a/test/jdk/tools/launcher/VersionCheck.java b/test/jdk/tools/launcher/VersionCheck.java index 8ce636c4af7cf..539af8698d473 100644 --- a/test/jdk/tools/launcher/VersionCheck.java +++ b/test/jdk/tools/launcher/VersionCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, 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 @@ -67,7 +67,6 @@ public class VersionCheck extends TestHelper { // tools that do not accept -version static final String[] BLACKLIST_VERSION = { - "appletviewer", "controlpanel", "jaccessinspector", "jaccessinspector-32", diff --git a/test/jdk/tools/sincechecker/SinceChecker.java b/test/jdk/tools/sincechecker/SinceChecker.java new file mode 100644 index 0000000000000..860db6a2798fd --- /dev/null +++ b/test/jdk/tools/sincechecker/SinceChecker.java @@ -0,0 +1,948 @@ +/* + * 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.io.IOException; +import java.io.UncheckedIOException; +import java.lang.Runtime.Version; +import java.net.URI; +import java.nio.file.*; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import javax.lang.model.element.*; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import javax.tools.*; +import javax.tools.JavaFileManager.Location; +import com.sun.source.tree.*; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import com.sun.tools.javac.api.JavacTaskImpl; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.util.Pair; +import jtreg.SkippedException; + +/* +This checker checks the values of the `@since` tag found in the documentation comment for an element against +the release in which the element first appeared. +The source code containing the documentation comments is read from `src.zip` in the release of JDK used to run the test. +The releases used to determine the expected value of `@since` tags are taken from the historical data built into `javac`. + +The `@since` checker works as a two-step process: +In the first step, we process JDKs 9-current, only classfiles, + producing a map ` => ``. + - "version(s)", because we handle versioning of Preview API, so there may be two versions + (we use a class with two fields for preview and stable), + one when it was introduced as a preview, and one when it went out of preview. More on that below. + - For each Element, we compute the unique ID, look into the map, and if there's nothing, + record the current version as the originating version. + - At the end of this step we have a map of the Real since values + +In the second step, we look at "effective" `@since` tags in the mainline sources, from `src.zip` + (if the test run doesn't have it, we throw a `jtreg.SkippedException`) + - We only check the specific MODULE whose name was passed as an argument in the test. + In that module, we look for unqualified exports and test those packages. + - The `@since` checker verifies that for every API element, the real since value and + the effective since value are the same, and reports an error if they are not. + +Important note : We only check code written since JDK 9 as the releases used to determine the expected value + of @since tags are taken from the historical data built into javac which only goes back that far + +note on rules for Real and effective `@since: + +Real since value of an API element is computed as the oldest release in which the given API element was introduced. +That is: +- for modules, packages, classes and interfaces, the release in which the element with the given qualified name was introduced +- for constructors, the release in which the constructor with the given VM descriptor was introduced +- for methods and fields, the release in which the given method or field with the given VM descriptor became a member + of its enclosing class or interface, whether direct or inherited + +Effective since value of an API element is computed as follows: +- if the given element has a @since tag in its javadoc, it is used +- in all other cases, return the effective since value of the enclosing element + + +Special Handling for preview method, as per JEP 12: +- When an element is still marked as preview, the `@since` should be the first JDK release where the element was added. +- If the element is no longer marked as preview, the `@since` should be the first JDK release where it was no longer preview. + +note on legacy preview: Until JDK 14, the preview APIs were not marked in any machine-understandable way. + It was deprecated, and had a comment in the javadoc. + and the use of `@PreviewFeature` only became standard in JDK 17. + So the checker has an explicit knowledge of these preview elements. + +note: The `` for methods looks like + `method: .()`. +it is somewhat inspired from the VM Method Descriptors. But we use the erased return so that methods +that were later generified remain the same. + +usage: the checker is run from a module specific test + `@run main SinceChecker [--exclude package1,package2 | --exclude package1 package2]` +*/ + +public class SinceChecker { + private final Map> LEGACY_PREVIEW_METHODS = new HashMap<>(); + private final Map classDictionary = new HashMap<>(); + private final JavaCompiler tool; + private int errorCount = 0; + + // packages to skip during the test + private static final Set EXCLUDE_LIST = new HashSet<>(); + + public static class IntroducedIn { + public String introducedPreview; + public String introducedStable; + } + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + throw new IllegalArgumentException("Test module not specified"); + } + String moduleName = args[0]; + boolean excludeFlag = false; + + for (int i = 1; i < args.length; i++) { + if ("--exclude".equals(args[i])) { + excludeFlag = true; + continue; + } + + if (excludeFlag) { + if (args[i].contains(",")) { + EXCLUDE_LIST.addAll(Arrays.asList(args[i].split(","))); + } else { + EXCLUDE_LIST.add(args[i]); + } + } + } + + SinceChecker sinceCheckerTestHelper = new SinceChecker(moduleName); + sinceCheckerTestHelper.checkModule(moduleName); + } + + private void error(String message) { + System.err.println(message); + errorCount++; + } + + private SinceChecker(String moduleName) throws IOException { + tool = ToolProvider.getSystemJavaCompiler(); + for (int i = 9; i <= Runtime.version().feature(); i++) { + DiagnosticListener noErrors = d -> { + if (!d.getCode().equals("compiler.err.module.not.found")) { + error(d.getMessage(null)); + } + }; + JavacTask ct = (JavacTask) tool.getTask(null, + null, + noErrors, + List.of("--add-modules", moduleName, "--release", String.valueOf(i)), + null, + Collections.singletonList(SimpleJavaFileObject.forSource(URI.create("myfo:/Test.java"), ""))); + ct.analyze(); + + String version = String.valueOf(i); + Elements elements = ct.getElements(); + elements.getModuleElement("java.base"); // forces module graph to be instantiated + elements.getAllModuleElements().forEach(me -> + processModuleElement(me, version, ct)); + } + } + + private void processModuleElement(ModuleElement moduleElement, String releaseVersion, JavacTask ct) { + processElement(moduleElement, moduleElement, ct.getTypes(), releaseVersion); + for (ModuleElement.ExportsDirective ed : ElementFilter.exportsIn(moduleElement.getDirectives())) { + if (ed.getTargetModules() == null) { + processPackageElement(ed.getPackage(), releaseVersion, ct); + } + } + } + + private void processPackageElement(PackageElement pe, String releaseVersion, JavacTask ct) { + processElement(pe, pe, ct.getTypes(), releaseVersion); + List typeElements = ElementFilter.typesIn(pe.getEnclosedElements()); + for (TypeElement te : typeElements) { + processClassElement(te, releaseVersion, ct.getTypes(), ct.getElements()); + } + } + + /// JDK documentation only contains public and protected declarations + private boolean isDocumented(Element te) { + Set mod = te.getModifiers(); + return mod.contains(Modifier.PUBLIC) || mod.contains(Modifier.PROTECTED); + } + + private boolean isMember(Element e) { + var kind = e.getKind(); + return kind.isField() || switch (kind) { + case METHOD, CONSTRUCTOR -> true; + default -> false; + }; + } + + private void processClassElement(TypeElement te, String version, Types types, Elements elements) { + if (!isDocumented(te)) { + return; + } + processElement(te.getEnclosingElement(), te, types, version); + elements.getAllMembers(te).stream() + .filter(this::isDocumented) + .filter(this::isMember) + .forEach(element -> processElement(te, element, types, version)); + te.getEnclosedElements().stream() + .filter(element -> element.getKind().isDeclaredType()) + .map(TypeElement.class::cast) + .forEach(nestedClass -> processClassElement(nestedClass, version, types, elements)); + } + + private void processElement(Element explicitOwner, Element element, Types types, String version) { + String uniqueId = getElementName(explicitOwner, element, types); + IntroducedIn introduced = classDictionary.computeIfAbsent(uniqueId, _ -> new IntroducedIn()); + if (isPreview(element, uniqueId, version)) { + if (introduced.introducedPreview == null) { + introduced.introducedPreview = version; + } + } else { + if (introduced.introducedStable == null) { + introduced.introducedStable = version; + } + } + } + + private boolean isPreview(Element el, String uniqueId, String currentVersion) { + while (el != null) { + Symbol s = (Symbol) el; + if ((s.flags() & Flags.PREVIEW_API) != 0) { + return true; + } + el = el.getEnclosingElement(); + } + + return LEGACY_PREVIEW_METHODS.getOrDefault(currentVersion, Set.of()) + .contains(uniqueId); + } + + private void checkModule(String moduleName) throws Exception { + Path home = Paths.get(System.getProperty("java.home")); + Path srcZip = home.resolve("lib").resolve("src.zip"); + if (Files.notExists(srcZip)) { + //possibly running over an exploded JDK build, attempt to find a + //co-located full JDK image with src.zip: + Path testJdk = Paths.get(System.getProperty("test.jdk")); + srcZip = testJdk.getParent().resolve("images").resolve("jdk").resolve("lib").resolve("src.zip"); + } + if (!Files.isReadable(srcZip)) { + throw new SkippedException("Skipping Test because src.zip wasn't found or couldn't be read"); + } + URI uri = URI.create("jar:" + srcZip.toUri()); + try (FileSystem zipFO = FileSystems.newFileSystem(uri, Collections.emptyMap())) { + Path root = zipFO.getRootDirectories().iterator().next(); + Path moduleDirectory = root.resolve(moduleName); + try (StandardJavaFileManager fm = + tool.getStandardFileManager(null, null, null)) { + JavacTask ct = (JavacTask) tool.getTask(null, + fm, + null, + List.of("--add-modules", moduleName, "-d", "."), + null, + Collections.singletonList(SimpleJavaFileObject.forSource(URI.create("myfo:/Test.java"), ""))); + ct.analyze(); + Elements elements = ct.getElements(); + elements.getModuleElement("java.base"); + try (EffectiveSourceSinceHelper javadocHelper = EffectiveSourceSinceHelper.create(ct, List.of(root), this)) { + processModuleCheck(elements.getModuleElement(moduleName), ct, moduleDirectory, javadocHelper); + } catch (Exception e) { + e.printStackTrace(); + error("Initiating javadocHelper Failed " + e); + } + if (errorCount > 0) { + throw new Exception("The `@since` checker found " + errorCount + " problems"); + } + } + } + } + + private boolean isExcluded(ModuleElement.ExportsDirective ed ){ + return EXCLUDE_LIST.stream().anyMatch(excludePackage -> + ed.getPackage().toString().equals(excludePackage) || + ed.getPackage().toString().startsWith(excludePackage + ".")); + } + + private void processModuleCheck(ModuleElement moduleElement, JavacTask ct, Path moduleDirectory, EffectiveSourceSinceHelper javadocHelper) { + if (moduleElement == null) { + error("Module element: was null because `elements.getModuleElement(moduleName)` returns null." + + "fixes are needed for this Module"); + } + String moduleVersion = getModuleVersionFromFile(moduleDirectory); + checkModuleOrPackage(javadocHelper, moduleVersion, moduleElement, ct, "Module: "); + for (ModuleElement.ExportsDirective ed : ElementFilter.exportsIn(moduleElement.getDirectives())) { + if (ed.getTargetModules() == null) { + String packageVersion = getPackageVersionFromFile(moduleDirectory, ed); + if (packageVersion != null && !isExcluded(ed)) { + checkModuleOrPackage(javadocHelper, packageVersion, ed.getPackage(), ct, "Package: "); + analyzePackageCheck(ed.getPackage(), ct, javadocHelper); + } // Skip the package if packageVersion is null + } + } + } + + private void checkModuleOrPackage(EffectiveSourceSinceHelper javadocHelper, String moduleVersion, Element moduleElement, JavacTask ct, String elementCategory) { + String id = getElementName(moduleElement, moduleElement, ct.getTypes()); + var elementInfo = classDictionary.get(id); + if (elementInfo == null) { + error("Element :" + id + " was not mapped"); + return; + } + String version = elementInfo.introducedStable; + if (moduleVersion == null) { + error("Unable to retrieve `@since` for " + elementCategory + id); + } else { + String position = javadocHelper.getElementPosition(id); + checkEquals(position, moduleVersion, version, id); + } + } + + private String getModuleVersionFromFile(Path moduleDirectory) { + Path moduleInfoFile = moduleDirectory.resolve("module-info.java"); + String version = null; + if (Files.exists(moduleInfoFile)) { + try { + String moduleInfoContent = Files.readString(moduleInfoFile); + var extractedVersion = extractSinceVersionFromText(moduleInfoContent); + if (extractedVersion != null) { + version = extractedVersion.toString(); + } + } catch (IOException e) { + error("module-info.java not found or couldn't be opened AND this module has no unqualified exports"); + } + } + return version; + } + + private String getPackageVersionFromFile(Path moduleDirectory, ModuleElement.ExportsDirective ed) { + Path pkgInfo = moduleDirectory.resolve(ed.getPackage() + .getQualifiedName() + .toString() + .replace(".", File.separator) + ) + .resolve("package-info.java"); + + if (!Files.exists(pkgInfo)) { + return null; // Skip if the file does not exist + } + + String packageTopVersion = null; + try { + String packageContent = Files.readString(pkgInfo); + var extractedVersion = extractSinceVersionFromText(packageContent); + if (extractedVersion != null) { + packageTopVersion = extractedVersion.toString(); + } else { + error(ed.getPackage().getQualifiedName() + ": package-info.java exists but doesn't contain @since"); + } + } catch (IOException e) { + error(ed.getPackage().getQualifiedName() + ": package-info.java couldn't be opened"); + } + return packageTopVersion; + } + + private void analyzePackageCheck(PackageElement pe, JavacTask ct, EffectiveSourceSinceHelper javadocHelper) { + List typeElements = ElementFilter.typesIn(pe.getEnclosedElements()); + for (TypeElement te : typeElements) { + analyzeClassCheck(te, null, javadocHelper, ct.getTypes(), ct.getElements()); + } + } + + private boolean isNotCommonRecordMethod(TypeElement te, Element element, Types types) { + var isRecord = te.getKind() == ElementKind.RECORD; + if (!isRecord) { + return true; + } + String uniqueId = getElementName(te, element, types); + boolean isCommonMethod = uniqueId.endsWith(".toString()") || + uniqueId.endsWith(".hashCode()") || + uniqueId.endsWith(".equals(java.lang.Object)"); + if (isCommonMethod) { + return false; + } + for (var parameter : te.getEnclosedElements()) { + if (parameter.getKind() == ElementKind.RECORD_COMPONENT) { + if (uniqueId.endsWith(String.format("%s.%s()", te.getSimpleName(), parameter.getSimpleName().toString()))) { + return false; + } + } + } + return true; + } + + private void analyzeClassCheck(TypeElement te, String version, EffectiveSourceSinceHelper javadocHelper, + Types types, Elements elementUtils) { + String currentjdkVersion = String.valueOf(Runtime.version().feature()); + if (!isDocumented(te)) { + return; + } + checkElement(te.getEnclosingElement(), te, types, javadocHelper, version, elementUtils); + te.getEnclosedElements().stream().filter(this::isDocumented) + .filter(this::isMember) + .filter(element -> isNotCommonRecordMethod(te, element, types)) + .forEach(element -> checkElement(te, element, types, javadocHelper, version, elementUtils)); + te.getEnclosedElements().stream() + .filter(element -> element.getKind().isDeclaredType()) + .map(TypeElement.class::cast) + .forEach(nestedClass -> analyzeClassCheck(nestedClass, currentjdkVersion, javadocHelper, types, elementUtils)); + } + + private void checkElement(Element explicitOwner, Element element, Types types, + EffectiveSourceSinceHelper javadocHelper, String currentVersion, Elements elementUtils) { + String uniqueId = getElementName(explicitOwner, element, types); + + if (element.getKind() == ElementKind.METHOD && + element.getEnclosingElement().getKind() == ElementKind.ENUM && + (uniqueId.contains(".values()") || uniqueId.contains(".valueOf(java.lang.String)"))) { + //mandated enum type methods + return; + } + String sinceVersion = null; + var effectiveSince = javadocHelper.effectiveSinceVersion(explicitOwner, element, types, elementUtils); + if (effectiveSince == null) { + // Skip the element if the java file doesn't exist in src.zip + return; + } + sinceVersion = effectiveSince.toString(); + IntroducedIn mappedVersion = classDictionary.get(uniqueId); + if (mappedVersion == null) { + error("Element: " + uniqueId + " was not mapped"); + return; + } + String realMappedVersion = null; + try { + realMappedVersion = isPreview(element, uniqueId, currentVersion) ? + mappedVersion.introducedPreview : + mappedVersion.introducedStable; + } catch (Exception e) { + error("For element " + element + "mappedVersion" + mappedVersion + " is null " + e); + } + String position = javadocHelper.getElementPosition(uniqueId); + checkEquals(position, sinceVersion, realMappedVersion, uniqueId); + } + + private Version extractSinceVersionFromText(String documentation) { + Pattern pattern = Pattern.compile("@since\\s+(\\d+(?:\\.\\d+)?)"); + Matcher matcher = pattern.matcher(documentation); + if (matcher.find()) { + String versionString = matcher.group(1); + try { + if (versionString.equals("1.0")) { + versionString = "1"; //ended up being necessary + } else if (versionString.startsWith("1.")) { + versionString = versionString.substring(2); + } + return Version.parse(versionString); + } catch (NumberFormatException ex) { + error("`@since` value that cannot be parsed: " + versionString); + return null; + } + } else { + return null; + } + } + + private void checkEquals(String prefix, String sinceVersion, String mappedVersion, String name) { + if (sinceVersion == null || mappedVersion == null) { + error(name + ": NULL value for either real or effective `@since` . real/mapped version is=" + + mappedVersion + " while the `@since` in the source code is= " + sinceVersion); + return; + } + if (Integer.parseInt(sinceVersion) < 9) { + sinceVersion = "9"; + } + if (!sinceVersion.equals(mappedVersion)) { + String message = getWrongSinceMessage(prefix, sinceVersion, mappedVersion, name); + error(message); + } + } + private static String getWrongSinceMessage(String prefix, String sinceVersion, String mappedVersion, String elementSimpleName) { + String message; + if (mappedVersion.equals("9")) { + message = elementSimpleName + ": `@since` version is " + sinceVersion + " but the element exists before JDK 10"; + } else { + message = elementSimpleName + ": `@since` version: " + sinceVersion + "; should be: " + mappedVersion; + } + return prefix + message; + } + + private static String getElementName(Element owner, Element element, Types types) { + String prefix = ""; + String suffix = ""; + ElementKind kind = element.getKind(); + if (kind.isField()) { + TypeElement te = (TypeElement) owner; + prefix = "field"; + suffix = ": " + te.getQualifiedName() + ":" + element.getSimpleName(); + } else if (kind == ElementKind.METHOD || kind == ElementKind.CONSTRUCTOR) { + prefix = "method"; + TypeElement te = (TypeElement) owner; + ExecutableElement executableElement = (ExecutableElement) element; + String returnType = types.erasure(executableElement.getReturnType()).toString(); + String methodName = executableElement.getSimpleName().toString(); + String descriptor = executableElement.getParameters().stream() + .map(p -> types.erasure(p.asType()).toString()) + .collect(Collectors.joining(",", "(", ")")); + suffix = ": " + returnType + " " + te.getQualifiedName() + "." + methodName + descriptor; + } else if (kind.isDeclaredType()) { + if (kind.isClass()) { + prefix = "class"; + } else if (kind.isInterface()) { + prefix = "interface"; + } + suffix = ": " + ((TypeElement) element).getQualifiedName(); + } else if (kind == ElementKind.PACKAGE) { + prefix = "package"; + suffix = ": " + ((PackageElement) element).getQualifiedName(); + } else if (kind == ElementKind.MODULE) { + prefix = "module"; + suffix = ": " + ((ModuleElement) element).getQualifiedName(); + } + return prefix + suffix; + } + + //these were preview in before the introduction of the @PreviewFeature + { + LEGACY_PREVIEW_METHODS.put("9", Set.of( + "module: jdk.nio.mapmode", + "module: java.transaction.xa", + "module: jdk.unsupported.desktop", + "module: jdk.jpackage", + "module: java.net.http" + )); + LEGACY_PREVIEW_METHODS.put("10", Set.of( + "module: jdk.nio.mapmode", + "module: java.transaction.xa", + "module: java.net.http", + "module: jdk.unsupported.desktop", + "module: jdk.jpackage" + )); + LEGACY_PREVIEW_METHODS.put("11", Set.of( + "module: jdk.nio.mapmode", + "module: jdk.jpackage" + )); + LEGACY_PREVIEW_METHODS.put("12", Set.of( + "module: jdk.nio.mapmode", + "module: jdk.jpackage", + "method: com.sun.source.tree.ExpressionTree com.sun.source.tree.BreakTree.getValue()", + "method: java.util.List com.sun.source.tree.CaseTree.getExpressions()", + "method: com.sun.source.tree.Tree com.sun.source.tree.CaseTree.getBody()", + "method: com.sun.source.tree.CaseTree.CaseKind com.sun.source.tree.CaseTree.getCaseKind()", + "class: com.sun.source.tree.CaseTree.CaseKind", + "field: com.sun.source.tree.CaseTree.CaseKind:STATEMENT", + "field: com.sun.source.tree.CaseTree.CaseKind:RULE", + "field: com.sun.source.tree.Tree.Kind:SWITCH_EXPRESSION", + "interface: com.sun.source.tree.SwitchExpressionTree", + "method: com.sun.source.tree.ExpressionTree com.sun.source.tree.SwitchExpressionTree.getExpression()", + "method: java.util.List com.sun.source.tree.SwitchExpressionTree.getCases()", + "method: java.lang.Object com.sun.source.tree.TreeVisitor.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.TreeScanner.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.SimpleTreeVisitor.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)" + )); + + LEGACY_PREVIEW_METHODS.put("13", Set.of( + "module: jdk.nio.mapmode", + "module: jdk.jpackage", + "method: java.util.List com.sun.source.tree.CaseTree.getExpressions()", + "method: com.sun.source.tree.Tree com.sun.source.tree.CaseTree.getBody()", + "method: com.sun.source.tree.CaseTree.CaseKind com.sun.source.tree.CaseTree.getCaseKind()", + "class: com.sun.source.tree.CaseTree.CaseKind", + "field: com.sun.source.tree.CaseTree.CaseKind:STATEMENT", + "field: com.sun.source.tree.CaseTree.CaseKind:RULE", + "field: com.sun.source.tree.Tree.Kind:SWITCH_EXPRESSION", + "interface: com.sun.source.tree.SwitchExpressionTree", + "method: com.sun.source.tree.ExpressionTree com.sun.source.tree.SwitchExpressionTree.getExpression()", + "method: java.util.List com.sun.source.tree.SwitchExpressionTree.getCases()", + "method: java.lang.Object com.sun.source.tree.TreeVisitor.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.TreeScanner.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.SimpleTreeVisitor.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)", + "method: java.lang.String java.lang.String.stripIndent()", + "method: java.lang.String java.lang.String.translateEscapes()", + "method: java.lang.String java.lang.String.formatted(java.lang.Object[])", + "class: javax.swing.plaf.basic.motif.MotifLookAndFeel", + "field: com.sun.source.tree.Tree.Kind:YIELD", + "interface: com.sun.source.tree.YieldTree", + "method: com.sun.source.tree.ExpressionTree com.sun.source.tree.YieldTree.getValue()", + "method: java.lang.Object com.sun.source.tree.TreeVisitor.visitYield(com.sun.source.tree.YieldTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.SimpleTreeVisitor.visitYield(com.sun.source.tree.YieldTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.TreeScanner.visitYield(com.sun.source.tree.YieldTree,java.lang.Object)" + )); + + LEGACY_PREVIEW_METHODS.put("14", Set.of( + "module: jdk.jpackage", + "class: javax.swing.plaf.basic.motif.MotifLookAndFeel", + "field: jdk.jshell.Snippet.SubKind:RECORD_SUBKIND", + "class: javax.lang.model.element.RecordComponentElement", + "method: javax.lang.model.type.TypeMirror javax.lang.model.element.RecordComponentElement.asType()", + "method: java.lang.Object javax.lang.model.element.ElementVisitor.visitRecordComponent(javax.lang.model.element.RecordComponentElement,java.lang.Object)", + "class: javax.lang.model.util.ElementScanner14", + "class: javax.lang.model.util.AbstractElementVisitor14", + "class: javax.lang.model.util.SimpleElementVisitor14", + "method: java.lang.Object javax.lang.model.util.ElementKindVisitor6.visitTypeAsRecord(javax.lang.model.element.TypeElement,java.lang.Object)", + "class: javax.lang.model.util.ElementKindVisitor14", + "method: javax.lang.model.element.RecordComponentElement javax.lang.model.util.Elements.recordComponentFor(javax.lang.model.element.ExecutableElement)", + "method: java.util.List javax.lang.model.util.ElementFilter.recordComponentsIn(java.lang.Iterable)", + "method: java.util.Set javax.lang.model.util.ElementFilter.recordComponentsIn(java.util.Set)", + "method: java.util.List javax.lang.model.element.TypeElement.getRecordComponents()", + "field: javax.lang.model.element.ElementKind:RECORD", + "field: javax.lang.model.element.ElementKind:RECORD_COMPONENT", + "field: javax.lang.model.element.ElementKind:BINDING_VARIABLE", + "field: com.sun.source.tree.Tree.Kind:RECORD", + "field: sun.reflect.annotation.TypeAnnotation.TypeAnnotationTarget:RECORD_COMPONENT", + "class: java.lang.reflect.RecordComponent", + "class: java.lang.runtime.ObjectMethods", + "field: java.lang.annotation.ElementType:RECORD_COMPONENT", + "method: boolean java.lang.Class.isRecord()", + "method: java.lang.reflect.RecordComponent[] java.lang.Class.getRecordComponents()", + "class: java.lang.Record", + "interface: com.sun.source.tree.PatternTree", + "field: com.sun.source.tree.Tree.Kind:BINDING_PATTERN", + "method: com.sun.source.tree.PatternTree com.sun.source.tree.InstanceOfTree.getPattern()", + "interface: com.sun.source.tree.BindingPatternTree", + "method: java.lang.Object com.sun.source.tree.TreeVisitor.visitBindingPattern(com.sun.source.tree.BindingPatternTree,java.lang.Object)" + )); + + LEGACY_PREVIEW_METHODS.put("15", Set.of( + "module: jdk.jpackage", + "field: jdk.jshell.Snippet.SubKind:RECORD_SUBKIND", + "class: javax.lang.model.element.RecordComponentElement", + "method: javax.lang.model.type.TypeMirror javax.lang.model.element.RecordComponentElement.asType()", + "method: java.lang.Object javax.lang.model.element.ElementVisitor.visitRecordComponent(javax.lang.model.element.RecordComponentElement,java.lang.Object)", + "class: javax.lang.model.util.ElementScanner14", + "class: javax.lang.model.util.AbstractElementVisitor14", + "class: javax.lang.model.util.SimpleElementVisitor14", + "method: java.lang.Object javax.lang.model.util.ElementKindVisitor6.visitTypeAsRecord(javax.lang.model.element.TypeElement,java.lang.Object)", + "class: javax.lang.model.util.ElementKindVisitor14", + "method: javax.lang.model.element.RecordComponentElement javax.lang.model.util.Elements.recordComponentFor(javax.lang.model.element.ExecutableElement)", + "method: java.util.List javax.lang.model.util.ElementFilter.recordComponentsIn(java.lang.Iterable)", + "method: java.util.Set javax.lang.model.util.ElementFilter.recordComponentsIn(java.util.Set)", + "method: java.util.List javax.lang.model.element.TypeElement.getRecordComponents()", + "field: javax.lang.model.element.ElementKind:RECORD", + "field: javax.lang.model.element.ElementKind:RECORD_COMPONENT", + "field: javax.lang.model.element.ElementKind:BINDING_VARIABLE", + "field: com.sun.source.tree.Tree.Kind:RECORD", + "field: sun.reflect.annotation.TypeAnnotation.TypeAnnotationTarget:RECORD_COMPONENT", + "class: java.lang.reflect.RecordComponent", + "class: java.lang.runtime.ObjectMethods", + "field: java.lang.annotation.ElementType:RECORD_COMPONENT", + "class: java.lang.Record", + "method: boolean java.lang.Class.isRecord()", + "method: java.lang.reflect.RecordComponent[] java.lang.Class.getRecordComponents()", + "field: javax.lang.model.element.Modifier:SEALED", + "field: javax.lang.model.element.Modifier:NON_SEALED", + "method: javax.lang.model.element.TypeElement:getPermittedSubclasses:()", + "method: java.util.List com.sun.source.tree.ClassTree.getPermitsClause()", + "method: boolean java.lang.Class.isSealed()", + "method: java.lang.constant.ClassDesc[] java.lang.Class.permittedSubclasses()", + "interface: com.sun.source.tree.PatternTree", + "field: com.sun.source.tree.Tree.Kind:BINDING_PATTERN", + "method: com.sun.source.tree.PatternTree com.sun.source.tree.InstanceOfTree.getPattern()", + "interface: com.sun.source.tree.BindingPatternTree", + "method: java.lang.Object com.sun.source.tree.TreeVisitor.visitBindingPattern(com.sun.source.tree.BindingPatternTree,java.lang.Object)" + )); + + LEGACY_PREVIEW_METHODS.put("16", Set.of( + "field: jdk.jshell.Snippet.SubKind:RECORD_SUBKIND", + "field: javax.lang.model.element.Modifier:SEALED", + "field: javax.lang.model.element.Modifier:NON_SEALED", + "method: javax.lang.model.element.TypeElement:getPermittedSubclasses:()", + "method: java.util.List com.sun.source.tree.ClassTree.getPermitsClause()", + "method: boolean java.lang.Class.isSealed()", + "method: java.lang.constant.ClassDesc[] java.lang.Class.permittedSubclasses()" + )); + + // java.lang.foreign existed since JDK 19 and wasn't annotated - went out of preview in JDK 22 + LEGACY_PREVIEW_METHODS.put("19", Set.of( + "package: java.lang.foreign" + )); + LEGACY_PREVIEW_METHODS.put("20", Set.of( + "package: java.lang.foreign" + )); + LEGACY_PREVIEW_METHODS.put("21", Set.of( + "package: java.lang.foreign" + )); + } + + /** + * Helper to find javadoc and resolve @inheritDoc and the effective since version. + */ + + private final class EffectiveSourceSinceHelper implements AutoCloseable { + private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + private final JavaFileManager baseFileManager; + private final StandardJavaFileManager fm; + private final Set seenLookupElements = new HashSet<>(); + private final Map signature2Source = new HashMap<>(); + private final Map signature2Location = new HashMap<>(); + + /** + * Create the helper. + * + * @param mainTask JavacTask from which the further Elements originate + * @param sourceLocations paths where source files should be searched + * @param validator enclosing class of the helper, typically the object invoking this method + * @return a EffectiveSourceSinceHelper + */ + + public static EffectiveSourceSinceHelper create(JavacTask mainTask, Collection sourceLocations, SinceChecker validator) { + StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null); + try { + fm.setLocationFromPaths(StandardLocation.MODULE_SOURCE_PATH, sourceLocations); + return validator.new EffectiveSourceSinceHelper(mainTask, fm); + } catch (IOException ex) { + try { + fm.close(); + } catch (IOException closeEx) { + ex.addSuppressed(closeEx); + } + throw new UncheckedIOException(ex); + } + } + + private EffectiveSourceSinceHelper(JavacTask mainTask, StandardJavaFileManager fm) { + this.baseFileManager = ((JavacTaskImpl) mainTask).getContext().get(JavaFileManager.class); + this.fm = fm; + } + + public Version effectiveSinceVersion(Element owner, Element element, Types typeUtils, Elements elementUtils) { + String handle = getElementName(owner, element, typeUtils); + Version since = signature2Source.get(handle); + + if (since == null) { + try { + Element lookupElement = switch (element.getKind()) { + case MODULE, PACKAGE -> element; + default -> elementUtils.getOutermostTypeElement(element); + }; + + if (lookupElement == null) + return null; + + String lookupHandle = getElementName(owner, element, typeUtils); + + if (!seenLookupElements.add(lookupHandle)) { + //we've already processed this top-level, don't try to compute + //the values again: + return null; + } + + Pair source = findSource(lookupElement, elementUtils); + + if (source == null) + return null; + + fillElementCache(source.fst, source.snd, source.fst.getTypes(), source.fst.getElements()); + since = signature2Source.get(handle); + + } catch (IOException ex) { + error("JavadocHelper failed for " + element); + } + } + + return since; + } + + private String getElementPosition(String signature) { + return signature2Location.getOrDefault(signature, ""); + } + + //where: + private void fillElementCache(JavacTask task, CompilationUnitTree cut, Types typeUtils, Elements elementUtils) { + Trees trees = Trees.instance(task); + String fileName = cut.getSourceFile().getName(); + + new TreePathScanner() { + @Override + public Void visitMethod(MethodTree node, Void p) { + handleDeclaration(node, fileName); + return null; + } + + @Override + public Void visitClass(ClassTree node, Void p) { + handleDeclaration(node, fileName); + return super.visitClass(node, p); + } + + @Override + public Void visitVariable(VariableTree node, Void p) { + handleDeclaration(node, fileName); + return null; + } + + @Override + public Void visitModule(ModuleTree node, Void p) { + handleDeclaration(node, fileName); + return null; + } + + @Override + public Void visitBlock(BlockTree node, Void p) { + return null; + } + + @Override + public Void visitPackage(PackageTree node, Void p) { + if (cut.getSourceFile().isNameCompatible("package-info", JavaFileObject.Kind.SOURCE)) { + handleDeclaration(node, fileName); + } + return super.visitPackage(node, p); + } + + private void handleDeclaration(Tree node, String fileName) { + Element currentElement = trees.getElement(getCurrentPath()); + + if (currentElement != null) { + long startPosition = trees.getSourcePositions().getStartPosition(cut, node); + long lineNumber = cut.getLineMap().getLineNumber(startPosition); + String filePathWithLineNumber = String.format("src%s:%s ", fileName, lineNumber); + + signature2Source.put(getElementName(currentElement.getEnclosingElement(), currentElement, typeUtils), computeSinceVersion(currentElement, typeUtils, elementUtils)); + signature2Location.put(getElementName(currentElement.getEnclosingElement(), currentElement, typeUtils), filePathWithLineNumber); + } + } + }.scan(cut, null); + } + + private Version computeSinceVersion(Element element, Types types, + Elements elementUtils) { + String docComment = elementUtils.getDocComment(element); + Version version = null; + if (docComment != null) { + version = extractSinceVersionFromText(docComment); + } + + if (version != null) { + return version; //explicit @since has an absolute priority + } + + if (element.getKind() != ElementKind.MODULE) { + version = effectiveSinceVersion(element.getEnclosingElement().getEnclosingElement(), element.getEnclosingElement(), types, elementUtils); + } + + return version; + } + + private Pair findSource(Element forElement, Elements elementUtils) throws IOException { + String moduleName = elementUtils.getModuleOf(forElement).getQualifiedName().toString(); + String binaryName = switch (forElement.getKind()) { + case MODULE -> "module-info"; + case PACKAGE -> ((QualifiedNameable) forElement).getQualifiedName() + ".package-info"; + default -> elementUtils.getBinaryName((TypeElement) forElement).toString(); + }; + Location packageLocationForModule = fm.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, moduleName); + JavaFileObject jfo = fm.getJavaFileForInput(packageLocationForModule, + binaryName, + JavaFileObject.Kind.SOURCE); + + if (jfo == null) + return null; + + List jfos = Arrays.asList(jfo); + JavaFileManager patchFM = moduleName != null + ? new PatchModuleFileManager(baseFileManager, jfo, moduleName) + : baseFileManager; + JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, patchFM, d -> { + }, null, null, jfos); + Iterable cuts = task.parse(); + + task.enter(); + + return Pair.of(task, cuts.iterator().next()); + } + + @Override + public void close() throws IOException { + fm.close(); + } + + /** + * Manages files within a patch module. + * Provides custom behavior for handling file locations within a patch module. + * Includes methods to specify module locations, infer module names and determine + * if a location belongs to the patch module path. + */ + private static final class PatchModuleFileManager + extends ForwardingJavaFileManager { + + private final JavaFileObject file; + private final String moduleName; + + public PatchModuleFileManager(JavaFileManager fileManager, + JavaFileObject file, + String moduleName) { + super(fileManager); + this.file = file; + this.moduleName = moduleName; + } + + @Override + public Location getLocationForModule(Location location, + JavaFileObject fo) throws IOException { + return fo == file + ? PATCH_LOCATION + : super.getLocationForModule(location, fo); + } + + @Override + public String inferModuleName(Location location) throws IOException { + return location == PATCH_LOCATION + ? moduleName + : super.inferModuleName(location); + } + + @Override + public boolean hasLocation(Location location) { + return location == StandardLocation.PATCH_MODULE_PATH || + super.hasLocation(location); + } + + private static final Location PATCH_LOCATION = new Location() { + @Override + public String getName() { + return "PATCH_LOCATION"; + } + + @Override + public boolean isOutputLocation() { + return false; + } + + @Override + public boolean isModuleOrientedLocation() { + return false; + } + }; + } + } +} diff --git a/src/hotspot/os/bsd/gc/x/xLargePages_bsd.cpp b/test/jdk/tools/sincechecker/modules/java_base/CheckSince_javaBase.java similarity index 69% rename from src/hotspot/os/bsd/gc/x/xLargePages_bsd.cpp rename to test/jdk/tools/sincechecker/modules/java_base/CheckSince_javaBase.java index 1c82e83120881..6d0b9d0e932e8 100644 --- a/src/hotspot/os/bsd/gc/x/xLargePages_bsd.cpp +++ b/test/jdk/tools/sincechecker/modules/java_base/CheckSince_javaBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,14 +21,14 @@ * questions. */ -#include "precompiled.hpp" -#include "gc/x/xLargePages.hpp" -#include "runtime/globals.hpp" - -void XLargePages::pd_initialize() { - if (UseLargePages) { - _state = Explicit; - } else { - _state = Disabled; - } -} +/* + * @test + * @bug 8331051 + * @summary Test for `@since` for java.base module + * @library /test/lib + * /test/jdk/tools/sincechecker + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.util + * jdk.compiler/com.sun.tools.javac.code + * @run main SinceChecker java.base --exclude java.lang.classfile + */ diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 539a1f23208c3..4f00846116cb6 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -131,7 +131,7 @@ public Map call() { map.put("vm.libgraal.jit", this::isLibgraalJIT); map.put("vm.compiler1.enabled", this::isCompiler1Enabled); map.put("vm.compiler2.enabled", this::isCompiler2Enabled); - map.put("docker.support", this::dockerSupport); + map.put("container.support", this::containerSupport); map.put("systemd.support", this::systemdSupport); map.put("vm.musl", this::isMusl); map.put("release.implementor", this::implementor); @@ -323,17 +323,6 @@ protected void vmGC(SafeMap map) { for (GC gc: GC.values()) { map.put("vm.gc." + gc.name(), () -> "" + vmGCProperty.test(gc)); } - - // Special handling for ZGC modes - var vmGCZ = vmGCProperty.test(GC.Z); - var genZ = WB.getBooleanVMFlag("ZGenerational"); - var genZIsDefault = WB.isDefaultVMFlag("ZGenerational"); - // vm.gc.ZGenerational=true means: - // vm.gc.Z is true and ZGenerational is either explicitly true, or default - map.put("vm.gc.ZGenerational", () -> "" + (vmGCZ && (genZ || genZIsDefault))); - // vm.gc.ZSinglegen=true means: - // vm.gc.Z is true and ZGenerational is either explicitly false, or default - map.put("vm.gc.ZSinglegen", () -> "" + (vmGCZ && (!genZ || genZIsDefault))); } /** @@ -384,10 +373,10 @@ protected void vmOptFinalFlags(SafeMap map) { vmOptFinalFlag(map, "CriticalJNINatives"); vmOptFinalFlag(map, "EnableJVMCI"); vmOptFinalFlag(map, "EliminateAllocations"); + vmOptFinalFlag(map, "UnlockExperimentalVMOptions"); vmOptFinalFlag(map, "UseCompressedOops"); vmOptFinalFlag(map, "UseLargePages"); vmOptFinalFlag(map, "UseVectorizedMismatchIntrinsic"); - vmOptFinalFlag(map, "ZGenerational"); } /** @@ -478,12 +467,14 @@ protected boolean isCDSRuntimeOptionsCompatible() { } String CCP_DISABLED = "-XX:-UseCompressedClassPointers"; String G1GC_ENABLED = "-XX:+UseG1GC"; + String PARALLELGC_ENABLED = "-XX:+UseParallelGC"; + String SERIALGC_ENABLED = "-XX:+UseSerialGC"; for (String opt : jtropts.split(",")) { if (opt.equals(CCP_DISABLED)) { return false; } if (opt.startsWith(GC_PREFIX) && opt.endsWith(GC_SUFFIX) && - !opt.equals(G1GC_ENABLED)) { + !opt.equals(G1GC_ENABLED) && !opt.equals(PARALLELGC_ENABLED) && !opt.equals(SERIALGC_ENABLED)) { return false; } } @@ -582,16 +573,16 @@ protected String isCompiler2Enabled() { } /** - * A simple check for docker support + * A simple check for container support * - * @return true if docker is supported in a given environment + * @return true if container is supported in a given environment */ - protected String dockerSupport() { - log("Entering dockerSupport()"); + protected String containerSupport() { + log("Entering containerSupport()"); boolean isSupported = false; if (Platform.isLinux()) { - // currently docker testing is only supported for Linux, + // currently container testing is only supported for Linux, // on certain platforms String arch = System.getProperty("os.arch"); @@ -607,17 +598,17 @@ protected String dockerSupport() { } } - log("dockerSupport(): platform check: isSupported = " + isSupported); + log("containerSupport(): platform check: isSupported = " + isSupported); if (isSupported) { try { - isSupported = checkProgramSupport("checkDockerSupport()", Container.ENGINE_COMMAND); + isSupported = checkProgramSupport("checkContainerSupport()", Container.ENGINE_COMMAND); } catch (Exception e) { isSupported = false; } } - log("dockerSupport(): returning isSupported = " + isSupported); + log("containerSupport(): returning isSupported = " + isSupported); return "" + isSupported; } diff --git a/test/langtools/tools/javac/ImportModule.java b/test/langtools/tools/javac/ImportModule.java index f38b77062e224..dc1ed9bd0c12d 100644 --- a/test/langtools/tools/javac/ImportModule.java +++ b/test/langtools/tools/javac/ImportModule.java @@ -797,4 +797,50 @@ public class C {} } } + + @Test + public void testImportModuleNoModules(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeJavaFiles(src, + """ + package test; + import module java.base; + public class Test { + List l; + } + """); + + Files.createDirectories(classes); + + List actualErrors = new JavacTask(tb) + .options("--release", "8", + "-XDshould-stop.at=FLOW", + "-XDdev", + "-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expectedErrors = List.of( + "- compiler.warn.option.obsolete.source: 8", + "- compiler.warn.option.obsolete.target: 8", + "- compiler.warn.option.obsolete.suppression", + "Test.java:2:8: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.module.imports)", + "Test.java:2:1: compiler.err.import.module.not.found: java.base", + "Test.java:4:5: compiler.err.cant.resolve.location: kindname.class, List, , , (compiler.misc.location: kindname.class, test.Test, null)", + "3 errors", + "3 warnings" + ); + + if (!Objects.equals(expectedErrors, actualErrors)) { + throw new AssertionError("Incorrect Output, expected: " + expectedErrors + + ", actual: " + out); + + } + } + } diff --git a/test/langtools/tools/javac/generics/ParametricException.java b/test/langtools/tools/javac/generics/parametricException/ParametricException.java similarity index 100% rename from test/langtools/tools/javac/generics/ParametricException.java rename to test/langtools/tools/javac/generics/parametricException/ParametricException.java diff --git a/test/langtools/tools/javac/inference_non_determinism/NonDeterminismTest.java b/test/langtools/tools/javac/inference_non_determinism/NonDeterminismTest.java new file mode 100644 index 0000000000000..2f245d4f8778e --- /dev/null +++ b/test/langtools/tools/javac/inference_non_determinism/NonDeterminismTest.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. + */ + +/* + * @test + * @bug 8342090 8288590 + * @summary Infer::IncorporationBinaryOp::equals can produce side-effects + * @compile NonDeterminismTest.java + * @compile -J-XX:+UnlockExperimentalVMOptions -J-XX:hashCode=2 NonDeterminismTest.java + */ + +import java.util.*; +import java.lang.foreign.*; +import static java.lang.foreign.ValueLayout.*; + +import static java.util.Arrays.asList; + +class NonDeterminismTest { + void test1() { + Map CANONICAL_LAYOUTS = Map.ofEntries( + // specified canonical layouts + Map.entry("bool", JAVA_BOOLEAN), + Map.entry("char", JAVA_BYTE), + Map.entry("float", JAVA_FLOAT), + Map.entry("long long", JAVA_LONG), + Map.entry("double", JAVA_DOUBLE), + Map.entry("void*", ADDRESS), + // JNI types + Map.entry("jboolean", JAVA_BOOLEAN), + Map.entry("jchar", JAVA_CHAR), + Map.entry("jbyte", JAVA_BYTE), + Map.entry("jshort", JAVA_SHORT), + Map.entry("jint", JAVA_INT), + Map.entry("jlong", JAVA_LONG), + Map.entry("jfloat", JAVA_FLOAT), + Map.entry("jdouble", JAVA_DOUBLE) + ); + } + + class Test2 { + interface I1 {} + interface I2 {} + + record R1(List T1) implements I1 {} + record R2(List T1, List T2) implements I2 {} + + I1 m1(T1 T1) { + return new R1<>(asList(T1)); + } + I2 m2(T1 T1, T2 T2) { + return new R2<>(asList(T1), asList(T2)); + } + } +} diff --git a/test/langtools/tools/javac/modules/AnnotationsOnModules.java b/test/langtools/tools/javac/modules/AnnotationsOnModules.java index bfae27d4d21db..909b5294d00d2 100644 --- a/test/langtools/tools/javac/modules/AnnotationsOnModules.java +++ b/test/langtools/tools/javac/modules/AnnotationsOnModules.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, 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 8159602 8170549 8171255 8171322 8254023 + * @bug 8159602 8170549 8171255 8171322 8254023 8341966 * @summary Test annotations on module declaration. * @library /tools/lib * @enablePreview @@ -35,8 +35,10 @@ */ import java.io.File; +import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -55,6 +57,7 @@ import java.lang.classfile.*; import java.lang.classfile.ClassFile; import java.lang.classfile.attribute.*; +import java.lang.reflect.AccessFlag; import toolbox.JavacTask; import toolbox.Task; import toolbox.Task.OutputKind; @@ -726,6 +729,93 @@ public TestCase(String extraDecl, String decl, String use, String expectedAnnota } } + @Test + public void testBrokenModuleInfoClassWithAnnotation(Path base) throws Exception { + Path lib = base.resolve("lib"); + tb.writeJavaFiles(lib, + """ + @Deprecated + module m{} + """); + + Path libClasses = base.resolve("lib-classes"); + Files.createDirectories(libClasses); + + new JavacTask(tb) + .options("--release", "21") + .outdir(libClasses) + .files(findJavaFiles(lib)) + .run() + .writeAll(); + + Path modifiedModuleInfo = libClasses.resolve("module-info.class"); + ClassModel cm1 = ClassFile.of().parse(modifiedModuleInfo); + byte[] newBytes = ClassFile.of().transformClass(cm1, (builder, element) -> { + if (element instanceof ModuleAttribute attr) { + List requires = new ArrayList<>(); + + for (ModuleRequireInfo mri : attr.requires()) { + if (mri.requires().name().equalsString("java.base")) { + requires.add(ModuleRequireInfo.of(mri.requires(), + List.of(AccessFlag.TRANSITIVE), + mri.requiresVersion() + .orElse(null))); + } else { + requires.add(mri); + } + } + + builder.accept(ModuleAttribute.of(attr.moduleName(), + attr.moduleFlagsMask(), + attr.moduleVersion() + .orElseGet(() -> null), + requires, + attr.exports(), + attr.opens(), + attr.uses(), + attr.provides())); + } else { + builder.accept(element); + } + }); + + try (OutputStream out = Files.newOutputStream(modifiedModuleInfo)) { + out.write(newBytes); + } + + Path src = base.resolve("src"); + Path classes = base.resolve("classes"); + + tb.writeJavaFiles(src, + """ + public class C {} + """); + + Files.createDirectories(classes); + + List actualErrors = + new JavacTask(tb) + .options("--module-path", libClasses.toString(), + "--add-modules", "m", + "-XDshould-stop.at=FLOW", + "-XDdev", + "-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + List expectedErrors = List.of( + "- compiler.err.cant.access: m.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.bad.requires.flag: ACC_TRANSITIVE (0x0020))", + "1 error" + ); + + if (!expectedErrors.equals(actualErrors)) { + throw new AssertionError("Unexpected errors, expected: " + expectedErrors + + ", but got: " + actualErrors); + } + } + private static final String OPT_EXPECTED_ANNOTATIONS = "expectedAnnotations"; @SupportedAnnotationTypes("*") diff --git a/test/langtools/tools/javac/patterns/Switches.java b/test/langtools/tools/javac/patterns/Switches.java index 9adf3cded4052..7d7cb83e02ffc 100644 --- a/test/langtools/tools/javac/patterns/Switches.java +++ b/test/langtools/tools/javac/patterns/Switches.java @@ -28,7 +28,7 @@ /* * @test - * @bug 8262891 8268333 8268896 8269802 8269808 8270151 8269113 8277864 8290709 + * @bug 8262891 8268333 8268896 8269802 8269808 8270151 8269113 8277864 8290709 8339296 * @summary Check behavior of pattern switches. */ public class Switches { @@ -117,6 +117,9 @@ void run() { assertEquals(0, constantAndPatternGuardEnum(E.B, true)); assertEquals(1, constantAndPatternGuardEnum(E.B, false)); assertEquals(2, constantAndPatternGuardEnum(E.A, false)); + assertEquals(0, nestedSwitchesInArgumentPosition(1)); + assertEquals(1, nestedSwitchesInArgumentPosition(new R(1))); + assertEquals(5, nestedSwitchesInArgumentPosition(new R(new R("hello")))); } void run(Function mapper) { @@ -749,6 +752,24 @@ int constantAndPatternGuardEnum(E e, boolean g) { }; } + int nestedSwitchesInArgumentPosition(Object o1) { + return id(switch (o1) { + case R(var o2) -> switch (o2) { + case R(String s) -> s; + default -> "n"; + }; + default -> ""; + }); + } + + int id(String s) { + return s.length(); + } + + int id(int i) { + return i; + } + //verify that for cases like: //case ConstantClassClash -> //ConstantClassClash is interpreted as a field, not as a class diff --git a/test/langtools/tools/javac/processing/model/type/AnnotatedTypeToString/AnnotatedTypeToString.java b/test/langtools/tools/javac/processing/model/type/AnnotatedTypeToString/AnnotatedTypeToString.java index 54538e443462e..6967f271dcdb6 100644 --- a/test/langtools/tools/javac/processing/model/type/AnnotatedTypeToString/AnnotatedTypeToString.java +++ b/test/langtools/tools/javac/processing/model/type/AnnotatedTypeToString/AnnotatedTypeToString.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8284220 + * @bug 8284220 8342934 * @summary Tests DeclaredType.toString with type annotations present, for example that '@A * Map.Entry' is printed as 'java.util.@A Map.Entry' (and not '@A java.util.Map.Entry' or * 'java.util.@A Entry'). diff --git a/test/langtools/tools/javac/processing/model/type/AnnotatedTypeToString/Test.java b/test/langtools/tools/javac/processing/model/type/AnnotatedTypeToString/Test.java index 570407a363a74..8311344ea9dd5 100644 --- a/test/langtools/tools/javac/processing/model/type/AnnotatedTypeToString/Test.java +++ b/test/langtools/tools/javac/processing/model/type/AnnotatedTypeToString/Test.java @@ -32,6 +32,10 @@ @Target(ElementType.TYPE_USE) @interface A {} +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE_USE) +@interface B {} + public class Test { static class StaticNested { static class InnerMostStaticNested {} @@ -41,8 +45,8 @@ class Inner { class InnerMost {} } - @ExpectedToString("p.Test.@p.A StaticNested") - @A StaticNested i; + @ExpectedToString("p.Test.@p.A @p.B StaticNested") + @A @B StaticNested i; @ExpectedToString("p.Test.StaticNested.@p.A InnerMostStaticNested") StaticNested.@A InnerMostStaticNested j; diff --git a/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java b/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java index 3cc1e246e41d9..47b11bbbba84e 100644 --- a/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java +++ b/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8340721 + * @bug 8340721 8341483 * @summary Test invalid inputs to javax.lang.model.util.Types methods * @library /tools/javac/lib * @modules java.compiler @@ -68,8 +68,20 @@ public boolean process(Set annotations, RoundEnvironment roundEnv) { if (!roundEnv.processingOver()) { initializeTypes(); + + // isSubType + // isAssignable + // contains + // directSupertypes testUnboxedType(); + // capture + // getPrimitiveType + // getNoType + testGetArrayType(); testGetWildcardType(); + // getDeclaredType + // getDeclaredType (overload) + // asMemberOf } return true; } @@ -136,15 +148,18 @@ void testUnboxedType() { // Reference types are ArrayType, DeclaredType, ErrorType, NullType, TypeVariable // non-reference: ExecutableType, IntersectionType, NoType, PrimitiveType, UnionType, WildcardType - var invalidInputs = List.of(objectType, stringType, arrayType, - executableType, intersectionType, - noTypeVoid, noTypeNone, noTypePackage, noTypeModule, nullType, - primitiveType, /*unionType, */ wildcardType); + var invalidInputs = + List.of(primitiveType, executableType, + objectType, stringType, arrayType, + intersectionType, /*unionType, */ + noTypeVoid, noTypeNone, noTypePackage, noTypeModule, + nullType, + wildcardType); for (TypeMirror tm : invalidInputs) { try { PrimitiveType pt = types.unboxedType(tm); - throw new RuntimeException("Should not reach " + tm); + shouldNotReach(tm); } catch(IllegalArgumentException iae) { ; // Expected } @@ -152,6 +167,11 @@ void testUnboxedType() { return; } + private void shouldNotReach(TypeMirror tm) { + throw new RuntimeException("Should not reach " + tm + + " " + tm.getKind()); + } + /** * @throws IllegalArgumentException if bounds are not valid, * including for types that are not {@linkplain ReferenceType @@ -160,25 +180,51 @@ void testUnboxedType() { void testGetWildcardType() { // Reference types are ArrayType, DeclaredType, ErrorType, NullType, TypeVariable // non-reference: ExecutableType, IntersectionType, NoType, PrimitiveType, UnionType, WildcardType - var invalidInputs = List.of(executableType, intersectionType, - noTypeVoid, noTypeNone, noTypePackage, noTypeModule, nullType, - primitiveType, /*unionType, */ wildcardType); + var invalidInputs = + List.of(primitiveType, executableType, + intersectionType, /*unionType, */ + noTypeVoid, noTypeNone, noTypePackage, noTypeModule, + nullType, + wildcardType); for (TypeMirror tm : invalidInputs) { try { WildcardType wc1 = types.getWildcardType(tm, null); - throw new RuntimeException("Should not reach " + tm); + shouldNotReach(tm); } catch(IllegalArgumentException iae) { ; // Expected } try { WildcardType wc2 = types.getWildcardType(null, tm); - throw new RuntimeException("Should not reach " + tm); + shouldNotReach(tm); } catch(IllegalArgumentException iae) { ; // Expected } } return; } + + /** + * @throws IllegalArgumentException if the component type is not valid for + * an array. All valid types are {@linkplain ReferenceType + * reference types} or {@linkplain PrimitiveType primitive types}. + * Invalid types include null, executable, package, module, and wildcard types. + */ + void testGetArrayType() { + var invalidInputs = + List.of(executableType, + noTypeVoid, noTypeNone, noTypePackage, noTypeModule, + nullType, + /*unionType, */ wildcardType); + + for (TypeMirror tm : invalidInputs) { + try { + ArrayType arrayType = types.getArrayType(tm); + shouldNotReach(tm); + } catch(IllegalArgumentException iae) { + ; // Expected + } + } + } } diff --git a/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.java b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.java new file mode 100644 index 0000000000000..9e2b7e10080ff --- /dev/null +++ b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.java @@ -0,0 +1,23 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8337980 + * @summary Test compiler crash due to failure to resolve method ambiguity + * @compile/fail/ref=MethodAmbiguityCrash1.out -XDrawDiagnostics MethodAmbiguityCrash1.java + */ +public class MethodAmbiguityCrash1 { + + public interface A { + int op(); + } + + public abstract static class B { + abstract int op(); + } + + public abstract static class C extends B implements A { + + public static int test() { + return op(); // compile should fail here + } + } +} diff --git a/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.out b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.out new file mode 100644 index 0000000000000..ab94e965d598e --- /dev/null +++ b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.out @@ -0,0 +1,2 @@ +MethodAmbiguityCrash1.java:20:20: compiler.err.non-static.cant.be.ref: kindname.method, op() +1 error diff --git a/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.java b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.java new file mode 100644 index 0000000000000..9886e91a7f3d4 --- /dev/null +++ b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.java @@ -0,0 +1,26 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8337980 + * @summary Test compiler crash due to failure to resolve method ambiguity + * @compile/fail/ref=MethodAmbiguityCrash2.out -XDrawDiagnostics MethodAmbiguityCrash2.java + */ +public class MethodAmbiguityCrash2 { + + public interface A { + int op(); + } + + public abstract static class B { + public abstract int op(); + } + + public abstract static class C extends B implements A { + + public C(int x) { + } + + public C() { + this(op()); // compile should fail here + } + } +} diff --git a/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.out b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.out new file mode 100644 index 0000000000000..ace3ffce9cdd7 --- /dev/null +++ b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.out @@ -0,0 +1,2 @@ +MethodAmbiguityCrash2.java:23:18: compiler.err.cant.ref.before.ctor.called: op() +1 error diff --git a/test/langtools/tools/javac/sealed/PrivateMembersInPermitClause.java b/test/langtools/tools/javac/sealed/PrivateMembersInPermitClause.java new file mode 100644 index 0000000000000..0350b74e0e2e6 --- /dev/null +++ b/test/langtools/tools/javac/sealed/PrivateMembersInPermitClause.java @@ -0,0 +1,182 @@ +/* + * 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 8338981 + * @summary Access to private classes should be permitted inside the permits clause of the enclosing top-level class. + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask toolbox.Task + * @run main PrivateMembersInPermitClause -source 19+ + */ +import java.nio.file.Path; +import java.util.Objects; +import toolbox.Task; +import java.util.List; + +public class PrivateMembersInPermitClause extends toolbox.TestRunner { + + private final toolbox.ToolBox tb; + + public PrivateMembersInPermitClause() { + super(System.err); + tb = new toolbox.ToolBox(); + } + + public static void main(String... args) throws Exception { + new PrivateMembersInPermitClause().runTests(); + } + + public void runTests() throws Exception { + runTests(_ -> new Object[] {}); + } + + /** + * Tests that a private class in the permits clause compiles successfully. + */ + @Test + public void privateClassPermitted() throws Exception { + var root = Path.of("src"); + tb.writeJavaFiles(root, + """ + sealed class S permits S.A { + private static final class A extends S {} + } + """ + ); + + new toolbox.JavacTask(tb) + .files(root.resolve("S.java")) + .run(toolbox.Task.Expect.SUCCESS); + } + + /** + * Tests that a private class from another top-level class in the permits clause fails to compile. + */ + @Test + public void otherTopLevelPrivateClassFails() throws Exception { + var root = Path.of("src"); + tb.writeJavaFiles(root, + """ + public class S { + private static final class A extends S {} + } + sealed class T permits S.A { + } + """ + ); + var expectedErrors = List.of( + "S.java:4:25: compiler.err.report.access: S.A, private, S", + "1 error" + ); + + var compileErrors = new toolbox.JavacTask(tb) + .files(root.resolve("S.java")) + .options("-XDrawDiagnostics") + .run(toolbox.Task.Expect.FAIL) + .getOutputLines(Task.OutputKind.DIRECT); + + if (!Objects.equals(compileErrors, expectedErrors)) { + throw new AssertionError("Expected errors: " + expectedErrors + ", but got: " + compileErrors); + } + } + + /** + * Tests that a private class in the permits clause of an inner class compiles successfully. + */ + @Test + public void privateClassInInnerPermitted() throws Exception { + var root = Path.of("src"); + tb.writeJavaFiles(root, + """ + public sealed class S permits S.T.A { + static class T { + private static final class A extends S {} + } + } + """ + ); + + new toolbox.JavacTask(tb) + .files(root.resolve("S.java")) + .run(toolbox.Task.Expect.SUCCESS); + } + + /** + * Tests that a private class in the permits clause contained in a sibling private inner class compiles successfully. + */ + @Test + public void siblingPrivateClassesPermitted() throws Exception { + var root = Path.of("src"); + tb.writeJavaFiles(root, + """ + public class S { + private static class A { + private static class B extends C.D {} + } + private static class C { + private static class D {} + } + } + """ + ); + + new toolbox.JavacTask(tb) + .files(root.resolve("S.java")) + .run(toolbox.Task.Expect.SUCCESS); + } + + /** + * Tests that a private class in the permits clause of a sealed class does not compile when the release is lower than 19. + */ + @Test + public void testSourceLowerThan19() throws Exception { + var root = Path.of("src"); + tb.writeJavaFiles(root, + """ + sealed class S permits S.A { + private static final class A extends S {} + } + """ + ); + + var expectedErrors = List.of( + "S.java:1:25: compiler.err.report.access: S.A, private, S", + "S.java:2:26: compiler.err.cant.inherit.from.sealed: S", + "2 errors" + ); + + var actualOutput = new toolbox.JavacTask(tb) + .files(root.resolve("S.java")) + .options("--release", "18", "-XDrawDiagnostics") + .run(toolbox.Task.Expect.FAIL) + .getOutputLines(Task.OutputKind.DIRECT); + + if (!Objects.equals(actualOutput, expectedErrors)) { + throw new AssertionError("Expected errors: " + expectedErrors + ", but got: " + actualOutput); + } + } +} diff --git a/test/langtools/tools/javac/types/UnknownTypeTest.java b/test/langtools/tools/javac/types/UnknownTypeTest.java new file mode 100644 index 0000000000000..edb4ab3a9be02 --- /dev/null +++ b/test/langtools/tools/javac/types/UnknownTypeTest.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. + */ + +/* + * @test + * @bug 8339296 + * @summary Verify that the UnknownType behaves as an erroneous type + * @library /tools/lib/types + * @modules jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.util + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * @build TypeHarness + * @run main UnknownTypeTest + */ + +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type.TypeVar; +import com.sun.tools.javac.code.Type.UnionClassType; +import com.sun.tools.javac.util.List; +import java.util.Objects; + +public class UnknownTypeTest extends TypeHarness { + + private final Type error; + private final Type unknown; + private final Type[] testTypes; + private final Operation[] testOperations; + + UnknownTypeTest() { + Symtab syms = Symtab.instance(context); + error = syms.errType; + unknown = syms.unknownType; + testTypes = new Type[] { + syms.objectType, + syms.errType, + syms.unknownType, + new TypeVar(syms.unknownSymbol, syms.objectType, syms.objectType), + types.makeIntersectionType(List.of(syms.annotationType, syms.stringType)), + new UnionClassType((Type.ClassType) syms.annotationType, List.of(syms.stringType)), + syms.intType, + types.makeArrayType(syms.stringType) + }; + testOperations = new Operation[] { + types::containedBy, + types::containsType, + types::isAssignable, + types::isCastable, + types::isConvertible, + types::isSameType, + types::isSubtype, + types::isSuperType, + types::isUnconditionallyExact, + (t1, _) -> types.isArray(t1), + (t1, _) -> types.isDerivedRaw(t1), + (t1, _) -> types.isReifiable(t1), + (t1, _) -> types.isUnbounded(t1), + (t1, _) -> types.boxedTypeOrType(t1), + (t1, _) -> types.unboxedType(t1), + (t1, _) -> types.unboxedTypeOrType(t1), + }; + } + + void test(Type[] testTypes, Operation[] testOperations) { + for (int typeIndex = 0; typeIndex < testTypes.length ; typeIndex++) { + for (int operationIndex = 0; operationIndex < testOperations.length ; operationIndex++) { + Object expected; + Object actual; + expected = testOperations[operationIndex].run(error, testTypes[typeIndex]); + actual = testOperations[operationIndex].run(unknown, testTypes[typeIndex]); + checkEquals("Type index: " + typeIndex + ", operationIndex: " + operationIndex + ", unknown in the first position", expected, actual); + expected = testOperations[operationIndex].run(testTypes[typeIndex], error); + actual = testOperations[operationIndex].run(testTypes[typeIndex], unknown); + checkEquals("Type index: " + typeIndex + ", operationIndex: " + operationIndex + ", unknown in the second position", expected, actual); + } + } + } + + void checkEquals(String message, Object expected, Object actual) { + boolean matches; + + if (expected instanceof Type t1 && actual instanceof Type t2) { + matches = types.isSameType(t1, t2); + } else { + matches = Objects.equals(expected, actual); + } + + if (!matches) { + throw new AssertionError("Unexpected outcome: " + actual + + ", expected: " + expected + + ", for test: " + message); + } + } + + void runTests() { + test(testTypes, testOperations); + } + + public static void main(String[] args) { + new UnknownTypeTest().runTests(); + } + + interface Operation { + public Object run(Type t1, Type t2); + } +} diff --git a/test/langtools/tools/javac/warnings/Serial.java b/test/langtools/tools/javac/warnings/Serial/Serial.java similarity index 100% rename from test/langtools/tools/javac/warnings/Serial.java rename to test/langtools/tools/javac/warnings/Serial/Serial.java diff --git a/test/langtools/tools/javac/warnings/Serial.out b/test/langtools/tools/javac/warnings/Serial/Serial.out similarity index 100% rename from test/langtools/tools/javac/warnings/Serial.out rename to test/langtools/tools/javac/warnings/Serial/Serial.out diff --git a/test/langtools/tools/javap/ClassWriterCodeIndentTest.java b/test/langtools/tools/javap/ClassWriterCodeIndentTest.java new file mode 100644 index 0000000000000..993c0a4364a6d --- /dev/null +++ b/test/langtools/tools/javap/ClassWriterCodeIndentTest.java @@ -0,0 +1,113 @@ +/* + * 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 8034066 + * @summary javap incorrect indentation when CodeWriter called via ClassWriter + * @run main ClassWriterCodeIndentTest + * @modules jdk.jdeps/com.sun.tools.javap + */ + +import java.io.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ClassWriterCodeIndentTest { + public static void main(String[] args) { + new ClassWriterCodeIndentTest().run(); + } + + public void run() { + /* + * Partial expected output within a larger file. There exists another "Code: " section above, and thus we + * select the second occurrence in `findNthMatchPrecedingSpaces(output, "Code:", 1);` + * ... + * Code: + * 0: iconst_0 + * 1: istore_1 + * StackMap locals: this int + * StackMap stack: + * ... + */ + String output = javap(); + + int codeHeaderIndent = findNthMatchPrecedingSpaces(output, "Code:", 1); + int detailIndent = findNthMatchPrecedingSpaces(output, "StackMap ", 0); + int bytecodeIndent = findNthMatchPrecedingSpaces(output, "0: iconst_0", 0); + + if (detailIndent - codeHeaderIndent != 2) { + error("Details are not indented correctly with respect to code header."); + } + + if (bytecodeIndent - codeHeaderIndent != 5) { + error("Bytecode is not indented correctly with respect to code header."); + } + + if (errors > 0) { + throw new Error(errors + " found."); + } + } + + String javap() { + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + int rc = com.sun.tools.javap.Main.run(new String[]{"-c", "-XDdetails:stackMaps", + System.getProperty("test.classes") + "/EmptyLoop.class"}, out); + if (rc != 0) + throw new Error("javap failed. rc=" + rc); + out.close(); + System.out.println(sw.toString()); + return sw.toString(); + } + + public static int findNthMatchPrecedingSpaces(String inputString, String searchString, int occurrence) { + String regex = "^(\\s*)" + Pattern.quote(searchString); + Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE); + Matcher matcher = pattern.matcher(inputString); + + int count = 0; + while (matcher.find()) { + if (count == occurrence) { + return matcher.group(1).length(); + } + count++; + } + + throw new Error("Could not find " + searchString + " in " + inputString); + } + + void error(String msg) { + System.err.println(msg); + errors++; + } + + int errors; +} + +class EmptyLoop { + public void emptyLoop() { + for (int i = 0; i < 10; i++) { + } + } +} \ No newline at end of file diff --git a/test/lib-test/jdk/test/lib/util/JarUtilsTest.java b/test/lib-test/jdk/test/lib/util/JarUtilsTest.java new file mode 100644 index 0000000000000..eb9dced32569a --- /dev/null +++ b/test/lib-test/jdk/test/lib/util/JarUtilsTest.java @@ -0,0 +1,77 @@ +/* + * 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 8309841 + * @summary Unit Test for a common Test API in jdk.test.lib.util.JarUtils + * @library /test/lib + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.util.JarUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.stream.Collectors; + +public class JarUtilsTest { + public static void main(String[] args) throws Exception { + Files.createDirectory(Path.of("bx")); + JarUtils.createJarFile(Path.of("a.jar"), + Path.of("."), + Files.writeString(Path.of("a"), ""), + Files.writeString(Path.of("b1"), ""), + Files.writeString(Path.of("b2"), ""), + Files.writeString(Path.of("bx/x"), ""), + Files.writeString(Path.of("c"), ""), + Files.writeString(Path.of("e1"), ""), + Files.writeString(Path.of("e2"), "")); + checkContent("a", "b1", "b2", "bx/x", "c", "e1", "e2"); + + JarUtils.deleteEntries(Path.of("a.jar"), "a"); + checkContent("b1", "b2", "bx/x", "c", "e1", "e2"); + + // Note: b* covers everything starting with b, even bx/x + JarUtils.deleteEntries(Path.of("a.jar"), "b*"); + checkContent("c", "e1", "e2"); + + // d* does not match + JarUtils.deleteEntries(Path.of("a.jar"), "d*"); + checkContent("c", "e1", "e2"); + + // multiple patterns + JarUtils.deleteEntries(Path.of("a.jar"), "d*", "e*"); + checkContent("c"); + } + + static void checkContent(String... expected) throws IOException { + try (var jf = new JarFile("a.jar")) { + Asserts.assertEquals(Set.of(expected), + jf.stream().map(JarEntry::getName).collect(Collectors.toSet())); + } + } +} diff --git a/test/lib/jdk/test/lib/Container.java b/test/lib/jdk/test/lib/Container.java index e0ca4851e144b..83fd265980f26 100644 --- a/test/lib/jdk/test/lib/Container.java +++ b/test/lib/jdk/test/lib/Container.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2019, Red Hat Inc. + * 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,9 +24,9 @@ package jdk.test.lib; public class Container { - // Use this property to specify docker location on your system. + // Use this property to specify container runtime location (e.g. docker) on your system. // E.g.: "/usr/local/bin/docker". We define this constant here so - // that it can be used in VMProps as well which checks docker support + // that it can be used in VMProps as well which checks container support // via this command public static final String ENGINE_COMMAND = System.getProperty("jdk.test.container.command", "docker"); diff --git a/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java b/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java index 6016e48bf4e56..4722ef3b67a95 100644 --- a/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java +++ b/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.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 @@ -26,11 +26,18 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.io.StringWriter; +import java.io.Writer; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import javax.tools.FileObject; import javax.tools.ForwardingJavaFileManager; @@ -76,36 +83,6 @@ * */ public class InMemoryJavaCompiler { - private static class MemoryJavaFileObject extends SimpleJavaFileObject { - private final String className; - private final CharSequence sourceCode; - private final ByteArrayOutputStream byteCode; - - public MemoryJavaFileObject(String className, CharSequence sourceCode) { - super(URI.create("string:///" + className.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE); - this.className = className; - this.sourceCode = sourceCode; - this.byteCode = new ByteArrayOutputStream(); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return sourceCode; - } - - @Override - public OutputStream openOutputStream() throws IOException { - return byteCode; - } - - public byte[] getByteCode() { - return byteCode.toByteArray(); - } - - public String getClassName() { - return className; - } - } private static class FileManagerWrapper extends ForwardingJavaFileManager { private static final Location PATCH_LOCATION = new Location() { @@ -119,12 +96,13 @@ public boolean isOutputLocation() { return false; } }; - private final MemoryJavaFileObject file; + private final SourceFile srcFile; + private ClassFile clsFile; private final String moduleOverride; - public FileManagerWrapper(MemoryJavaFileObject file, String moduleOverride) { + public FileManagerWrapper(SourceFile file, String moduleOverride) { super(getCompiler().getStandardFileManager(null, null, null)); - this.file = file; + this.srcFile = file; this.moduleOverride = moduleOverride; } @@ -132,16 +110,17 @@ public FileManagerWrapper(MemoryJavaFileObject file, String moduleOverride) { public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { - if (!file.getClassName().equals(className)) { - throw new IOException("Expected class with name " + file.getClassName() + + if (!srcFile.getClassName().equals(className)) { + throw new IOException("Expected class with name " + srcFile.getClassName() + ", but got " + className); } - return file; + clsFile = new ClassFile(className); + return clsFile; } @Override public Location getLocationForModule(Location location, JavaFileObject fo) throws IOException { - if (fo == file && moduleOverride != null) { + if (fo == srcFile && moduleOverride != null) { return PATCH_LOCATION; } return super.getLocationForModule(location, fo); @@ -160,6 +139,100 @@ public boolean hasLocation(Location location) { return super.hasLocation(location) || location == StandardLocation.PATCH_MODULE_PATH; } + public byte[] getByteCode() { + return clsFile.toByteArray(); + } + + } + + // Wraper for class file + static class ClassFile extends SimpleJavaFileObject { + + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + protected ClassFile(String name) { + super(URI.create("memo:///" + name.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS); + } + + @Override + public ByteArrayOutputStream openOutputStream() { return this.baos; } + + byte[] toByteArray() { return baos.toByteArray(); } + } + + // File manager which spawns ClassFile instances by demand + static class FileManager extends ForwardingJavaFileManager { + + private Map classesMap = new HashMap(); + + protected FileManager(JavaFileManager fileManager) { + super(fileManager); + } + + @Override + public ClassFile getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject source) { + ClassFile classFile = new ClassFile(name); + classesMap.put(name, classFile); + return classFile; + } + + public Map getByteCode() { + Map result = new HashMap(); + for (Entry entry : classesMap.entrySet()) { + result.put(entry.getKey(), entry.getValue().toByteArray()); + } + return result; + } + } + + // Wrapper for source file + static class SourceFile extends SimpleJavaFileObject { + + private CharSequence sourceCode; + private String className; + + public SourceFile(String name, CharSequence sourceCode) { + super(URI.create("memo:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); + this.sourceCode = sourceCode; + this.className = name; + } + + @Override + public CharSequence getCharContent(boolean ignore) { + return this.sourceCode; + } + + public String getClassName() { + return this.className; + } + } + + /** + * Compiles the list of classes with the given map of name and source code. + * This overloaded version of compile is useful for batch compile use cases. + * + * @param inputMap The map containing the name of the class and corresponding source code + * @throws RuntimeException if the compilation did not succeed + * @return The resulting byte code from the compilation + */ + public static Map compile(Map inputMap) { + Collection sourceFiles = new LinkedList(); + for (Entry entry : inputMap.entrySet()) { + sourceFiles.add(new SourceFile(entry.getKey(), entry.getValue())); + } + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + FileManager fileManager = new FileManager(compiler.getStandardFileManager(null, null, null)); + + Writer writer = new StringWriter(); + Boolean exitCode = compiler.getTask(writer, fileManager, null, null, null, sourceFiles).call(); + if (!exitCode) { + System.out.println("*********** javac output begin ***********"); + System.out.println(writer.toString()); + System.out.println("*********** javac output end ***********"); + throw new RuntimeException("Test bug: in memory compilation failed."); + } + return fileManager.getByteCode(); } /** @@ -173,7 +246,7 @@ public boolean hasLocation(Location location) { * @return The resulting byte code from the compilation */ public static byte[] compile(String className, CharSequence sourceCode, String... options) { - MemoryJavaFileObject file = new MemoryJavaFileObject(className, sourceCode); + SourceFile file = new SourceFile(className, sourceCode); List opts = new ArrayList<>(); String moduleOverride = null; for (String opt : options) { @@ -183,13 +256,13 @@ public static byte[] compile(String className, CharSequence sourceCode, String.. opts.add(opt); } } - try (JavaFileManager fileManager = new FileManagerWrapper(file, moduleOverride)) { + try (FileManagerWrapper fileManager = new FileManagerWrapper(file, moduleOverride)) { CompilationTask task = getCompiler().getTask(null, fileManager, null, opts, null, Arrays.asList(file)); if (!task.call()) { throw new RuntimeException("Could not compile " + className + " with source code " + sourceCode); } - return file.getByteCode(); + return fileManager.getByteCode(); } catch (IOException ioe) { throw new RuntimeException(ioe); } diff --git a/test/lib/jdk/test/lib/security/DiffieHellmanGroup.java b/test/lib/jdk/test/lib/security/DiffieHellmanGroup.java new file mode 100644 index 0000000000000..b8f7c0c34beec --- /dev/null +++ b/test/lib/jdk/test/lib/security/DiffieHellmanGroup.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.security; + +import java.math.BigInteger; + +/** + * An enumeration of DH groups for tests. + */ +public enum DiffieHellmanGroup { + + /** + * RFC 7919 - ffdhe2048. + */ + ffdhe2048(new BigInteger("FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B423861285C97FFFFFFFFFFFFFFFF", 16), 2), + /** + * RFC 7919 - ffdhe3072. + */ + ffdhe3072(new BigInteger("FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF", 16), 2), + /** + * RFC 7919 - ffdhe4096. + */ + ffdhe4096(new BigInteger("FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A" + + "FFFFFFFFFFFFFFFF", 16), 2); + + + public BigInteger getPrime() { + return prime; + } + + private final BigInteger prime; + + public BigInteger getBase() { + return base; + } + + private final BigInteger base; + + DiffieHellmanGroup(BigInteger prime, int base) { + this.prime = prime; + this.base = BigInteger.valueOf(base); + } +} diff --git a/test/lib/jdk/test/lib/security/SecurityUtils.java b/test/lib/jdk/test/lib/security/SecurityUtils.java index 319416a466c22..2885440e2a29a 100644 --- a/test/lib/jdk/test/lib/security/SecurityUtils.java +++ b/test/lib/jdk/test/lib/security/SecurityUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,12 +30,34 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.test.lib.security.DiffieHellmanGroup; /** * Common library for various security test helper functions. */ public final class SecurityUtils { + /* + * Key Sizes for various algorithms. + */ + private enum KeySize{ + RSA(2048), + DSA(2048), + DH(2048); + + private final int keySize; + KeySize(int keySize) { + this.keySize = keySize; + } + + @Override + public String toString() { + return String.valueOf(keySize); + } + } + + private final static int DEFAULT_SALTSIZE = 16; + private static String getCacerts() { String sep = File.separator; return System.getProperty("java.home") + sep @@ -107,6 +129,44 @@ public static void removeAlgsFromDSigPolicy(String... algs) { removeFromDSigPolicy("disallowAlg", List.of(algs)); } + /** + * Returns a salt size for tests + */ + public static int getTestSaltSize() { + return DEFAULT_SALTSIZE; + } + + /** + * Returns a key size in bits for tests, depending on the specified algorithm + */ + public static int getTestKeySize(String algo) { + return switch (algo) { + case "RSA" -> KeySize.RSA.keySize; + case "DSA" -> KeySize.DSA.keySize; + case "DH", "DiffieHellman" -> KeySize.DH.keySize; + default -> throw new RuntimeException("Test key size not defined for " + algo); + }; + } + + /** + * Returns a DH predefined group for tests + */ + public static DiffieHellmanGroup getTestDHGroup() { + return getTestDHGroup(2048); + } + + /** + * Returns a DH predefined group for tests, depending on the specified prime size + */ + public static DiffieHellmanGroup getTestDHGroup(int primeSize) { + return switch(primeSize) { + case 2048 -> DiffieHellmanGroup.ffdhe2048; + case 3072 -> DiffieHellmanGroup.ffdhe3072; + case 4096 -> DiffieHellmanGroup.ffdhe4096; + default -> throw new RuntimeException("Test DH group not defined for " + primeSize); + }; + } + private static void removeFromDSigPolicy(String rule, List algs) { String value = Security.getProperty("jdk.xml.dsig.secureValidationPolicy"); value = Arrays.stream(value.split(",")) diff --git a/test/lib/jdk/test/lib/util/JarUtils.java b/test/lib/jdk/test/lib/util/JarUtils.java index e1b3ccac19fc5..3aa4ada5197ad 100644 --- a/test/lib/jdk/test/lib/util/JarUtils.java +++ b/test/lib/jdk/test/lib/util/JarUtils.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 @@ -320,6 +320,57 @@ public static void updateManifest(String src, String dest, Manifest man) updateJar(src, dest, Map.of(JarFile.MANIFEST_NAME, bout.toByteArray())); } + /** + * Remove entries from a ZIP file. + * + * Each entry can be a name or a name ending with "*". + * + * @return number of removed entries + * @throws IOException if there is any I/O error + */ + public static int deleteEntries(Path jarfile, String... patterns) + throws IOException { + Path tmpfile = Files.createTempFile("jar", "jar"); + int count = 0; + + try (OutputStream out = Files.newOutputStream(tmpfile); + JarOutputStream jos = new JarOutputStream(out)) { + try (JarFile jf = new JarFile(jarfile.toString())) { + Enumeration jentries = jf.entries(); + top: while (jentries.hasMoreElements()) { + JarEntry jentry = jentries.nextElement(); + String name = jentry.getName(); + for (String pattern : patterns) { + if (pattern.endsWith("*")) { + if (name.startsWith(pattern.substring( + 0, pattern.length() - 1))) { + // Go directly to next entry. This + // one is not written into `jos` and + // therefore removed. + count++; + continue top; + } + } else { + if (name.equals(pattern)) { + // Same as above + count++; + continue top; + } + } + } + // No pattern matched, file retained + jos.putNextEntry(copyEntry(jentry)); + jf.getInputStream(jentry).transferTo(jos); + } + } + } + + // replace the original JAR file + Files.move(tmpfile, jarfile, StandardCopyOption.REPLACE_EXISTING); + + return count; + } + private static void updateEntry(JarOutputStream jos, String name, Object content) throws IOException { if (content instanceof Boolean) { diff --git a/test/micro/org/openjdk/bench/java/io/DataOutputStreamBench.java b/test/micro/org/openjdk/bench/java/io/DataOutputStreamBench.java new file mode 100644 index 0000000000000..34568110dde53 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/io/DataOutputStreamBench.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.io; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.HexFormat; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Fork(2) +@Measurement(iterations = 6, time = 1) +@Warmup(iterations = 4, time = 2) +@State(Scope.Thread) +public class DataOutputStreamBench { + + @Param({"ascii", "utf8_2_bytes", "utf8_3_bytes", "emoji"}) + public String charType; + + ByteArrayOutputStream bytesOutput; + DataOutputStream dataOutput; + ObjectOutputStream objectOutput; + String[] strings; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] bytes = HexFormat.of().parseHex( + switch (charType) { + case "ascii" -> "78"; + case "utf8_2_bytes" -> "c2a9"; + case "utf8_3_bytes" -> "e6b8a9"; + case "emoji" -> "e29da3efb88f"; + default -> throw new IllegalArgumentException("bad charType: " + charType); + } + ); + String s = new String(bytes, 0, bytes.length, StandardCharsets.UTF_8); + strings = new String[128]; + for (int i = 0; i < strings.length; i++) { + strings[i] = "A".repeat(i).concat(s.repeat(i)); + } + + bytesOutput = new ByteArrayOutputStream(1024 * 64); + dataOutput = new DataOutputStream(bytesOutput); + objectOutput = new ObjectOutputStream(bytesOutput); + } + + @Benchmark + public void dataOutwriteUTF(Blackhole bh) throws Exception { + bytesOutput.reset(); + for (var s : strings) { + dataOutput.writeUTF(s); + } + dataOutput.flush(); + bh.consume(bytesOutput.size()); + } + + @Benchmark + public void objectWriteUTF(Blackhole bh) throws Exception { + bytesOutput.reset(); + for (var s : strings) { + objectOutput.writeUTF(s); + } + objectOutput.flush(); + bh.consume(bytesOutput.size()); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/CallerClassBench.java b/test/micro/org/openjdk/bench/java/lang/CallerClassBench.java index 01399c7c2700f..742c1c29b7afb 100644 --- a/test/micro/org/openjdk/bench/java/lang/CallerClassBench.java +++ b/test/micro/org/openjdk/bench/java/lang/CallerClassBench.java @@ -36,7 +36,7 @@ @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 3, jvmArgsAppend = {"-Xmx1g", "-Xms1g"}) +@Fork(value = 3, jvmArgs = {"-Xmx1g", "-Xms1g"}) @State(Scope.Benchmark) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) diff --git a/test/micro/org/openjdk/bench/java/lang/ObjectHashCode.java b/test/micro/org/openjdk/bench/java/lang/ObjectHashCode.java index 9b89f6d1b5a4d..3cc836cd59e2a 100644 --- a/test/micro/org/openjdk/bench/java/lang/ObjectHashCode.java +++ b/test/micro/org/openjdk/bench/java/lang/ObjectHashCode.java @@ -50,37 +50,37 @@ public int mode_default() { // Experimental hashCode generation schemes. See synchronizer.cpp get_next_hash /* @Benchmark - @Fork(jvmArgsPrepend = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=0"}) + @Fork(jvmArgs = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=0"}) public int mode_0() { return System.identityHashCode(new Object()); } @Benchmark - @Fork(jvmArgsPrepend = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=1"}) + @Fork(jvmArgs = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=1"}) public int mode_1() { return System.identityHashCode(new Object()); } @Benchmark - @Fork(jvmArgsPrepend = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=2"}) + @Fork(jvmArgs = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=2"}) public int mode_2() { return System.identityHashCode(new Object()); } @Benchmark - @Fork(jvmArgsPrepend = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=3"}) + @Fork(jvmArgs = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=3"}) public int mode_3() { return System.identityHashCode(new Object()); } @Benchmark - @Fork(jvmArgsPrepend = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=4"}) + @Fork(jvmArgs = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=4"}) public int mode_4() { return System.identityHashCode(new Object()); } @Benchmark - @Fork(jvmArgsPrepend = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=5"}) + @Fork(jvmArgs = {"-XX:+UnlockExperimentalVMOptions", "-XX:hashCode=5"}) public int mode_5() { return System.identityHashCode(new Object()); } diff --git a/test/micro/org/openjdk/bench/java/lang/ScopedValues.java b/test/micro/org/openjdk/bench/java/lang/ScopedValues.java index f11bc805b7f37..70c97d5755116 100644 --- a/test/micro/org/openjdk/bench/java/lang/ScopedValues.java +++ b/test/micro/org/openjdk/bench/java/lang/ScopedValues.java @@ -40,7 +40,7 @@ @Measurement(iterations=10, time=1) @Threads(1) @Fork(value = 1, - jvmArgsPrepend = {"-Djmh.executor.class=org.openjdk.bench.java.lang.ScopedValuesExecutorService", + jvmArgs = {"-Djmh.executor.class=org.openjdk.bench.java.lang.ScopedValuesExecutorService", "-Djmh.executor=CUSTOM", "-Djmh.blackhole.mode=COMPILER", "--enable-preview"}) diff --git a/test/micro/org/openjdk/bench/java/lang/StringHashCode.java b/test/micro/org/openjdk/bench/java/lang/StringHashCode.java index 20735a3bf7662..5578712f0f980 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringHashCode.java +++ b/test/micro/org/openjdk/bench/java/lang/StringHashCode.java @@ -96,7 +96,7 @@ public int empty() { @State(Scope.Thread) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) - @Fork(value = 3, jvmArgsAppend = {"--add-exports", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED"}) + @Fork(value = 3, jvmArgs = {"--add-exports", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED"}) public static class Algorithm { private final static String alphabet = "abcdefghijklmnopqrstuvwxyz"; diff --git a/test/micro/org/openjdk/bench/java/lang/classfile/TypeKindBench.java b/test/micro/org/openjdk/bench/java/lang/classfile/TypeKindBench.java index c8d9ad85d548e..43d94f0385a32 100644 --- a/test/micro/org/openjdk/bench/java/lang/classfile/TypeKindBench.java +++ b/test/micro/org/openjdk/bench/java/lang/classfile/TypeKindBench.java @@ -50,7 +50,7 @@ @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 3, time = 2) @Measurement(iterations = 6, time = 1) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @State(Scope.Thread) public class TypeKindBench { diff --git a/test/micro/org/openjdk/bench/java/lang/classfile/Utf8EntryWriteTo.java b/test/micro/org/openjdk/bench/java/lang/classfile/Utf8EntryWriteTo.java index a124b0792688a..db27d3186993a 100644 --- a/test/micro/org/openjdk/bench/java/lang/classfile/Utf8EntryWriteTo.java +++ b/test/micro/org/openjdk/bench/java/lang/classfile/Utf8EntryWriteTo.java @@ -56,7 +56,7 @@ @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 1, time = 2) @Measurement(iterations = 3, time = 1) -@Fork(jvmArgsAppend = "--enable-preview", value = 3) +@Fork(jvmArgs = "--enable-preview", value = 3) @State(Scope.Thread) public class Utf8EntryWriteTo { static final ClassDesc STRING_BUILDER = ClassDesc.ofDescriptor("Ljava/lang/StringBuilder;"); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java index 390add8801ce0..16a915af2ed42 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java @@ -45,7 +45,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED" }) public class AllocFromSliceTest extends CLayouts { @Param({"5", "20", "100", "500", "1000"}) diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromTest.java index fcd79870ca0bf..520c1ad5a9bc4 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromTest.java @@ -48,7 +48,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED" }) public class AllocFromTest extends CLayouts { Arena arena = Arena.ofConfined(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/AllocTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/AllocTest.java index 4ae2c0364dc56..d9b268a1846a2 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/AllocTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/AllocTest.java @@ -50,7 +50,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED" }) public class AllocTest extends CLayouts { Arena arena = Arena.ofConfined(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CallByRefHighArity.java b/test/micro/org/openjdk/bench/java/lang/foreign/CallByRefHighArity.java new file mode 100644 index 0000000000000..417a7c39c1a55 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CallByRefHighArity.java @@ -0,0 +1,247 @@ +/* + * 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 org.openjdk.bench.java.lang.foreign; + +import org.openjdk.jmh.annotations.*; + +import java.lang.foreign.*; +import java.lang.invoke.*; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(org.openjdk.jmh.annotations.Scope.Thread) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +public class CallByRefHighArity { + + static { + System.loadLibrary("CallByRefHighArity"); + } + + @Param + SegmentKind kind; + + public enum SegmentKind { + CONFINED, + SHARED, + GLOBAL, + HEAP + } + + Supplier segmentSupplier; + Arena arena; + + @Setup + public void setup() { + if (kind == SegmentKind.CONFINED) { + arena = Arena.ofConfined(); + MemorySegment segment = arena.allocateFrom(ValueLayout.JAVA_INT, 0); + segmentSupplier = () -> segment; + } else if (kind == SegmentKind.SHARED) { + arena = Arena.ofShared(); + MemorySegment segment = arena.allocateFrom(ValueLayout.JAVA_INT, 0); + segmentSupplier = () -> segment; + } else if (kind == SegmentKind.HEAP) { + byte[] array = new byte[8]; + MemorySegment segment = MemorySegment.ofArray(array); + segmentSupplier = () -> segment; + } else { // global + segmentSupplier = () -> MemorySegment.ofAddress(0); + } + } + + @TearDown + public void tearDown() { + if (arena != null) { + arena.close(); + } + } + + // A shared library that exports the functions below + private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); + + // void noop_params0() {} + private static final MethodHandle MH_NOOP_PARAMS0 = Linker.nativeLinker() + .downcallHandle(FunctionDescriptor.ofVoid(), Linker.Option.critical(true)) + .bindTo(LOOKUP.find("noop_params0").orElseThrow()); + + // void noop_params1(void *param0) {} + private static final MethodHandle MH_NOOP_PARAMS1 = Linker.nativeLinker() + .downcallHandle(FunctionDescriptor.ofVoid( + ValueLayout.ADDRESS + ), Linker.Option.critical(true)) + .bindTo(LOOKUP.find("noop_params1").orElseThrow()); + + // void noop_params2(void *param0, void *param1) {} + private static final MethodHandle MH_NOOP_PARAMS2 = Linker.nativeLinker() + .downcallHandle(FunctionDescriptor.ofVoid( + ValueLayout.ADDRESS, + ValueLayout.ADDRESS + ), Linker.Option.critical(true)) + .bindTo(LOOKUP.find("noop_params2").orElseThrow()); + + // void noop_params3(void *param0, void *param1, void *param2) {} + private static final MethodHandle MH_NOOP_PARAMS3 = Linker.nativeLinker() + .downcallHandle(FunctionDescriptor.ofVoid( + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS + ), Linker.Option.critical(true)) + .bindTo(LOOKUP.find("noop_params3").orElseThrow()); + + // void noop_params4(void *param0, void *param1, void *param2, void *param3) {} + private static final MethodHandle MH_NOOP_PARAMS4 = Linker.nativeLinker() + .downcallHandle(FunctionDescriptor.ofVoid( + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS + ), Linker.Option.critical(true)) + .bindTo(LOOKUP.find("noop_params4").orElseThrow()); + + // void noop_params5(int param0, int param1, void *param2, void *param3, void *param4) {} + private static final MethodHandle MH_NOOP_PARAMS5 = Linker.nativeLinker() + .downcallHandle(FunctionDescriptor.ofVoid( + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS + ), Linker.Option.critical(true)) + .bindTo(LOOKUP.find("noop_params5").orElseThrow()); + + // void noop_params10(void *param0, void *param1, void *param2, void *param3, void *param4, + // void *param5, void *param6, void *param7, void *param8, void *param9) {} + private static final MethodHandle MH_NOOP_PARAMS10 = Linker.nativeLinker() + .downcallHandle(FunctionDescriptor.ofVoid( + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS + ), Linker.Option.critical(true)) + .bindTo(LOOKUP.find("noop_params10").orElseThrow()); + + @Benchmark + public void noop_params0() { + try { + MH_NOOP_PARAMS0.invokeExact(); + } catch (Throwable t) { + throw new AssertionError(t); + } + } + + @Benchmark + public void noop_params1() { + try { + MH_NOOP_PARAMS1.invokeExact( + segmentSupplier.get() + ); + } catch (Throwable t) { + throw new AssertionError(t); + } + } + + @Benchmark + public void noop_params2() { + try { + MH_NOOP_PARAMS2.invokeExact( + segmentSupplier.get(), + segmentSupplier.get() + ); + } catch (Throwable t) { + throw new AssertionError(t); + } + } + + @Benchmark + public void noop_params3() { + try { + MH_NOOP_PARAMS3.invokeExact( + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get() + ); + } catch (Throwable t) { + throw new AssertionError(t); + } + } + + @Benchmark + public void noop_params4() { + try { + MH_NOOP_PARAMS4.invokeExact( + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get() + ); + } catch (Throwable t) { + throw new AssertionError(t); + } + } + + @Benchmark + public void noop_params5() { + try { + MH_NOOP_PARAMS5.invokeExact( + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get() + ); + } catch (Throwable t) { + throw new AssertionError(t); + } + } + + @Benchmark + public void noop_params10() { + try { + MH_NOOP_PARAMS10.invokeExact( + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get(), + segmentSupplier.get() + ); + } catch (Throwable t) { + throw new AssertionError(t); + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadConstant.java b/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadConstant.java index 7f20d094b8e62..8e618da44ad0d 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadConstant.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadConstant.java @@ -41,7 +41,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class CallOverheadConstant { @Benchmark diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadVirtual.java b/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadVirtual.java index d6b7028d287b9..274c11a87cf04 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadVirtual.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadVirtual.java @@ -41,7 +41,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class CallOverheadVirtual { @Benchmark diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CriticalCalls.java b/test/micro/org/openjdk/bench/java/lang/foreign/CriticalCalls.java index 0f384f816853d..1b62d2c72643e 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/CriticalCalls.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CriticalCalls.java @@ -51,7 +51,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class CriticalCalls { static final MethodHandle PINNED; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/InternalStrLen.java b/test/micro/org/openjdk/bench/java/lang/foreign/InternalStrLen.java index 81ed675c7d92b..2db15bfe2652d 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/InternalStrLen.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/InternalStrLen.java @@ -50,7 +50,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = {"--add-exports=java.base/jdk.internal.foreign=ALL-UNNAMED", "--enable-native-access=ALL-UNNAMED", "--enable-preview"}) +@Fork(value = 3, jvmArgs = {"--add-exports=java.base/jdk.internal.foreign=ALL-UNNAMED", "--enable-native-access=ALL-UNNAMED", "--enable-preview"}) public class InternalStrLen { private MemorySegment singleByteSegment; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LinkUpcall.java b/test/micro/org/openjdk/bench/java/lang/foreign/LinkUpcall.java index 57c8bd029baf4..bf1d35801d2fc 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LinkUpcall.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LinkUpcall.java @@ -47,7 +47,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.MICROSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED" }) public class LinkUpcall extends CLayouts { static final Linker LINKER = Linker.nativeLinker(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java new file mode 100644 index 0000000000000..834d051cff0d6 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.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. + */ +package org.openjdk.bench.java.lang.foreign; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.CompilerControl; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import sun.misc.Unsafe; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Proxy; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import static java.lang.foreign.ValueLayout.*; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(org.openjdk.jmh.annotations.Scope.Thread) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Fork(value = 3, jvmArgs = { "-XX:-TieredCompilation" }) +public class LoopOverNonConstantAsType extends JavaLayouts { + + static final Unsafe unsafe = Utils.unsafe; + + static final int ELEM_SIZE = 1_000_000; + static final int CARRIER_SIZE = (int)JAVA_LONG.byteSize(); + static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; + + @Param({"false", "true"}) + public boolean asTypeCompiled; + + Arena arena; + MemorySegment segment; + long unsafe_addr; + + @Setup + public void setup() { + unsafe_addr = unsafe.allocateMemory(ALLOC_SIZE); + for (int i = 0; i < ELEM_SIZE; i++) { + unsafe.putInt(unsafe_addr + (i * CARRIER_SIZE) , i); + } + arena = Arena.ofConfined(); + segment = arena.allocate(ALLOC_SIZE, 1); + for (int i = 0; i < ELEM_SIZE; i++) { + VH_INT.set(segment, (long) i, i); + } + if (asTypeCompiled) { + compileAsType(); + } + } + + public interface T { } + + static final int TYPE_SIZE = 100; + static final Class[] types; + + static { + types = new Class[TYPE_SIZE]; + ClassLoader customLoader = new URLClassLoader(new URL[0], LoopOverNonConstantAsType.class.getClassLoader()); + for (int i = 0 ; i < TYPE_SIZE ; i++) { + types[i] = Proxy.newProxyInstance(customLoader, + new Class[] { T.class }, (_, _, _) -> null).getClass(); + } + } + + void compileAsType() { + for (Class type : types) { + MethodHandle handle = MethodHandles.zero(Object.class); + Class[] args = new Class[254]; + Arrays.fill(args, Object.class); + handle = MethodHandles.dropArguments(handle, 0, args); + for (int j = 0; j < args.length ; j++) { + handle = handle.asType(handle.type().changeParameterType(j, type)); + } + } + } + + @TearDown + public void tearDown() { + arena.close(); + unsafe.freeMemory(unsafe_addr); + } + + @Benchmark + public long unsafe_loop() { + long res = 0; + for (int i = 0; i < ELEM_SIZE; i ++) { + res += unsafe.getLong(unsafe_addr + (i * CARRIER_SIZE)); + } + return res; + } + + @Benchmark + public long segment_loop() { + long sum = 0; + for (int i = 0; i < ELEM_SIZE; i++) { + sum += segment.get(JAVA_LONG, i * CARRIER_SIZE); + } + return sum; + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverOfAddress.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverOfAddress.java index 740d8a2c78337..91f2c9e457964 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverOfAddress.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverOfAddress.java @@ -43,7 +43,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED" }) public class LoopOverOfAddress extends JavaLayouts { static final int ITERATIONS = 1_000_000; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentCopyUnsafe.java b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentCopyUnsafe.java index 4b6db5f961832..c5cdd26016dd0 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentCopyUnsafe.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentCopyUnsafe.java @@ -45,7 +45,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = {"--enable-native-access=ALL-UNNAMED"}) +@Fork(value = 3, jvmArgs = {"--enable-native-access=ALL-UNNAMED"}) public class MemorySegmentCopyUnsafe { static final Unsafe UNSAFE = Utils.unsafe; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentGetUnsafe.java b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentGetUnsafe.java index 233c967293545..31303e5114115 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentGetUnsafe.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentGetUnsafe.java @@ -50,7 +50,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = {"--enable-native-access=ALL-UNNAMED"}) +@Fork(value = 3, jvmArgs = {"--enable-native-access=ALL-UNNAMED"}) public class MemorySegmentGetUnsafe { static final Unsafe UNSAFE = Utils.unsafe; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentZeroUnsafe.java b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentZeroUnsafe.java index ba705e2ecd4db..6a52ed3fc5b18 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentZeroUnsafe.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentZeroUnsafe.java @@ -44,7 +44,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = {"--enable-native-access=ALL-UNNAMED"}) +@Fork(value = 3, jvmArgs = {"--enable-native-access=ALL-UNNAMED"}) public class MemorySegmentZeroUnsafe { static final Unsafe UNSAFE = Utils.unsafe; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/PointerInvoke.java b/test/micro/org/openjdk/bench/java/lang/foreign/PointerInvoke.java index ab77ae630c1cf..63975e47c7dde 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/PointerInvoke.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/PointerInvoke.java @@ -43,7 +43,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class PointerInvoke extends CLayouts { Arena arena = Arena.ofConfined(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/QSort.java b/test/micro/org/openjdk/bench/java/lang/foreign/QSort.java index 76298ae073993..b21e812c50317 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/QSort.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/QSort.java @@ -46,7 +46,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class QSort extends CLayouts { static final Linker abi = Linker.nativeLinker(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java index 22ef139aac08a..ca6f21d20e99c 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java @@ -84,25 +84,25 @@ public void bufferCopy() { dstBuffer.put(srcBuffer); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.copy=31"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=31"}) @Benchmark public void heapSegmentCopyJava() { MemorySegment.copy(heapSrcSegment, 0, heapDstSegment, 0, ELEM_SIZE); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.copy=0"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=0"}) @Benchmark public void heapSegmentCopyUnsafe() { MemorySegment.copy(heapSrcSegment, 0, heapDstSegment, 0, ELEM_SIZE); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.copy=31"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=31"}) @Benchmark public void nativeSegmentCopyJava() { MemorySegment.copy(nativeSrcSegment, 0, nativeDstSegment, 0, ELEM_SIZE); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.copy=0"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=0"}) @Benchmark public void nativeSegmentCopyUnsafe() { MemorySegment.copy(nativeSrcSegment, 0, nativeDstSegment, 0, ELEM_SIZE); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java index 95ca722896944..eb19fc56ac28e 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java @@ -74,37 +74,37 @@ public void arraysFill() { Arrays.fill(array, (byte) 0); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) @Benchmark public void heapSegmentFillJava() { heapSegment.fill((byte) 0); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) @Benchmark public void heapSegmentFillUnsafe() { heapSegment.fill((byte) 0); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) @Benchmark public void nativeSegmentFillJava() { nativeSegment.fill((byte) 0); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) @Benchmark public void nativeSegmentFillUnsafe() { nativeSegment.fill((byte) 0); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) @Benchmark public void unalignedSegmentFillJava() { unalignedSegment.fill((byte) 0); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) @Benchmark public void unalignedSegmentFillUnsafe() { unalignedSegment.fill((byte) 0); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java index 5656b2f6b9f74..61ceb7b956ee4 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java @@ -79,25 +79,25 @@ public void setup() { dstHeap = MemorySegment.ofArray(dstArray); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.mismatch=31"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=31"}) @Benchmark public long nativeSegmentJava() { return srcNative.mismatch(dstNative); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.mismatch=31"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=31"}) @Benchmark public long heapSegmentJava() { return srcHeap.mismatch(dstHeap); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.mismatch=0"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=0"}) @Benchmark public long nativeSegmentUnsafe() { return srcNative.mismatch(dstNative); } - @Fork(value = 3, jvmArgsAppend = {"-Djava.lang.foreign.native.threshold.power.mismatch=0"}) + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=0"}) @Benchmark public long heapSegmentUnsafe() { return srcHeap.mismatch(dstHeap); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/StrLenTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/StrLenTest.java index 2ad723eadf321..04562e0ec00ee 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/StrLenTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/StrLenTest.java @@ -48,7 +48,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class StrLenTest extends CLayouts { Arena arena = Arena.ofConfined(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/ToCStringTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/ToCStringTest.java index 7ba9384958e22..41d7deb2ebe4b 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/ToCStringTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/ToCStringTest.java @@ -51,7 +51,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class ToCStringTest extends CLayouts { @Param({"5", "20", "100", "200"}) diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/ToJavaStringTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/ToJavaStringTest.java index f6f26f72a6a03..02b1a47d03fe2 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/ToJavaStringTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/ToJavaStringTest.java @@ -43,7 +43,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "--enable-preview", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "--enable-preview", "-Djava.library.path=micro/native" }) public class ToJavaStringTest { private MemorySegment strSegment; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/UnrolledAccess.java b/test/micro/org/openjdk/bench/java/lang/foreign/UnrolledAccess.java index 6888f82e529a3..36c2ba32887ab 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/UnrolledAccess.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/UnrolledAccess.java @@ -40,7 +40,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.MICROSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED" }) public class UnrolledAccess extends JavaLayouts { static final Unsafe U = Utils.unsafe; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/Upcalls.java b/test/micro/org/openjdk/bench/java/lang/foreign/Upcalls.java index 1b852e6ff9df0..9b6ec3fe05828 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/Upcalls.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/Upcalls.java @@ -45,7 +45,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class Upcalls extends CLayouts { static final Linker abi = Linker.nativeLinker(); diff --git a/src/hotspot/os/bsd/gc/x/xNUMA_bsd.cpp b/test/micro/org/openjdk/bench/java/lang/foreign/libCallByRefHighArity.c similarity index 60% rename from src/hotspot/os/bsd/gc/x/xNUMA_bsd.cpp rename to test/micro/org/openjdk/bench/java/lang/foreign/libCallByRefHighArity.c index b0e23a1716ad9..02eedb79f0236 100644 --- a/src/hotspot/os/bsd/gc/x/xNUMA_bsd.cpp +++ b/test/micro/org/openjdk/bench/java/lang/foreign/libCallByRefHighArity.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,23 +21,13 @@ * questions. */ -#include "precompiled.hpp" -#include "gc/x/xNUMA.hpp" -#include "utilities/globalDefinitions.hpp" +#include "export.h" -void XNUMA::pd_initialize() { - _enabled = false; -} - -uint32_t XNUMA::count() { - return 1; -} - -uint32_t XNUMA::id() { - return 0; -} - -uint32_t XNUMA::memory_id(uintptr_t addr) { - // NUMA support not enabled, assume everything belongs to node zero - return 0; -} +EXPORT void noop_params0() {} +EXPORT void noop_params1(void *param0) {} +EXPORT void noop_params2(void *param0, void *param1) {} +EXPORT void noop_params3(void *param0, void *param1, void *param2) {} +EXPORT void noop_params4(void *param0, void *param1, void *param2, void *param3) {} +EXPORT void noop_params5(void *param0, void *param1, void *param2, void *param3, void *param4) {} +EXPORT void noop_params10(void *param0, void *param1, void *param2, void *param3, void *param4, + void *param5, void *param6, void *param7, void *param8, void *param9) {} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/pointers/PointerBench.java b/test/micro/org/openjdk/bench/java/lang/foreign/pointers/PointerBench.java index 9eabd7d0e7851..b93b613f8c6f4 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/pointers/PointerBench.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/pointers/PointerBench.java @@ -46,7 +46,7 @@ @Warmup(iterations = 3, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @OutputTimeUnit(TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED" }) @State(Scope.Benchmark) public class PointerBench { diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAccess.java b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAccess.java index e649468fc9765..eeedf18c7712f 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAccess.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAccess.java @@ -43,7 +43,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class PointsAccess { BBPoint BBPoint; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAlloc.java b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAlloc.java index f9d254ed97521..a210e459c21a3 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAlloc.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAlloc.java @@ -41,7 +41,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class PointsAlloc { @Benchmark diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsDistance.java b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsDistance.java index fa86137ff0211..a42b8ac09471e 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsDistance.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsDistance.java @@ -43,7 +43,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class PointsDistance { BBPoint jniP1; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsFree.java b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsFree.java index 51bd7738eda40..bb41de670d851 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsFree.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsFree.java @@ -42,7 +42,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class PointsFree { JNIPoint jniPoint; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/xor/XorTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/xor/XorTest.java index 8ff8a4d1816fd..40ae114e8fa75 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/xor/XorTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/xor/XorTest.java @@ -19,7 +19,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class XorTest { diff --git a/test/micro/org/openjdk/bench/java/lang/invoke/CallSiteSetTarget.java b/test/micro/org/openjdk/bench/java/lang/invoke/CallSiteSetTarget.java deleted file mode 100644 index 965c071320707..0000000000000 --- a/test/micro/org/openjdk/bench/java/lang/invoke/CallSiteSetTarget.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 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. - */ -package org.openjdk.bench.java.lang.invoke; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.TearDown; -import org.openjdk.jmh.annotations.Warmup; - -import java.lang.invoke.CallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.invoke.MutableCallSite; -import java.lang.invoke.VolatileCallSite; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * This benchmark evaluates INDY performance under dynamic target updates. - */ -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@State(Scope.Thread) -@Warmup(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) -@Fork(3) -public class CallSiteSetTarget { - - /* - * Implementation notes: - * - This test makes sense for mutable and volatile call sites only - * - Multiple threads are calling the same callsite, and invalidator thread tries to swap target on the fly. - * - Additional baseline includes "raw" test, calling callsite's MH directly - */ - - private static volatile CallSite cs; - - private static MethodHandle doCall1; - private static MethodHandle doCall2; - - static { - try { - doCall1 = MethodHandles.lookup().findVirtual(CallSiteSetTarget.class, "call1", MethodType.methodType(int.class)); - doCall2 = MethodHandles.lookup().findVirtual(CallSiteSetTarget.class, "call2", MethodType.methodType(int.class)); - cs = new MutableCallSite(doCall1); - } catch (NoSuchMethodException | IllegalAccessException e) { - throw new IllegalStateException(e); - } - } - - private int i1; - private int i2; - - public int call1() { - return i1++; - } - - public int call2() { - return i2++; - } - - @Benchmark - public int baselineRaw() throws Throwable { - return (int) cs.getTarget().invokeExact(this); - } - - @Benchmark - public int testMutable() throws Throwable { - return (int) INDY_Mutable().invokeExact(this); - } - - @Benchmark - public int testVolatile() throws Throwable { - return (int) INDY_Volatile().invokeExact(this); - } - - /* =========================== INDY TRAMPOLINES ============================== */ - - private static MethodType MT_bsm() { - shouldNotCallThis(); - return MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class); - } - - private static MethodHandle MH_bsm_Mutable() throws ReflectiveOperationException { - shouldNotCallThis(); - return MethodHandles.lookup().findStatic(MethodHandles.lookup().lookupClass(), "bsm_Mutable", MT_bsm()); - } - - private static MethodHandle MH_bsm_Volatile() throws ReflectiveOperationException { - shouldNotCallThis(); - return MethodHandles.lookup().findStatic(MethodHandles.lookup().lookupClass(), "bsm_Volatile", MT_bsm()); - } - - private static MethodHandle INDY_Mutable() throws Throwable { - shouldNotCallThis(); - return ((CallSite) MH_bsm_Mutable().invoke(MethodHandles.lookup(), "doCall1", MethodType.methodType(int.class, CallSiteSetTarget.class))).dynamicInvoker(); - } - - private static MethodHandle INDY_Volatile() throws Throwable { - shouldNotCallThis(); - return ((CallSite) MH_bsm_Volatile().invoke(MethodHandles.lookup(), "doCall1", MethodType.methodType(int.class, CallSiteSetTarget.class))).dynamicInvoker(); - } - - public static CallSite bsm_Mutable(MethodHandles.Lookup lookup, String name, MethodType type) { - synchronized (CallSiteSetTarget.class) { - if (cs == null) - cs = new MutableCallSite(doCall1); - return cs; - } - } - - public static CallSite bsm_Volatile(MethodHandles.Lookup lookup, String name, MethodType type) { - synchronized (CallSiteSetTarget.class) { - if (cs == null) - cs = new VolatileCallSite(doCall1); - return cs; - } - } - - private static void shouldNotCallThis() { - // if this gets called, the transformation has not taken place - throw new AssertionError("this code should be statically transformed away by Indify"); - } - - /* =========================== INVALIDATE LOGIC ============================== */ - - private final static Invalidator invalidator = new Invalidator(); - - @Setup - public void setup() { - invalidator.start(); - } - - @TearDown - public void tearDown() throws InterruptedException { - invalidator.stop(); - } - - public static class Invalidator implements Runnable { - - private final long period = Integer.getInteger("period", 1000); - - private final AtomicBoolean started = new AtomicBoolean(); - private volatile Thread thread; - - @Override - public void run() { - try { - while(!Thread.interrupted()) { - if (cs != null) { - cs.setTarget(doCall1); - } - TimeUnit.MICROSECONDS.sleep(period); - - if (cs != null) { - cs.setTarget(doCall2); - } - TimeUnit.MICROSECONDS.sleep(period); - } - } catch (InterruptedException e) { - // do nothing - } - } - - public void start() { - if (started.compareAndSet(false, true)) { - thread = new Thread(this); - thread.setPriority(Thread.MAX_PRIORITY); - thread.start(); - } - } - - public void stop() { - if (thread != null) { - thread.interrupt(); - try { - thread.join(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - started.set(false); - } - } - } - -} diff --git a/test/micro/org/openjdk/bench/java/lang/invoke/CallSiteSetTargetSelf.java b/test/micro/org/openjdk/bench/java/lang/invoke/CallSiteSetTargetSelf.java deleted file mode 100644 index ac51b4a80e7ba..0000000000000 --- a/test/micro/org/openjdk/bench/java/lang/invoke/CallSiteSetTargetSelf.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 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. - */ -package org.openjdk.bench.java.lang.invoke; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; - -import java.lang.invoke.CallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.invoke.MutableCallSite; -import java.lang.invoke.VolatileCallSite; -import java.util.concurrent.TimeUnit; - -/** - * This benchmark evaluates INDY performance under dynamic target updates. - */ -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@State(Scope.Thread) -@Warmup(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) -@Fork(3) -public class CallSiteSetTargetSelf { - - /* - * Implementation notes: - * - This test makes sense for mutable and volatile call sites only - * - Multiple threads are calling the same callsite, and each call is swapping the target. - * - Additional baseline includes "raw" test, calling callsite's MH directly - * - * - NOTE: invalidating shared target callsite is very bad with multiple threads. - * I.e. this test is inherently non-scalable. - */ - - private static CallSite cs; - - private static MethodHandle doCall1; - private static MethodHandle doCall2; - - static { - try { - doCall1 = MethodHandles.lookup().findVirtual(CallSiteSetTargetSelf.class, "call1", MethodType.methodType(int.class)); - doCall2 = MethodHandles.lookup().findVirtual(CallSiteSetTargetSelf.class, "call2", MethodType.methodType(int.class)); - cs = new MutableCallSite(doCall1); - } catch (NoSuchMethodException | IllegalAccessException e) { - throw new IllegalStateException(e); - } - } - - private int i1; - private int i2; - - public int call1() { - cs.setTarget(doCall2); - return i1++; - } - - public int call2() { - cs.setTarget(doCall1); - return i2++; - } - - @Benchmark - public int baselineRaw() throws Throwable { - return (int) cs.getTarget().invokeExact(this); - } - - @Benchmark - public int testMutable() throws Throwable { - return (int) INDY_Mutable().invokeExact(this); - } - - @Benchmark - public int testVolatile() throws Throwable { - return (int) INDY_Volatile().invokeExact(this); - } - - /* =========================== INDY TRAMPOLINES ============================== */ - - private static MethodType MT_bsm() { - shouldNotCallThis(); - return MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class); - } - - private static MethodHandle MH_bsm_Mutable() throws ReflectiveOperationException { - shouldNotCallThis(); - return MethodHandles.lookup().findStatic(MethodHandles.lookup().lookupClass(), "bsm_Mutable", MT_bsm()); - } - - private static MethodHandle MH_bsm_Volatile() throws ReflectiveOperationException { - shouldNotCallThis(); - return MethodHandles.lookup().findStatic(MethodHandles.lookup().lookupClass(), "bsm_Volatile", MT_bsm()); - } - - private static MethodHandle INDY_Mutable() throws Throwable { - shouldNotCallThis(); - return ((CallSite) MH_bsm_Mutable().invoke(MethodHandles.lookup(), "doCall1", MethodType.methodType(int.class, CallSiteSetTargetSelf.class))).dynamicInvoker(); - } - - private static MethodHandle INDY_Volatile() throws Throwable { - shouldNotCallThis(); - return ((CallSite) MH_bsm_Volatile().invoke(MethodHandles.lookup(), "doCall1", MethodType.methodType(int.class, CallSiteSetTargetSelf.class))).dynamicInvoker(); - } - - public static CallSite bsm_Mutable(MethodHandles.Lookup lookup, String name, MethodType type) { - synchronized (CallSiteSetTarget.class) { - if (cs == null) - cs = new MutableCallSite(doCall1); - return cs; - } - } - - public static CallSite bsm_Volatile(MethodHandles.Lookup lookup, String name, MethodType type) { - synchronized (CallSiteSetTarget.class) { - if (cs == null) - cs = new VolatileCallSite(doCall1); - return cs; - } - } - - private static void shouldNotCallThis() { - // if this gets called, the transformation has not taken place - throw new AssertionError("this code should be statically transformed away by Indify"); - } - -} diff --git a/test/micro/org/openjdk/bench/java/lang/invoke/CallSiteStable.java b/test/micro/org/openjdk/bench/java/lang/invoke/CallSiteStable.java deleted file mode 100644 index cf7c4f487f1a6..0000000000000 --- a/test/micro/org/openjdk/bench/java/lang/invoke/CallSiteStable.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 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. - */ -package org.openjdk.bench.java.lang.invoke; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; - -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.invoke.MutableCallSite; -import java.lang.invoke.VolatileCallSite; -import java.util.concurrent.TimeUnit; - -/** - * This benchmark evaluates INDY performance when call sites are not changed. - */ -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@State(Scope.Thread) -@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@Fork(3) -public class CallSiteStable { - - /* - * Implementation notes: - * - Test is calling simple method via INDY - * - Additional baseline includes "raw" test, calling target method directly in virtual and static modes - */ - - private static java.lang.invoke.CallSite cs; - - private static MethodHandle doCallMH; - - static { - try { - doCallMH = MethodHandles.lookup().findVirtual(CallSiteStable.class, "doCall", MethodType.methodType(int.class, int.class)); - } catch (NoSuchMethodException | IllegalAccessException e) { - throw new IllegalStateException(e); - } - } - - private int i; - - public int doCall(int value) { - return value + 1; - } - - public static int doCallStatic(int value) { - return value + 1; - } - - @Benchmark - public void baselineVirtual() { - i = doCall(i); - } - - @Benchmark - public void baselineStatic() { - i = doCallStatic(i); - } - - @Benchmark - public void testConstant() throws Throwable { - i = (int) INDY_Constant().invokeExact(this, i); - } - - @Benchmark - public void testMutable() throws Throwable { - i = (int) INDY_Mutable().invokeExact(this, i); - } - - @Benchmark - public void testVolatile() throws Throwable { - i = (int) INDY_Volatile().invokeExact(this, i); - } - - /* =========================== INDY TRAMPOLINES ============================== */ - - private static MethodType MT_bsm() { - shouldNotCallThis(); - return MethodType.methodType(java.lang.invoke.CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class); - } - - private static MethodHandle MH_bsm_Constant() throws ReflectiveOperationException { - shouldNotCallThis(); - return MethodHandles.lookup().findStatic(MethodHandles.lookup().lookupClass(), "bsm_Constant", MT_bsm()); - } - - private static MethodHandle MH_bsm_Mutable() throws ReflectiveOperationException { - shouldNotCallThis(); - return MethodHandles.lookup().findStatic(MethodHandles.lookup().lookupClass(), "bsm_Mutable", MT_bsm()); - } - - private static MethodHandle MH_bsm_Volatile() throws ReflectiveOperationException { - shouldNotCallThis(); - return MethodHandles.lookup().findStatic(MethodHandles.lookup().lookupClass(), "bsm_Volatile", MT_bsm()); - } - - private static MethodHandle INDY_Constant() throws Throwable { - shouldNotCallThis(); - return ((java.lang.invoke.CallSite) MH_bsm_Constant().invoke(MethodHandles.lookup(), "doCall", MethodType.methodType(int.class, CallSiteStable.class, int.class))).dynamicInvoker(); - } - private static MethodHandle INDY_Mutable() throws Throwable { - shouldNotCallThis(); - return ((java.lang.invoke.CallSite) MH_bsm_Mutable().invoke(MethodHandles.lookup(), "doCall", MethodType.methodType(int.class, CallSiteStable.class, int.class))).dynamicInvoker(); - } - private static MethodHandle INDY_Volatile() throws Throwable { - shouldNotCallThis(); - return ((java.lang.invoke.CallSite) MH_bsm_Volatile().invoke(MethodHandles.lookup(), "doCall", MethodType.methodType(int.class, CallSiteStable.class, int.class))).dynamicInvoker(); - } - - public static java.lang.invoke.CallSite bsm_Constant(MethodHandles.Lookup lookup, String name, MethodType type) { - synchronized (CallSiteStable.class) { - if (cs == null) - cs = new ConstantCallSite(doCallMH); - return cs; - } - } - - public static java.lang.invoke.CallSite bsm_Mutable(MethodHandles.Lookup lookup, String name, MethodType type) { - synchronized (CallSiteStable.class) { - if (cs == null) - cs = new MutableCallSite(doCallMH); - return cs; - } - } - - public static java.lang.invoke.CallSite bsm_Volatile(MethodHandles.Lookup lookup, String name, MethodType type) { - synchronized (CallSiteStable.class) { - if (cs == null) - cs = new VolatileCallSite(doCallMH); - return cs; - } - } - - private static void shouldNotCallThis() { - // if this gets called, the transformation has not taken place - throw new AssertionError("this code should be statically transformed away by Indify"); - } - -} diff --git a/test/micro/org/openjdk/bench/java/lang/invoke/LazyStaticColdStart.java b/test/micro/org/openjdk/bench/java/lang/invoke/LazyStaticColdStart.java index fb73901adf4b3..49a77d9539ef4 100644 --- a/test/micro/org/openjdk/bench/java/lang/invoke/LazyStaticColdStart.java +++ b/test/micro/org/openjdk/bench/java/lang/invoke/LazyStaticColdStart.java @@ -52,7 +52,7 @@ @BenchmarkMode(Mode.SingleShotTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @State(Scope.Thread) -@Fork(value = 10, warmups = 5, jvmArgsAppend = { +@Fork(value = 10, warmups = 5, jvmArgs = { "--enable-preview" }) public class LazyStaticColdStart { diff --git a/test/micro/org/openjdk/bench/java/lang/invoke/Wrappers.java b/test/micro/org/openjdk/bench/java/lang/invoke/Wrappers.java index 61aea6b6dcf98..c172548752907 100644 --- a/test/micro/org/openjdk/bench/java/lang/invoke/Wrappers.java +++ b/test/micro/org/openjdk/bench/java/lang/invoke/Wrappers.java @@ -45,7 +45,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Thread) -@Fork(value = 3, jvmArgsAppend = "--add-exports=java.base/sun.invoke.util=ALL-UNNAMED") +@Fork(value = 3, jvmArgs = "--add-exports=java.base/sun.invoke.util=ALL-UNNAMED") public class Wrappers { public static Class[] PRIM_CLASSES = { diff --git a/test/micro/org/openjdk/bench/java/lang/ref/ReferenceClear.java b/test/micro/org/openjdk/bench/java/lang/ref/ReferenceClear.java new file mode 100644 index 0000000000000..6a7b4d6997056 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/ref/ReferenceClear.java @@ -0,0 +1,81 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.ref; + +import java.lang.ref.*; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(3) +public class ReferenceClear { + + final Reference soft = new SoftReference<>(new Object()); + final Reference weak = new WeakReference<>(new Object()); + final Reference phantom = new PhantomReference<>(new Object(), null); + + @Benchmark + public void soft() { + soft.clear(); + } + + @Benchmark + public void soft_new(Blackhole bh) { + Object ref = new Object(); + bh.consume(ref); + Reference soft = new SoftReference<>(ref); + soft.clear(); + } + + @Benchmark + public void weak() { + weak.clear(); + } + + @Benchmark + public void weak_new(Blackhole bh) { + Object ref = new Object(); + bh.consume(ref); + Reference weak = new WeakReference<>(ref); + weak.clear(); + } + + @Benchmark + public void phantom() { + phantom.clear(); + } + + @Benchmark + public void phantom_new(Blackhole bh) { + Object ref = new Object(); + bh.consume(ref); + Reference phantom = new PhantomReference<>(ref, null); + phantom.clear(); + } + +} diff --git a/test/micro/org/openjdk/bench/java/lang/reflect/proxy/ProxyGeneratorBench.java b/test/micro/org/openjdk/bench/java/lang/reflect/proxy/ProxyGeneratorBench.java index 3393431730080..6963a040b6541 100644 --- a/test/micro/org/openjdk/bench/java/lang/reflect/proxy/ProxyGeneratorBench.java +++ b/test/micro/org/openjdk/bench/java/lang/reflect/proxy/ProxyGeneratorBench.java @@ -45,7 +45,7 @@ */ @Warmup(iterations = 5, time = 2) @Measurement(iterations = 5, time = 2) -@Fork(value = 1, jvmArgsPrepend = "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED") +@Fork(value = 1, jvmArgs = "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED") @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Thread) diff --git a/test/micro/org/openjdk/bench/java/math/BigDecimalStripTrailingZeros.java b/test/micro/org/openjdk/bench/java/math/BigDecimalStripTrailingZeros.java new file mode 100644 index 0000000000000..af5ce3aa9acdd --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/BigDecimalStripTrailingZeros.java @@ -0,0 +1,96 @@ +/* + * 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 org.openjdk.bench.java.math; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import java.math.BigInteger; +import java.math.BigDecimal; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 3) +public class BigDecimalStripTrailingZeros { + + private BigDecimal xsPow, sPow, mPow, lPow, xlPow; + + @Setup + public void setup() { + xsPow = new BigDecimal(BigInteger.TEN.pow(1 << 4)); + sPow = new BigDecimal(BigInteger.TEN.pow(1 << 5)); + mPow = new BigDecimal(BigInteger.TEN.pow(1 << 10)); + lPow = new BigDecimal(BigInteger.TEN.pow(1 << 15)); + xlPow = new BigDecimal(BigInteger.TEN.pow(1 << 20)); + } + + /** Test BigDecimal.stripTrailingZeros() with 10^16 */ + @Benchmark + @OperationsPerInvocation(1) + public void testXS(Blackhole bh) { + bh.consume(xsPow.stripTrailingZeros()); + } + + /** Test BigDecimal.stripTrailingZeros() with 10^32 */ + @Benchmark + @OperationsPerInvocation(1) + public void testS(Blackhole bh) { + bh.consume(sPow.stripTrailingZeros()); + } + + /** Test BigDecimal.stripTrailingZeros() with 10^1024 */ + @Benchmark + @OperationsPerInvocation(1) + public void testM(Blackhole bh) { + bh.consume(mPow.stripTrailingZeros()); + } + + /** Test BigDecimal.stripTrailingZeros() with 10^32_768 */ + @Benchmark + @OperationsPerInvocation(1) + public void testL(Blackhole bh) { + bh.consume(lPow.stripTrailingZeros()); + } + + /** Test BigDecimal.stripTrailingZeros() with 10^1_048_576 */ + @Benchmark + @OperationsPerInvocation(1) + public void testXL(Blackhole bh) { + bh.consume(xlPow.stripTrailingZeros()); + } +} diff --git a/test/micro/org/openjdk/bench/java/net/NetworkInterfaceLookup.java b/test/micro/org/openjdk/bench/java/net/NetworkInterfaceLookup.java index 2a77e6a16ecb5..4b1a5bc439a43 100644 --- a/test/micro/org/openjdk/bench/java/net/NetworkInterfaceLookup.java +++ b/test/micro/org/openjdk/bench/java/net/NetworkInterfaceLookup.java @@ -45,7 +45,7 @@ @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) -@Fork(value = 2, jvmArgsAppend = "--add-opens=java.base/java.net=ALL-UNNAMED") +@Fork(value = 2, jvmArgs = "--add-opens=java.base/java.net=ALL-UNNAMED") @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) public class NetworkInterfaceLookup { diff --git a/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java b/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java index c410056816113..704cca94af031 100644 --- a/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java +++ b/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java @@ -125,7 +125,7 @@ public static void main(String[] args) throws RunnerException { opt = new OptionsBuilder() .include(org.openjdk.bench.java.net.SocketChannelConnectionSetup.class.getSimpleName()) - .jvmArgsPrepend("-Djdk.net.useFastTcpLoopback=true") + .jvmArgs("-Djdk.net.useFastTcpLoopback=true") .warmupForks(1) .forks(2) .build(); diff --git a/test/micro/org/openjdk/bench/java/net/SocketEventOverhead.java b/test/micro/org/openjdk/bench/java/net/SocketEventOverhead.java index a898aff528368..f386fb1620dfd 100644 --- a/test/micro/org/openjdk/bench/java/net/SocketEventOverhead.java +++ b/test/micro/org/openjdk/bench/java/net/SocketEventOverhead.java @@ -45,7 +45,7 @@ @State(Scope.Thread) public class SocketEventOverhead { - @Fork(value = 1, jvmArgsAppend = { + @Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.event=ALL-UNNAMED" }) @Benchmark @@ -53,7 +53,7 @@ public int socketWriteJFRDisabled(SkeletonFixture fixture) { return fixture.write(); } - @Fork(value = 1, jvmArgsAppend = { + @Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.event=ALL-UNNAMED", "-XX:StartFlightRecording:jdk.SocketWrite#enabled=false"}) @@ -62,7 +62,7 @@ public int socketWriteJFREnabledEventDisabled(SkeletonFixture fixture) { return fixture.write(); } - @Fork(value = 1, jvmArgsAppend = { + @Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.event=ALL-UNNAMED", "-XX:StartFlightRecording:jdk.SocketWrite#enabled=true,jdk.SocketWrite#threshold=1s"}) @@ -71,7 +71,7 @@ public int socketWriteJFREnabledEventNotEmitted(SkeletonFixture fixture) { return fixture.write(); } - @Fork(value = 1, jvmArgsAppend = { + @Fork(value = 1, jvmArgs = { "--add-exports","java.base/jdk.internal.event=ALL-UNNAMED", "-XX:StartFlightRecording:jdk.SocketWrite#enabled=true,jdk.SocketWrite#threshold=0ms,disk=false,jdk.SocketWrite#stackTrace=false"}) @Benchmark @@ -79,7 +79,7 @@ public int socketWriteJFREnabledEventEmitted(SkeletonFixture fixture) { return fixture.write(); } - @Fork(value = 1, jvmArgsAppend = { + @Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.event=ALL-UNNAMED" }) @Benchmark @@ -87,7 +87,7 @@ public int socketReadJFRDisabled(SkeletonFixture fixture) { return fixture.read(); } - @Fork(value = 1, jvmArgsAppend = { + @Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.event=ALL-UNNAMED", "-XX:StartFlightRecording:jdk.SocketRead#enabled=false"}) @@ -96,7 +96,7 @@ public int socketReadJFREnabledEventDisabled(SkeletonFixture fixture) { return fixture.read(); } - @Fork(value = 1, jvmArgsAppend = { + @Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.event=ALL-UNNAMED", "-XX:StartFlightRecording:jdk.SocketRead#enabled=true,jdk.SocketRead#threshold=1s"}) @@ -105,7 +105,7 @@ public int socketReadJFREnabledEventNotEmitted(SkeletonFixture fixture) { return fixture.read(); } - @Fork(value = 1, jvmArgsAppend = { + @Fork(value = 1, jvmArgs = { "--add-exports","java.base/jdk.internal.event=ALL-UNNAMED", "-XX:StartFlightRecording:jdk.SocketRead#enabled=true,jdk.SocketRead#threshold=0ms,disk=false,jdk.SocketRead#stackTrace=false"}) @Benchmark diff --git a/test/micro/org/openjdk/bench/java/net/ThreadLocalParseUtil.java b/test/micro/org/openjdk/bench/java/net/ThreadLocalParseUtil.java index 93af26379a7cc..180de650ede57 100644 --- a/test/micro/org/openjdk/bench/java/net/ThreadLocalParseUtil.java +++ b/test/micro/org/openjdk/bench/java/net/ThreadLocalParseUtil.java @@ -48,7 +48,7 @@ @State(Scope.Thread) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 1, jvmArgsAppend = "--add-exports=java.base/sun.net.www=ALL-UNNAMED") +@Fork(value = 1, jvmArgs = "--add-exports=java.base/sun.net.www=ALL-UNNAMED") public class ThreadLocalParseUtil { private static final MethodHandle MH_DECODE; diff --git a/test/micro/org/openjdk/bench/java/security/AlgorithmConstraintsPermits.java b/test/micro/org/openjdk/bench/java/security/AlgorithmConstraintsPermits.java index 46e68ea627fdd..683d069bc7e74 100644 --- a/test/micro/org/openjdk/bench/java/security/AlgorithmConstraintsPermits.java +++ b/test/micro/org/openjdk/bench/java/security/AlgorithmConstraintsPermits.java @@ -45,7 +45,7 @@ @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = {"--add-exports", "java.base/sun.security.util=ALL-UNNAMED"}) +@Fork(value = 3, jvmArgs = {"--add-exports", "java.base/sun.security.util=ALL-UNNAMED"}) @State(Scope.Thread) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) diff --git a/test/micro/org/openjdk/bench/java/security/CacheBench.java b/test/micro/org/openjdk/bench/java/security/CacheBench.java index 9b7c39a3cf2de..7366a18c020d8 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"}) +@Fork(value = 3, jvmArgs = {"--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/CipherSuiteBench.java b/test/micro/org/openjdk/bench/java/security/CipherSuiteBench.java index dcda7c252f003..c78fbb5dbb109 100644 --- a/test/micro/org/openjdk/bench/java/security/CipherSuiteBench.java +++ b/test/micro/org/openjdk/bench/java/security/CipherSuiteBench.java @@ -30,7 +30,7 @@ import java.util.concurrent.TimeUnit; -@Fork(value = 3, jvmArgsAppend = {"--add-exports", "java.base/sun.security.ssl=ALL-UNNAMED", "--add-opens", "java.base/sun.security.ssl=ALL-UNNAMED"}) +@Fork(value = 3, jvmArgs = {"--add-exports", "java.base/sun.security.ssl=ALL-UNNAMED", "--add-opens", "java.base/sun.security.ssl=ALL-UNNAMED"}) @State(Scope.Thread) @OutputTimeUnit(TimeUnit.MICROSECONDS) @BenchmarkMode(Mode.Throughput) diff --git a/test/micro/org/openjdk/bench/java/security/HSS.java b/test/micro/org/openjdk/bench/java/security/HSS.java index d89147406dcd3..c2f746d2449e4 100644 --- a/test/micro/org/openjdk/bench/java/security/HSS.java +++ b/test/micro/org/openjdk/bench/java/security/HSS.java @@ -55,7 +55,7 @@ @OutputTimeUnit(TimeUnit.MICROSECONDS) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 3, jvmArgsAppend = {"--add-exports", "java.base/sun.security.util=ALL-UNNAMED"}) +@Fork(value = 3, jvmArgs = {"--add-exports", "java.base/sun.security.util=ALL-UNNAMED"}) // Tests 1-2 are from RFC 8554, Appendix F. diff --git a/test/micro/org/openjdk/bench/java/security/MessageDigests.java b/test/micro/org/openjdk/bench/java/security/MessageDigests.java index a3ab483c39c19..2a4e3933d31f4 100644 --- a/test/micro/org/openjdk/bench/java/security/MessageDigests.java +++ b/test/micro/org/openjdk/bench/java/security/MessageDigests.java @@ -47,7 +47,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(jvmArgsAppend = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 3) +@Fork(jvmArgs = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 3) public class MessageDigests { @Param({"64", "16384"}) diff --git a/test/micro/org/openjdk/bench/java/security/PKCS12KeyStores.java b/test/micro/org/openjdk/bench/java/security/PKCS12KeyStores.java index f68b4503ef524..065bd96c4bf34 100644 --- a/test/micro/org/openjdk/bench/java/security/PKCS12KeyStores.java +++ b/test/micro/org/openjdk/bench/java/security/PKCS12KeyStores.java @@ -41,7 +41,7 @@ @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) @BenchmarkMode(Mode.AverageTime) -@Fork(jvmArgsAppend = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 3) +@Fork(jvmArgs = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 3) public class PKCS12KeyStores { private static final char[] PASS = "changeit".toCharArray(); diff --git a/test/micro/org/openjdk/bench/java/security/ProtectionDomainBench.java b/test/micro/org/openjdk/bench/java/security/ProtectionDomainBench.java index ec85e09634f04..cf302d83e9bb9 100644 --- a/test/micro/org/openjdk/bench/java/security/ProtectionDomainBench.java +++ b/test/micro/org/openjdk/bench/java/security/ProtectionDomainBench.java @@ -123,7 +123,7 @@ void work() throws ClassNotFoundException { } @Benchmark - @Fork(value = 3, jvmArgsPrepend={"-Djava.security.manager=allow"}) + @Fork(value = 3, jvmArgs={"-Djava.security.manager=allow"}) public void withSecurityManager() throws ClassNotFoundException { work(); } diff --git a/test/micro/org/openjdk/bench/java/security/Signatures.java b/test/micro/org/openjdk/bench/java/security/Signatures.java index 7a14cb24b88b2..1bd723343437c 100644 --- a/test/micro/org/openjdk/bench/java/security/Signatures.java +++ b/test/micro/org/openjdk/bench/java/security/Signatures.java @@ -34,7 +34,7 @@ @State(Scope.Thread) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(jvmArgsAppend = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 3) +@Fork(jvmArgs = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 3) public class Signatures { private static Signature signer; diff --git a/test/micro/org/openjdk/bench/java/util/ArraysSort.java b/test/micro/org/openjdk/bench/java/util/ArraysSort.java index 4cd45d79412c1..d32bfa7fd2d3f 100644 --- a/test/micro/org/openjdk/bench/java/util/ArraysSort.java +++ b/test/micro/org/openjdk/bench/java/util/ArraysSort.java @@ -47,7 +47,7 @@ /** * Performance test of Arrays.sort() methods */ -@Fork(value=1, jvmArgsAppend={"-XX:CompileThreshold=1", "-XX:-TieredCompilation"}) +@Fork(value=1, jvmArgs={"-XX:CompileThreshold=1", "-XX:-TieredCompilation"}) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @State(Scope.Thread) diff --git a/test/micro/org/openjdk/bench/java/util/ListArgs.java b/test/micro/org/openjdk/bench/java/util/ListArgs.java index 073214ce2a129..d44d8b604ef50 100644 --- a/test/micro/org/openjdk/bench/java/util/ListArgs.java +++ b/test/micro/org/openjdk/bench/java/util/ListArgs.java @@ -36,7 +36,7 @@ */ @State(Scope.Thread) @OutputTimeUnit(TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgsAppend = { "-verbose:gc", "-XX:+UseParallelGC", "-Xms4g", "-Xmx4g", "-Xint" }) +@Fork(value = 3, jvmArgs = { "-verbose:gc", "-XX:+UseParallelGC", "-Xms4g", "-Xmx4g", "-Xint" }) @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) public class ListArgs { diff --git a/test/micro/org/openjdk/bench/java/util/StringJoinerBenchmark.java b/test/micro/org/openjdk/bench/java/util/StringJoinerBenchmark.java index 6df0045ef32ba..38b6389db54e8 100644 --- a/test/micro/org/openjdk/bench/java/util/StringJoinerBenchmark.java +++ b/test/micro/org/openjdk/bench/java/util/StringJoinerBenchmark.java @@ -45,7 +45,7 @@ @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgsAppend = {"-Xms1g", "-Xmx1g"}) +@Fork(value = 3, jvmArgs = {"-Xms1g", "-Xmx1g"}) public class StringJoinerBenchmark { @Benchmark diff --git a/test/micro/org/openjdk/bench/java/util/jar/JarFileGetEntry.java b/test/micro/org/openjdk/bench/java/util/jar/JarFileGetEntry.java index bc2182e00b4cc..a0c3938e8ebd5 100644 --- a/test/micro/org/openjdk/bench/java/util/jar/JarFileGetEntry.java +++ b/test/micro/org/openjdk/bench/java/util/jar/JarFileGetEntry.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 @@ -31,9 +31,12 @@ import java.nio.file.Files; import java.util.Random; import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; /** * Simple benchmark measuring cost of looking up entries in a jar file. @@ -71,6 +74,9 @@ public class JarFileGetEntry { @Param({"512", "1024"}) private int size; + @Param({"false", "true"}) + private boolean mr; + public JarFile jarFile; public String[] entryNames; public String[] missingEntryNames; @@ -91,9 +97,20 @@ public void beforeRun() throws IOException { entryNames = new String[size]; missingEntryNames = new String[size]; + Manifest man = new Manifest(); + man.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + if (mr) { + man.getMainAttributes().put(Attributes.Name.MULTI_RELEASE, "true"); + } try (FileOutputStream fos = new FileOutputStream(tempFile); - JarOutputStream jos = new JarOutputStream(fos)) { + JarOutputStream jos = new JarOutputStream(fos, man)) { + if (mr) { + // Add a few versioned entries + jos.putNextEntry(new ZipEntry("META-INF/versions/9/module-info.class")); + jos.putNextEntry(new ZipEntry("META-INF/versions/17/foo/library/Library.class")); + jos.putNextEntry(new ZipEntry("META-INF/versions/21/foo/library/Library.class")); + } Random random = new Random(4711); for (int i = 0; i < size; i++) { String ename = "entry-" + (random.nextInt(90000) + 10000) + "-" + i; @@ -107,7 +124,7 @@ public void beforeRun() throws IOException { } } - jarFile = new JarFile(tempFile); + jarFile = new JarFile(tempFile, true, ZipFile.OPEN_READ, mr ? JarFile.runtimeVersion() : JarFile.baseVersion()); } @Benchmark diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFMRPar.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFMRPar.java index 476299df76e5a..cd83ab8603417 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFMRPar.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFMRPar.java @@ -49,7 +49,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherFMRPar { diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFMRSeq.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFMRSeq.java index 05e48e16d075b..a1973a4583188 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFMRSeq.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFMRSeq.java @@ -49,7 +49,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherFMRSeq { diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFlatMapInfinitySeq.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFlatMapInfinitySeq.java index 09c38f8348432..2b804551dbf7d 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFlatMapInfinitySeq.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFlatMapInfinitySeq.java @@ -48,7 +48,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherFlatMapInfinitySeq { diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFlatMapSeq.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFlatMapSeq.java index a13ee01a8514b..31c1f047c1283 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFlatMapSeq.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherFlatMapSeq.java @@ -48,7 +48,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherFlatMapSeq { diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMapPar.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMapPar.java index 62c2d03b1b1af..b7c60af6cdd67 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMapPar.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMapPar.java @@ -48,7 +48,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherMapPar { diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMapSeq.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMapSeq.java index 1e842c0c09e7d..1dbbbd05009e2 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMapSeq.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMapSeq.java @@ -48,7 +48,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherMapSeq { diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMiscPar.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMiscPar.java index 578e470ec5cb3..12f5c98702bb0 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMiscPar.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMiscPar.java @@ -49,7 +49,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherMiscPar { diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMiscSeq.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMiscSeq.java index 0d7d9bdef9f49..a60d02af7b6ae 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMiscSeq.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherMiscSeq.java @@ -51,7 +51,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherMiscSeq { diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherReducePar.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherReducePar.java index 2f2d0b06bd7a6..6742ee9859094 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherReducePar.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherReducePar.java @@ -49,7 +49,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherReducePar { diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherReduceSeq.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherReduceSeq.java index 7d8540d0ed46d..7356fdb979b27 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherReduceSeq.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherReduceSeq.java @@ -51,7 +51,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherReduceSeq { diff --git a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherWhileOrdered.java b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherWhileOrdered.java index 6e9e5fec1faf8..f0b3fef44389b 100644 --- a/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherWhileOrdered.java +++ b/test/micro/org/openjdk/bench/java/util/stream/ops/ref/GatherWhileOrdered.java @@ -49,7 +49,7 @@ @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 7, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(jvmArgsAppend = "--enable-preview", value = 1) +@Fork(jvmArgs = "--enable-preview", value = 1) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class GatherWhileOrdered { diff --git a/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java b/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java index e450fcfe9a0ae..4f6ae6373ec46 100644 --- a/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java +++ b/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.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 @@ -107,4 +107,13 @@ public void openCloseZipFilex2() throws Exception { zf.close(); zf2.close(); } + + // Provide a simple one-off run without JMH dependencies enable simple debugging, + // diagnostics and dual-purposing this micro as a startup test. + public static void main(String... args) throws Exception { + var bench = new ZipFileOpen(); + bench.size = 1024*4; + bench.beforeRun(); + bench.openCloseZipFile(); + } } diff --git a/test/micro/org/openjdk/bench/javax/crypto/AES.java b/test/micro/org/openjdk/bench/javax/crypto/AES.java index 23ecdb33f94a9..8bd4a6ff9b3a2 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/AES.java +++ b/test/micro/org/openjdk/bench/javax/crypto/AES.java @@ -59,19 +59,19 @@ public void setup() throws Exception { } @Benchmark - @Fork(jvmArgsAppend = {"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseAES", "-XX:-UseAESIntrinsics"}) + @Fork(jvmArgs = {"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseAES", "-XX:-UseAESIntrinsics"}) public byte[] testBaseline() throws Exception { return cipher.doFinal(src); } @Benchmark - @Fork(jvmArgsAppend = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseAES", "-XX:-UseAESIntrinsics"}) + @Fork(jvmArgs = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseAES", "-XX:-UseAESIntrinsics"}) public byte[] testUseAes() throws Exception { return cipher.doFinal(src); } @Benchmark - @Fork(jvmArgsAppend = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseAES", "-XX:+UseAESIntrinsics"}) + @Fork(jvmArgs = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseAES", "-XX:+UseAESIntrinsics"}) public byte[] testUseAesIntrinsics() throws Exception { return cipher.doFinal(src); } diff --git a/test/micro/org/openjdk/bench/javax/crypto/AESReinit.java b/test/micro/org/openjdk/bench/javax/crypto/AESReinit.java index 16f8b93063368..b2378576f2cc7 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/AESReinit.java +++ b/test/micro/org/openjdk/bench/javax/crypto/AESReinit.java @@ -32,7 +32,7 @@ @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@Fork(value = 3, jvmArgsAppend = {"-Xms1g", "-Xmx1g"}) +@Fork(value = 3, jvmArgs = {"-Xms1g", "-Xmx1g"}) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Thread) diff --git a/test/micro/org/openjdk/bench/javax/crypto/Crypto.java b/test/micro/org/openjdk/bench/javax/crypto/Crypto.java index 6a9a49bd84e06..38e88d0171e98 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/Crypto.java +++ b/test/micro/org/openjdk/bench/javax/crypto/Crypto.java @@ -51,7 +51,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @Warmup(iterations = 5) @Measurement(iterations = 10) -@Fork(jvmArgsAppend = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 5) +@Fork(jvmArgs = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 5) public class Crypto { @Param({"64", "1024", "16384"}) diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/CryptoBase.java b/test/micro/org/openjdk/bench/javax/crypto/full/CryptoBase.java index c0fbcdcaa019c..b2d08204d7b32 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/CryptoBase.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/CryptoBase.java @@ -45,7 +45,7 @@ import java.util.concurrent.TimeUnit; -@Fork(jvmArgsAppend = {"-XX:+AlwaysPreTouch"}, value = 5) +@Fork(jvmArgs = {"-XX:+AlwaysPreTouch"}, value = 5) @Warmup(iterations = 3, time = 3) @Measurement(iterations = 8, time = 2) @OutputTimeUnit(TimeUnit.SECONDS) diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/Poly1305DigestBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/Poly1305DigestBench.java index 529ce9a2b32da..bff0918b7a8cf 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/Poly1305DigestBench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/Poly1305DigestBench.java @@ -41,7 +41,7 @@ @Measurement(iterations = 3, time = 10) @Warmup(iterations = 3, time = 10) -@Fork(value = 1, jvmArgsAppend = {"--add-opens", "java.base/com.sun.crypto.provider=ALL-UNNAMED"}) +@Fork(value = 1, jvmArgs = {"--add-opens", "java.base/com.sun.crypto.provider=ALL-UNNAMED"}) public class Poly1305DigestBench extends CryptoBase { public static final int SET_SIZE = 128; diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java b/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java index 94c247c908022..34a6bd761ff98 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java @@ -40,7 +40,7 @@ import sun.security.util.math.MutableIntegerModuloP; import sun.security.util.math.ImmutableIntegerModuloP; -@Fork(jvmArgsAppend = {"-XX:+AlwaysPreTouch", +@Fork(jvmArgs = {"-XX:+AlwaysPreTouch", "--add-exports", "java.base/sun.security.util.math.intpoly=ALL-UNNAMED", "--add-exports", "java.base/sun.security.util.math=ALL-UNNAMED"}, value = 1) @Warmup(iterations = 3, time = 3) diff --git a/test/micro/org/openjdk/bench/javax/tools/JavacNameTable.java b/test/micro/org/openjdk/bench/javax/tools/JavacNameTable.java new file mode 100644 index 0000000000000..a98dcb0a89c26 --- /dev/null +++ b/test/micro/org/openjdk/bench/javax/tools/JavacNameTable.java @@ -0,0 +1,145 @@ +/* + * 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 org.openjdk.bench.javax.tools; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; + +import javax.tools.JavaCompiler; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; +import java.io.IOException; +import java.io.File; +import java.net.URI; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 3, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) +@Fork(value = 2, jvmArgs = "-Xmx1g") +public class JavacNameTable { + + private List compilationUnits; + private JavaCompiler compiler; + private StandardJavaFileManager fileManager; + private File classDir; + + @Setup + public void prepare() throws IOException { + + // Create a source file with lots of names + StringBuilder buf = new StringBuilder(); + buf.append("class BigSource {\n"); + for (int i = 0; i < 20000; i++) { + buf.append(String.format( + //"final String name%05d = \"some text #%5d\";\n", i, i)); + "String name%05d;\n", i, i)); + } + buf.append("}\n"); + String bigSource = buf.toString(); + + compiler = ToolProvider.getSystemJavaCompiler(); + + fileManager = compiler.getStandardFileManager(null, null, null); + classDir = Files.createTempDirectory( + JavacNameTable.class.getName()).toFile(); + fileManager.setLocation(StandardLocation.CLASS_OUTPUT, + Collections.singleton(classDir)); + + compilationUnits = new ArrayList<>(); + compilationUnits.add(new JavaSourceFromString("BigSource", bigSource)); + } + + @TearDown + public void tearDown() { + for (File f : classDir.listFiles()) { + if (f.isFile()) { + f.delete(); + } else { + throw new IllegalStateException("Unexpected non-file: " + f); + } + } + classDir.delete(); + } + + @Benchmark + public Boolean testSharedTable() throws Exception { + return testCompile(null); + } + + @Benchmark + public Boolean testUnsharedTable() throws Exception { + return testCompile("-XDuseUnsharedTable=true"); + } + + @Benchmark + public Boolean testStringTable() throws Exception { + return testCompile("-XDuseStringTable=true"); + } + + @Benchmark + public Boolean testInternStringTable() throws Exception { + return testCompile("-XDinternStringTable=true"); + } + + public Boolean testCompile(String flag) throws Exception { + final List options = flag != null ? + Collections.singletonList(flag) : null; + JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, + null, options, null, compilationUnits); + return task.call(); + } + + private static class JavaSourceFromString extends SimpleJavaFileObject { + + private final String code; + + JavaSourceFromString(String name, String code) { + super(URI.create("string:///" + + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); + this.code = code; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return code; + } + } +} diff --git a/test/micro/org/openjdk/bench/jdk/classfile/AbstractCorpusBenchmark.java b/test/micro/org/openjdk/bench/jdk/classfile/AbstractCorpusBenchmark.java index b714f1c5ff961..5f64e1148776d 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/AbstractCorpusBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/AbstractCorpusBenchmark.java @@ -43,7 +43,7 @@ */ @Warmup(iterations = 2) @Measurement(iterations = 4) -@Fork(value = 1, jvmArgsAppend = { +@Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED", "--enable-preview", diff --git a/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java b/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java index c07eff075c959..ecd671feaac37 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java @@ -50,7 +50,7 @@ */ @Warmup(iterations = 3) @Measurement(iterations = 5) -@Fork(value = 1, jvmArgsAppend = { +@Fork(value = 1, jvmArgs = { "--enable-preview"}) @State(Scope.Benchmark) diff --git a/test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java b/test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java index 4239f70504b17..877a36e3864c1 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java @@ -55,7 +55,7 @@ @BenchmarkMode(Mode.Throughput) @State(Scope.Benchmark) -@Fork(value = 1, jvmArgsAppend = { +@Fork(value = 1, jvmArgs = { "--enable-preview", "--add-exports", "java.base/jdk.internal.classfile.impl=ALL-UNNAMED"}) @Warmup(iterations = 2) diff --git a/test/micro/org/openjdk/bench/jdk/classfile/ConstantPoolBuildingClassEntry.java b/test/micro/org/openjdk/bench/jdk/classfile/ConstantPoolBuildingClassEntry.java index 0f8bf0449af0b..afb586dabe7d9 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/ConstantPoolBuildingClassEntry.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/ConstantPoolBuildingClassEntry.java @@ -43,7 +43,7 @@ @Measurement(iterations = 5) @OutputTimeUnit(TimeUnit.MILLISECONDS) @BenchmarkMode(Mode.Throughput) -@Fork(value = 1, jvmArgsAppend = {"--enable-preview"}) +@Fork(value = 1, jvmArgs = {"--enable-preview"}) @State(Scope.Benchmark) public class ConstantPoolBuildingClassEntry { // JDK-8338546 diff --git a/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java b/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java index 07deec0ae489a..f6542983e134a 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java @@ -37,7 +37,7 @@ @BenchmarkMode(Mode.Throughput) @State(Scope.Benchmark) -@Fork(value = 1, jvmArgsAppend = { +@Fork(value = 1, jvmArgs = { "--enable-preview"}) @Warmup(iterations = 2) @Measurement(iterations = 4) diff --git a/test/micro/org/openjdk/bench/jdk/classfile/RepeatedModelTraversal.java b/test/micro/org/openjdk/bench/jdk/classfile/RepeatedModelTraversal.java index 45fcbe0f5a52b..b9c9082625cd3 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/RepeatedModelTraversal.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/RepeatedModelTraversal.java @@ -36,7 +36,7 @@ @BenchmarkMode(Mode.Throughput) @State(Scope.Benchmark) -@Fork(value = 1, jvmArgsAppend = { +@Fork(value = 1, jvmArgs = { "--enable-preview"}) @Warmup(iterations = 3) @Measurement(iterations = 4) diff --git a/test/micro/org/openjdk/bench/jdk/classfile/Write.java b/test/micro/org/openjdk/bench/jdk/classfile/Write.java index b8bc9605559d9..19dfabbdce8f6 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/Write.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/Write.java @@ -56,12 +56,21 @@ */ @Warmup(iterations = 3) @Measurement(iterations = 5) -@Fork(value = 1, jvmArgsAppend = { +@Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED", "--enable-preview", "--add-exports", "java.base/jdk.internal.classfile.impl=ALL-UNNAMED"}) public class Write { + static final int REPEATS = 40; + static final String[] METHOD_NAMES; + static { + var names = new String[REPEATS]; + for (int xi = 0; xi < REPEATS; ++xi) { + names[xi] = "main" + ((xi == 0) ? "" : "" + xi); + } + METHOD_NAMES = names; + } static String checkFileAsm = "/tmp/asw/MyClass.class"; static String checkFileBc = "/tmp/byw/MyClass.class"; static boolean writeClassAsm = Files.exists(Paths.get(checkFileAsm).getParent()); @@ -90,8 +99,8 @@ public byte[] asmStream() { mv.visitEnd(); } - for (int xi = 0; xi < 40; ++xi) { - MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC, "main"+ ((xi==0)? "" : ""+xi), "([Ljava/lang/String;)V", null, null); + for (int xi = 0; xi < REPEATS; ++xi) { + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC, METHOD_NAMES[xi], "([Ljava/lang/String;)V", null, null); mv.visitCode(); Label loopTop = new Label(); Label loopEnd = new Label(); @@ -141,13 +150,13 @@ public byte[] jdkTree() { cb.withVersion(52, 0); cb.with(SourceFileAttribute.of(cb.constantPool().utf8Entry(("MyClass.java")))) .withMethod(INIT_NAME, MTD_void, 0, mb -> mb - .withCode(codeb -> codeb.loadLocal(REFERENCE, 0) - .invoke(INVOKESPECIAL, CD_Object, INIT_NAME, MTD_void, false) - .return_(VOID) + .withCode(codeb -> codeb.aload(0) + .invokespecial(CD_Object, INIT_NAME, MTD_void) + .return_() ) ); - for (int xi = 0; xi < 40; ++xi) { - cb.withMethod("main" + ((xi == 0) ? "" : "" + xi), MTD_void_StringArray, + for (int xi = 0; xi < REPEATS; ++xi) { + cb.withMethod(METHOD_NAMES[xi], MTD_void_StringArray, ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(c0 -> { java.lang.classfile.Label loopTop = c0.newLabel(); @@ -180,54 +189,6 @@ public byte[] jdkTree() { return bytes; } - @Benchmark - @BenchmarkMode(Mode.Throughput) - public byte[] jdkTreePrimitive() { - - byte[] bytes = ClassFile.of().build(CD_MyClass, cb -> { - cb.withFlags(AccessFlag.PUBLIC); - cb.withVersion(52, 0); - cb.with(SourceFileAttribute.of(cb.constantPool().utf8Entry(("MyClass.java")))) - .withMethod(INIT_NAME, MTD_void, 0, - mb -> mb.withCode(codeb -> codeb.loadLocal(REFERENCE, 0) - .invokespecial(CD_Object, INIT_NAME, MTD_void, false) - .return_() - ) - ); - for (int xi = 0; xi < 40; ++xi) { - cb.withMethod("main" + ((xi == 0) ? "" : "" + xi), MTD_void_StringArray, - ACC_PUBLIC | ACC_STATIC, - mb -> mb.withCode(c0 -> { - java.lang.classfile.Label loopTop = c0.newLabel(); - java.lang.classfile.Label loopEnd = c0.newLabel(); - int vFac = 1; - int vI = 2; - c0.iconst_1() // 0 - .istore(1) // 1 - .iconst_1() // 2 - .istore(2) // 3 - .labelBinding(loopTop) - .iload(2) // 4 - .bipush(10) // 5 - .if_icmpge(loopEnd) // 6 - .iload(1) // 7 - .iload(2) // 8 - .imul() // 9 - .istore(1) // 10 - .iinc(2, 1) // 11 - .goto_(loopTop) // 12 - .labelBinding(loopEnd) - .getstatic(CD_System, "out", CD_PrintStream) // 13 - .iload(1) - .invokevirtual(CD_PrintStream, "println", MTD_void_int) // 15 - .return_(); - })); - } - }); - if (writeClassBc) writeClass(bytes, checkFileBc); - return bytes; - } - private void writeClass(byte[] bytes, String fn) { try { FileOutputStream out = new FileOutputStream(fn); diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/ArrayMismatchBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/ArrayMismatchBenchmark.java index c6c34e890fa13..8d0cce89f98c5 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/ArrayMismatchBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/ArrayMismatchBenchmark.java @@ -47,7 +47,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class ArrayMismatchBenchmark { @Param({"9", "257", "100000"}) diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/BlackScholes.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/BlackScholes.java index f58821b669720..5db2c6b7d071c 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/BlackScholes.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/BlackScholes.java @@ -39,7 +39,7 @@ @State(Scope.Thread) @Warmup(iterations = 3, time = 5) @Measurement(iterations = 3, time = 5) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class BlackScholes { @Param("1024") diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/ColumnFilterBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/ColumnFilterBenchmark.java index d41d5404250b8..e78bd2172a08e 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/ColumnFilterBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/ColumnFilterBenchmark.java @@ -32,7 +32,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector", "-XX:UseAVX=2"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector", "-XX:UseAVX=2"}) public class ColumnFilterBenchmark { @Param({"1024", "2047", "4096"}) int size; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/EqualsIgnoreCaseBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/EqualsIgnoreCaseBenchmark.java index 888029f3c1198..20d7646586d12 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/EqualsIgnoreCaseBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/EqualsIgnoreCaseBenchmark.java @@ -46,7 +46,7 @@ @State(Scope.Benchmark) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 3, jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(value = 3, jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class EqualsIgnoreCaseBenchmark { static final VectorSpecies SPECIES = ByteVector.SPECIES_PREFERRED; private byte[] a; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/GatherOperationsBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/GatherOperationsBenchmark.java index 7a7578fcf84b8..09c467cea5be2 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/GatherOperationsBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/GatherOperationsBenchmark.java @@ -32,7 +32,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class GatherOperationsBenchmark { @Param({"64", "256", "1024", "4096"}) int SIZE; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexInRangeBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexInRangeBenchmark.java index 66a9b3fc522da..1875ea00feb8d 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexInRangeBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexInRangeBenchmark.java @@ -32,7 +32,7 @@ @State(Scope.Thread) @Warmup(iterations = 3, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 1, jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class IndexInRangeBenchmark { @Param({"7", "256", "259", "512"}) private int size; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexVectorBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexVectorBenchmark.java index 120ae94bd06ca..584e73c48865c 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexVectorBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexVectorBenchmark.java @@ -32,7 +32,7 @@ @State(Scope.Thread) @Warmup(iterations = 3, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 1, jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class IndexVectorBenchmark { @Param({"1024"}) private int size; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/LoadMaskedIOOBEBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/LoadMaskedIOOBEBenchmark.java index 869c98ef29f0e..52e64d8e0962b 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/LoadMaskedIOOBEBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/LoadMaskedIOOBEBenchmark.java @@ -32,7 +32,7 @@ @State(Scope.Thread) @Warmup(iterations = 3, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 1, jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class LoadMaskedIOOBEBenchmark { @Param({"1026"}) private int inSize; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskCastOperationsBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskCastOperationsBenchmark.java index 93871392f26e5..e277fd9114f18 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskCastOperationsBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskCastOperationsBenchmark.java @@ -30,7 +30,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class MaskCastOperationsBenchmark { VectorMask bmask64; VectorMask bmask128; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskFromLongBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskFromLongBenchmark.java index a7c73ea646087..ee0fadd6db8fc 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskFromLongBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskFromLongBenchmark.java @@ -29,7 +29,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class MaskFromLongBenchmark { private static final int ITERATION = 20000; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskQueryOperationsBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskQueryOperationsBenchmark.java index 373bd5017cc21..20537fe74f6aa 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskQueryOperationsBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskQueryOperationsBenchmark.java @@ -31,7 +31,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class MaskQueryOperationsBenchmark { @Param({"128","256","512"}) int bits; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.java index 97922c2f9ee7d..eb08aa38b8f48 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.java @@ -32,7 +32,7 @@ @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class MaskedLogicOpts { @Param({"256","512","1024"}) private int ARRAYLEN; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/MemorySegmentVectorAccess.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/MemorySegmentVectorAccess.java index 55248290f0e1b..a85ba440dce81 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/MemorySegmentVectorAccess.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/MemorySegmentVectorAccess.java @@ -48,7 +48,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 1, jvmArgsAppend = { +@Fork(value = 1, jvmArgs = { "--add-modules=jdk.incubator.vector", "--enable-native-access", "ALL-UNNAMED"}) public class MemorySegmentVectorAccess { diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/RearrangeBytesBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/RearrangeBytesBenchmark.java index daa15d41067ba..375ae9a03955f 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/RearrangeBytesBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/RearrangeBytesBenchmark.java @@ -32,7 +32,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class RearrangeBytesBenchmark { @Param({"256", "512", "1024"}) int size; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/RotateBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/RotateBenchmark.java index 3628479342a48..0ebf844e94b8c 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/RotateBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/RotateBenchmark.java @@ -32,7 +32,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class RotateBenchmark { @Param({"256","512"}) int size; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/SelectFromBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/SelectFromBenchmark.java new file mode 100644 index 0000000000000..1a370596c0807 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/SelectFromBenchmark.java @@ -0,0 +1,251 @@ +/* + * 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 org.openjdk.bench.jdk.incubator.vector; + +import java.util.Random; +import java.util.Arrays; +import jdk.incubator.vector.*; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) +public class SelectFromBenchmark { + @Param({"1024","2048"}) + int size; + + byte[] byteindex; + byte[] bytesrc1; + byte[] bytesrc2; + byte[] byteres; + + short[] shortindex; + short[] shortsrc1; + short[] shortsrc2; + short[] shortres; + + int[] intindex; + int[] intsrc1; + int[] intsrc2; + int[] intres; + + long[] longindex; + long[] longsrc1; + long[] longsrc2; + long[] longres; + + float[] floatindex; + float[] floatsrc1; + float[] floatsrc2; + float[] floatres; + + double[] doubleindex; + double[] doublesrc1; + double[] doublesrc2; + double[] doubleres; + + @Setup(Level.Trial) + public void BmSetup() { + Random r = new Random(1024); + byteindex = new byte[size]; + bytesrc1 = new byte[size]; + bytesrc2 = new byte[size]; + byteres = new byte[size]; + + shortindex = new short[size]; + shortsrc1 = new short[size]; + shortsrc2 = new short[size]; + shortres = new short[size]; + + intindex = new int[size]; + intsrc1 = new int[size]; + intsrc2 = new int[size]; + intres = new int[size]; + + longindex = new long[size]; + longsrc1 = new long[size]; + longsrc2 = new long[size]; + longres = new long[size]; + + floatindex = new float[size]; + floatsrc1 = new float[size]; + floatsrc2 = new float[size]; + floatres = new float[size]; + + doubleindex = new double[size]; + doublesrc1 = new double[size]; + doublesrc2 = new double[size]; + doubleres = new double[size]; + + Arrays.fill(bytesrc1, (byte)1); + Arrays.fill(bytesrc2, (byte)2); + + Arrays.fill(shortsrc1, (short)1); + Arrays.fill(shortsrc2, (short)2); + + Arrays.fill(intsrc1, 1); + Arrays.fill(intsrc2, 2); + + Arrays.fill(longsrc1, 1); + Arrays.fill(longsrc2, 2); + + Arrays.fill(floatsrc1, 1.0f); + Arrays.fill(floatsrc2, 2.0f); + + Arrays.fill(doublesrc1, 1.0); + Arrays.fill(doublesrc2, 2.0); + + for (int i = 0; i < size; i++) { + byteindex[i] = (byte)((ByteVector.SPECIES_PREFERRED.length() - 1) & i); + shortindex[i] = (short)((ShortVector.SPECIES_PREFERRED.length() - 1) & i); + intindex[i] = (int)((IntVector.SPECIES_PREFERRED.length() - 1) & i); + longindex[i] = (long)((LongVector.SPECIES_PREFERRED.length() - 1) & i); + floatindex[i] = (float)((FloatVector.SPECIES_PREFERRED.length() - 1) & i); + doubleindex[i] = (double)((DoubleVector.SPECIES_PREFERRED.length() - 1) & i); + } + } + + @Benchmark + public void selectFromByteVector() { + for (int j = 0; j < size; j += ByteVector.SPECIES_PREFERRED.length()) { + ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, byteindex, j) + .selectFrom(ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, bytesrc1, j), + ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, bytesrc2, j)) + .intoArray(byteres, j); + } + } + + @Benchmark + public void rearrangeFromByteVector() { + for (int j = 0; j < size; j += ByteVector.SPECIES_PREFERRED.length()) { + ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, bytesrc1, j) + .rearrange(ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, byteindex, j).toShuffle(), + ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, bytesrc2, j)) + .intoArray(byteres, j); + } + } + + @Benchmark + public void selectFromShortVector() { + for (int j = 0; j < size; j += ShortVector.SPECIES_PREFERRED.length()) { + ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortindex, j) + .selectFrom(ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortsrc1, j), + ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortsrc2, j)) + .intoArray(shortres, j); + } + } + + @Benchmark + public void rearrangeFromShortVector() { + for (int j = 0; j < size; j += ShortVector.SPECIES_PREFERRED.length()) { + ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortsrc1, j) + .rearrange(ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortindex, j).toShuffle(), + ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortsrc2, j)) + .intoArray(shortres, j); + } + } + + @Benchmark + public void selectFromIntVector() { + for (int j = 0; j < size; j += IntVector.SPECIES_PREFERRED.length()) { + IntVector.fromArray(IntVector.SPECIES_PREFERRED, intindex, j) + .selectFrom(IntVector.fromArray(IntVector.SPECIES_PREFERRED, intsrc1, j), + IntVector.fromArray(IntVector.SPECIES_PREFERRED, intsrc2, j)) + .intoArray(intres, j); + } + } + + @Benchmark + public void rearrangeFromIntVector() { + for (int j = 0; j < size; j += IntVector.SPECIES_PREFERRED.length()) { + IntVector.fromArray(IntVector.SPECIES_PREFERRED, intsrc1, j) + .rearrange(IntVector.fromArray(IntVector.SPECIES_PREFERRED, intindex, j).toShuffle(), + IntVector.fromArray(IntVector.SPECIES_PREFERRED, intsrc2, j)) + .intoArray(intres, j); + } + } + + @Benchmark + public void selectFromLongVector() { + for (int j = 0; j < size; j += LongVector.SPECIES_PREFERRED.length()) { + LongVector.fromArray(LongVector.SPECIES_PREFERRED, longindex, j) + .selectFrom(LongVector.fromArray(LongVector.SPECIES_PREFERRED, longsrc1, j), + LongVector.fromArray(LongVector.SPECIES_PREFERRED, longsrc2, j)) + .intoArray(longres, j); + } + } + + @Benchmark + public void rearrangeFromLongVector() { + for (int j = 0; j < size; j += LongVector.SPECIES_PREFERRED.length()) { + LongVector.fromArray(LongVector.SPECIES_PREFERRED, longsrc1, j) + .rearrange(LongVector.fromArray(LongVector.SPECIES_PREFERRED, longindex, j).toShuffle(), + LongVector.fromArray(LongVector.SPECIES_PREFERRED, longsrc2, j)) + .intoArray(longres, j); + } + } + + @Benchmark + public void selectFromFloatVector() { + for (int j = 0; j < size; j += FloatVector.SPECIES_PREFERRED.length()) { + FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatindex, j) + .selectFrom(FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatsrc1, j), + FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatsrc2, j)) + .intoArray(floatres, j); + } + } + + @Benchmark + public void rearrangeFromFloatVector() { + for (int j = 0; j < size; j += FloatVector.SPECIES_PREFERRED.length()) { + FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatsrc1, j) + .rearrange(FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatindex, j).toShuffle(), + FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatsrc2, j)) + .intoArray(floatres, j); + } + } + + @Benchmark + public void selectFromDoubleVector() { + for (int j = 0; j < size; j += DoubleVector.SPECIES_PREFERRED.length()) { + DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doubleindex, j) + .selectFrom(DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doublesrc1, j), + DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doublesrc2, j)) + .intoArray(doubleres, j); + } + } + + @Benchmark + public void rearrangeFromDoubleVector() { + for (int j = 0; j < size; j += DoubleVector.SPECIES_PREFERRED.length()) { + DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doublesrc1, j) + .rearrange(DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doubleindex, j).toShuffle(), + DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doublesrc2, j)) + .intoArray(doubleres, j); + } + } +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskTrueCount.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskTrueCount.java index 372edd0cfb52d..db9f7cf1028ad 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskTrueCount.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskTrueCount.java @@ -30,7 +30,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class StoreMaskTrueCount { private static final VectorSpecies S_SPECIES = ShortVector.SPECIES_PREFERRED; private static final VectorSpecies I_SPECIES = IntVector.SPECIES_PREFERRED; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskedBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskedBenchmark.java index e5c21527e4afc..626de9b898ca5 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskedBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskedBenchmark.java @@ -32,7 +32,7 @@ @State(Scope.Thread) @Warmup(iterations = 3, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 1, jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class StoreMaskedBenchmark { @Param({"1024"}) private int size; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskedIOOBEBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskedIOOBEBenchmark.java index 1855338552e12..241bd081d3a2d 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskedIOOBEBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/StoreMaskedIOOBEBenchmark.java @@ -31,7 +31,7 @@ @State(Scope.Thread) @Warmup(iterations = 3, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 1, jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class StoreMaskedIOOBEBenchmark { @Param({"1024"}) private int inSize; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadSegmentVarious.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadSegmentVarious.java index 5ec17c26ca5dd..53564edab2d8b 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadSegmentVarious.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadSegmentVarious.java @@ -46,7 +46,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 1, jvmArgsAppend = { +@Fork(value = 1, jvmArgs = { "--add-modules=jdk.incubator.vector", "--enable-native-access", "ALL-UNNAMED"}) public class TestLoadSegmentVarious { diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreBytes.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreBytes.java index 3ea1943e70317..feac109230ad6 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreBytes.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreBytes.java @@ -47,7 +47,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 1, jvmArgsAppend = { +@Fork(value = 1, jvmArgs = { "--add-modules=jdk.incubator.vector", "--enable-native-access", "ALL-UNNAMED", "-Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=1"}) diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreShorts.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreShorts.java index d6c6531d3f895..842313357bd97 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreShorts.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreShorts.java @@ -50,7 +50,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 1, jvmArgsAppend = { +@Fork(value = 1, jvmArgs = { "--add-modules=jdk.incubator.vector", "--enable-native-access", "ALL-UNNAMED"}) public class TestLoadStoreShorts { diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java index 4715cdb08ba04..6358cb0a5d493 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java @@ -28,7 +28,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class VectorExtractBenchmark { private int idx = 0; private boolean[] res = new boolean[8]; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorFPtoIntCastOperations.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorFPtoIntCastOperations.java index b66fc9646a05d..35069af60f6df 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorFPtoIntCastOperations.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorFPtoIntCastOperations.java @@ -31,7 +31,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class VectorFPtoIntCastOperations { @Param({"512", "1024"}) static int SIZE; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorZeroExtend.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorZeroExtend.java index 503d80356da96..e250ddd900848 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorZeroExtend.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorZeroExtend.java @@ -32,7 +32,7 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class VectorZeroExtend { private static final VectorSpecies B_SPECIES = ByteVector.SPECIES_PREFERRED; private static final VectorSpecies S_SPECIES = ShortVector.SPECIES_PREFERRED; diff --git a/test/micro/org/openjdk/bench/jdk/preview/patterns/Exactness.java b/test/micro/org/openjdk/bench/jdk/preview/patterns/Exactness.java index 675f5bda3980f..34971ccf93a32 100644 --- a/test/micro/org/openjdk/bench/jdk/preview/patterns/Exactness.java +++ b/test/micro/org/openjdk/bench/jdk/preview/patterns/Exactness.java @@ -35,7 +35,7 @@ @Measurement(iterations=5, time=1) @Threads(2) @Fork(value = 1, - jvmArgsPrepend = {"-Djmh.blackhole.mode=COMPILER", + jvmArgs = {"-Djmh.blackhole.mode=COMPILER", "--enable-preview"}) @State(Scope.Thread) @SuppressWarnings("preview") diff --git a/test/micro/org/openjdk/bench/vm/compiler/AllocationMerges.java b/test/micro/org/openjdk/bench/vm/compiler/AllocationMerges.java index 84c6c5c6483f6..b4b833cd95a40 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/AllocationMerges.java +++ b/test/micro/org/openjdk/bench/vm/compiler/AllocationMerges.java @@ -1194,7 +1194,7 @@ public void testString_two_caller(Blackhole bh) { // ------------------ Utility for Benchmarking ------------------- // - @Fork(value = 3, jvmArgsPrepend = { + @Fork(value = 3, jvmArgs = { "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseTLAB", "-XX:-ReduceAllocationMerges", @@ -1202,7 +1202,7 @@ public void testString_two_caller(Blackhole bh) { public static class NopRAM extends AllocationMerges { } - @Fork(value = 3, jvmArgsPrepend = { + @Fork(value = 3, jvmArgs = { "-XX:+UnlockDiagnosticVMOptions", "-XX:+ReduceAllocationMerges", }) diff --git a/test/micro/org/openjdk/bench/vm/compiler/ClearMemory.java b/test/micro/org/openjdk/bench/vm/compiler/ClearMemory.java index f70b4aa734ac0..434805875c19a 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/ClearMemory.java +++ b/test/micro/org/openjdk/bench/vm/compiler/ClearMemory.java @@ -38,7 +38,7 @@ import java.util.concurrent.TimeUnit; -@Fork(value = 3, jvmArgsPrepend = {"-XX:-EliminateAllocations", "-XX:-DoEscapeAnalysis"}) +@Fork(value = 3, jvmArgs = {"-XX:-EliminateAllocations", "-XX:-DoEscapeAnalysis"}) @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) diff --git a/test/micro/org/openjdk/bench/vm/compiler/ConstructorBarriers.java b/test/micro/org/openjdk/bench/vm/compiler/ConstructorBarriers.java index 7adbbe0e1a71e..83dc38552fa36 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/ConstructorBarriers.java +++ b/test/micro/org/openjdk/bench/vm/compiler/ConstructorBarriers.java @@ -41,7 +41,7 @@ @State(Scope.Thread) @Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) -@Fork(value = 3, jvmArgsAppend = {"-Xms512m", "-Xmx512m", "-XX:+AlwaysPreTouch", "-XX:+UseParallelGC"}) +@Fork(value = 3, jvmArgs = {"-Xms512m", "-Xmx512m", "-XX:+AlwaysPreTouch", "-XX:+UseParallelGC"}) public class ConstructorBarriers { // Checks the barrier coalescing/optimization around field initializations. diff --git a/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java b/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java index 7ccc91901de55..7e8800a3fbe72 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java +++ b/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java @@ -64,7 +64,7 @@ public void setupTrial() { @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) - @Fork(value=3, jvmArgsAppend={"-XX:TieredStopAtLevel=1"}) + @Fork(value=3, jvmArgs={"-XX:TieredStopAtLevel=1"}) public void invokePrivateInterfaceMethodC1() { for (int i = 0; i < objs.length; ++i) { objs[i].foo(); diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java index 26c8287c4de67..870422de25683 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java @@ -43,7 +43,7 @@ @State(Scope.Thread) @Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgsAppend = {"--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"}) +@Fork(value = 3, jvmArgs = {"--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"}) public class MergeStoreBench { private static final Unsafe UNSAFE = Unsafe.getUnsafe(); diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java index 84017573c075b..93d98116ecc5f 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java @@ -43,7 +43,7 @@ @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 3, time = 3) @Measurement(iterations = 3, time = 3) -@Fork(value = 3, jvmArgsAppend = { +@Fork(value = 3, jvmArgs = { "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.util=ALL-UNNAMED"}) @State(Scope.Benchmark) diff --git a/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheHits.java b/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheHits.java index aaaf0edb25804..69eaf87536301 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheHits.java +++ b/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheHits.java @@ -30,7 +30,7 @@ @Warmup(iterations = 5, time = 300, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 5, time = 300, timeUnit = TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgsAppend = {"-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1"}) +@Fork(value = 3, jvmArgs = {"-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1"}) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Threads(1) diff --git a/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheInterContention.java b/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheInterContention.java index 3cafa582c0950..03c6d75607bf6 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheInterContention.java +++ b/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheInterContention.java @@ -30,7 +30,7 @@ @Warmup(iterations = 5, time = 300, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 5, time = 300, timeUnit = TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgsAppend = {"-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1"}) +@Fork(value = 3, jvmArgs = {"-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1"}) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Threads(Threads.MAX) diff --git a/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheIntraContention.java b/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheIntraContention.java index b97d49e2e606f..3c30c69a864ac 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheIntraContention.java +++ b/test/micro/org/openjdk/bench/vm/compiler/SecondarySuperCacheIntraContention.java @@ -30,7 +30,7 @@ @Warmup(iterations = 5, time = 300, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 5, time = 300, timeUnit = TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgsAppend = {"-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1"}) +@Fork(value = 3, jvmArgs = {"-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1"}) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Threads(Threads.MAX) diff --git a/test/micro/org/openjdk/bench/vm/compiler/SubIdealC0Minus_YPlusC1_.java b/test/micro/org/openjdk/bench/vm/compiler/SubIdealC0Minus_YPlusC1_.java index 17728f6bc2589..5ac4e58dce6bf 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/SubIdealC0Minus_YPlusC1_.java +++ b/test/micro/org/openjdk/bench/vm/compiler/SubIdealC0Minus_YPlusC1_.java @@ -47,7 +47,7 @@ @State(Scope.Thread) @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@Fork(value = 3 , jvmArgsAppend = {"-XX:-TieredCompilation", "-Xbatch", "-Xcomp"}) +@Fork(value = 3 , jvmArgs = {"-XX:-TieredCompilation", "-Xbatch", "-Xcomp"}) public class SubIdealC0Minus_YPlusC1_ { private static final int I_C0 = 1234567; diff --git a/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java b/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java index a3e4445664ce9..c39107fdd006a 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java +++ b/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java @@ -382,7 +382,7 @@ public void andZ() { } @Benchmark - @Fork(jvmArgsPrepend = {"-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov"}) + @Fork(jvmArgs = {"-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov"}) public void cmoveD() { for (int i = 0; i < COUNT; i++) { resD[i] = resD[i] < doubles[i] ? resD[i] : doubles[i]; @@ -390,21 +390,21 @@ public void cmoveD() { } @Benchmark - @Fork(jvmArgsPrepend = {"-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov"}) + @Fork(jvmArgs = {"-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov"}) public void cmoveF() { for (int i = 0; i < COUNT; i++) { resF[i] = resF[i] < floats[i] ? resF[i] : floats[i]; } } - @Fork(value = 2, jvmArgsPrepend = { + @Fork(value = 2, jvmArgs = { "-XX:+UseSuperWord" }) public static class TypeVectorOperationsSuperWord extends TypeVectorOperations { } - @Fork(value = 2, jvmArgsPrepend = { + @Fork(value = 2, jvmArgs = { "-XX:-UseSuperWord" }) public static class TypeVectorOperationsNonSuperWord extends TypeVectorOperations { diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAlignment.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAlignment.java index 7fff4952c8efe..1d684260d89fb 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorAlignment.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAlignment.java @@ -293,22 +293,22 @@ public void bench401_hand_unrolled_misaligned() { } } - @Fork(value = 1, jvmArgsPrepend = { + @Fork(value = 1, jvmArgs = { "-XX:+UseSuperWord", "-XX:CompileCommand=Option,*::*,Vectorize" }) public static class VectorAlignmentSuperWordWithVectorize extends VectorAlignment {} - @Fork(value = 1, jvmArgsPrepend = { + @Fork(value = 1, jvmArgs = { "-XX:+UseSuperWord", "-XX:+AlignVector" }) public static class VectorAlignmentSuperWordAlignVector extends VectorAlignment {} - @Fork(value = 1, jvmArgsPrepend = { + @Fork(value = 1, jvmArgs = { "-XX:+UseSuperWord" }) public static class VectorAlignmentSuperWord extends VectorAlignment {} - @Fork(value = 1, jvmArgsPrepend = { + @Fork(value = 1, jvmArgs = { "-XX:-UseSuperWord" }) public static class VectorAlignmentNoSuperWord extends VectorAlignment {} diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorBitCount.java b/test/micro/org/openjdk/bench/vm/compiler/VectorBitCount.java index 49b644a64f158..cfb37b71caf37 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorBitCount.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorBitCount.java @@ -72,14 +72,14 @@ public int[] longBitCount() { } - @Fork(value = 2, jvmArgsPrepend = { + @Fork(value = 2, jvmArgs = { "-XX:+UseSuperWord" }) public static class WithSuperword extends VectorBitCount { } - @Fork(value = 2, jvmArgsPrepend = { + @Fork(value = 2, jvmArgs = { "-XX:-UseSuperWord" }) public static class NoSuperword extends VectorBitCount { diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorLoadToStoreForwarding.java b/test/micro/org/openjdk/bench/vm/compiler/VectorLoadToStoreForwarding.java index efbf99c6ce5e1..1aed0fc332129 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorLoadToStoreForwarding.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorLoadToStoreForwarding.java @@ -200,12 +200,12 @@ public void benchmark_20() { } } - @Fork(value = 1, jvmArgsPrepend = { + @Fork(value = 1, jvmArgs = { "-XX:+UseSuperWord" }) public static class VectorLoadToStoreForwardingSuperWord extends VectorLoadToStoreForwarding {} - @Fork(value = 1, jvmArgsPrepend = { + @Fork(value = 1, jvmArgs = { "-XX:-UseSuperWord" }) public static class VectorLoadToStoreForwardingNoSuperWord extends VectorLoadToStoreForwarding {} diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorReduction.java b/test/micro/org/openjdk/bench/vm/compiler/VectorReduction.java index 9b293b6b7e5c7..1507dd211e663 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorReduction.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorReduction.java @@ -176,14 +176,14 @@ public void andRedIOnGlobalAccumulator() { } } - @Fork(value = 2, jvmArgsPrepend = { + @Fork(value = 2, jvmArgs = { "-XX:+UseSuperWord" }) public static class WithSuperword extends VectorReduction { } - @Fork(value = 2, jvmArgsPrepend = { + @Fork(value = 2, jvmArgs = { "-XX:-UseSuperWord" }) public static class NoSuperword extends VectorReduction { diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorReduction2.java b/test/micro/org/openjdk/bench/vm/compiler/VectorReduction2.java index 5ec34a0423f62..ec614cb324bc2 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorReduction2.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorReduction2.java @@ -1445,10 +1445,10 @@ public void doubleMaxBig(Blackhole bh) { bh.consume(acc); } - @Fork(value = 1, jvmArgsPrepend = {"-XX:+UseSuperWord"}) + @Fork(value = 1, jvmArgs = {"-XX:+UseSuperWord"}) public static class WithSuperword extends VectorReduction2 {} - @Fork(value = 1, jvmArgsPrepend = {"-XX:-UseSuperWord"}) + @Fork(value = 1, jvmArgs = {"-XX:-UseSuperWord"}) public static class NoSuperword extends VectorReduction2 {} } diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorReductionFloatingMinMax.java b/test/micro/org/openjdk/bench/vm/compiler/VectorReductionFloatingMinMax.java index d25d22f12b168..870164b8050e7 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorReductionFloatingMinMax.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorReductionFloatingMinMax.java @@ -69,7 +69,7 @@ public void init() { } @Benchmark - @Fork(jvmArgsPrepend = {"-XX:-SuperWordLoopUnrollAnalysis"}) + @Fork(jvmArgs = {"-XX:-SuperWordLoopUnrollAnalysis"}) public void maxRedF(Blackhole bh) { float max = 0.0f; for (int i = 0; i < COUNT_FLOAT; i++) { @@ -79,7 +79,7 @@ public void maxRedF(Blackhole bh) { } @Benchmark - @Fork(jvmArgsPrepend = {"-XX:-SuperWordLoopUnrollAnalysis"}) + @Fork(jvmArgs = {"-XX:-SuperWordLoopUnrollAnalysis"}) public void minRedF(Blackhole bh) { float min = 0.0f; for (int i = 0; i < COUNT_FLOAT; i++) { diff --git a/test/micro/org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.java b/test/micro/org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.java index 0605050ed2a77..9538e13df2d9c 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.java +++ b/test/micro/org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.java @@ -52,25 +52,25 @@ public class SimpleRepeatCompilation { = "-XX:CompileCommand=option,org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.mixHashCode,intx,RepeatCompilation,500"; @Benchmark - @Fork(jvmArgsAppend={"-Xbatch", MIXHASH_METHOD}) + @Fork(jvmArgs={"-Xbatch", MIXHASH_METHOD}) public int mixHashCode_repeat() { return loop_hashCode(); } @Benchmark - @Fork(jvmArgsAppend={"-Xbatch", "-XX:-TieredCompilation", MIXHASH_METHOD}) + @Fork(jvmArgs={"-Xbatch", "-XX:-TieredCompilation", MIXHASH_METHOD}) public int mixHashCode_repeat_c2() { return loop_hashCode(); } @Benchmark - @Fork(jvmArgsAppend={"-Xbatch", "-XX:TieredStopAtLevel=1", MIXHASH_METHOD}) + @Fork(jvmArgs={"-Xbatch", "-XX:TieredStopAtLevel=1", MIXHASH_METHOD}) public int mixHashCode_repeat_c1() { return loop_hashCode(); } @Benchmark - @Fork(jvmArgsAppend={"-Xbatch"}) + @Fork(jvmArgs={"-Xbatch"}) public int mixHashCode_baseline() { return loop_hashCode(); } @@ -95,25 +95,25 @@ public int mixHashCode(String value) { = "-XX:CompileCommand=option,org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.trivialMath,intx,RepeatCompilation,2000"; @Benchmark - @Fork(jvmArgsAppend={"-Xbatch",TRIVIAL_MATH_METHOD}) + @Fork(jvmArgs={"-Xbatch",TRIVIAL_MATH_METHOD}) public int trivialMath_repeat() { return loop_trivialMath(); } @Benchmark - @Fork(jvmArgsAppend={"-Xbatch", "-XX:-TieredCompilation", TRIVIAL_MATH_METHOD}) + @Fork(jvmArgs={"-Xbatch", "-XX:-TieredCompilation", TRIVIAL_MATH_METHOD}) public int trivialMath_repeat_c2() { return loop_trivialMath(); } @Benchmark - @Fork(jvmArgsAppend={"-Xbatch", "-XX:TieredStopAtLevel=1", TRIVIAL_MATH_METHOD}) + @Fork(jvmArgs={"-Xbatch", "-XX:TieredStopAtLevel=1", TRIVIAL_MATH_METHOD}) public int trivialMath_repeat_c1() { return loop_trivialMath(); } @Benchmark - @Fork(jvmArgsAppend={"-Xbatch"}) + @Fork(jvmArgs={"-Xbatch"}) public int trivialMath_baseline() { return loop_trivialMath(); } @@ -135,25 +135,25 @@ public int trivialMath(int a, int b) { = "-XX:CompileCommand=option,org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.largeMethod,intx,RepeatCompilation,100"; @Benchmark - @Fork(jvmArgsAppend={"-Xbatch",LARGE_METHOD}) + @Fork(jvmArgs={"-Xbatch",LARGE_METHOD}) public int largeMethod_repeat() { return loop_largeMethod(); } @Benchmark - @Fork(jvmArgsAppend={"-Xbatch", "-XX:-TieredCompilation", LARGE_METHOD}) + @Fork(jvmArgs={"-Xbatch", "-XX:-TieredCompilation", LARGE_METHOD}) public int largeMethod_repeat_c2() { return loop_largeMethod(); } @Benchmark - @Fork(jvmArgsAppend={"-Xbatch", "-XX:TieredStopAtLevel=1", LARGE_METHOD}) + @Fork(jvmArgs={"-Xbatch", "-XX:TieredStopAtLevel=1", LARGE_METHOD}) public int largeMethod_repeat_c1() { return loop_largeMethod(); } @Benchmark - @Fork(jvmArgsAppend={"-Xbatch"}) + @Fork(jvmArgs={"-Xbatch"}) public int largeMethod_baseline() { return loop_largeMethod(); } diff --git a/test/micro/org/openjdk/bench/vm/compiler/x86/BasicRules.java b/test/micro/org/openjdk/bench/vm/compiler/x86/BasicRules.java index 4b04e168f162e..fa13fae42cc86 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/x86/BasicRules.java +++ b/test/micro/org/openjdk/bench/vm/compiler/x86/BasicRules.java @@ -31,7 +31,7 @@ @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Thread) -@Fork(value = 3, jvmArgsAppend = "-XX:-UseSuperWord") +@Fork(value = 3, jvmArgs = "-XX:-UseSuperWord") @Warmup(time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(time = 1, timeUnit = TimeUnit.SECONDS) public class BasicRules { diff --git a/test/micro/org/openjdk/bench/vm/compiler/x86/ConvertF2I.java b/test/micro/org/openjdk/bench/vm/compiler/x86/ConvertF2I.java index 406da5f65e54e..dd807532e7251 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/x86/ConvertF2I.java +++ b/test/micro/org/openjdk/bench/vm/compiler/x86/ConvertF2I.java @@ -31,7 +31,7 @@ @State(Scope.Thread) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 1, jvmArgsAppend = {"-XX:-UseSuperWord"}) +@Fork(value = 1, jvmArgs = {"-XX:-UseSuperWord"}) public class ConvertF2I { static final int LENGTH = 1000; int[] intArray = new int[LENGTH]; diff --git a/test/micro/org/openjdk/bench/vm/compiler/x86/LeaInstruction.java b/test/micro/org/openjdk/bench/vm/compiler/x86/LeaInstruction.java index f4cd27a5dd4ca..fb4be3ec45487 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/x86/LeaInstruction.java +++ b/test/micro/org/openjdk/bench/vm/compiler/x86/LeaInstruction.java @@ -29,7 +29,7 @@ @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 2, jvmArgsAppend = {"-XX:LoopUnrollLimit=1"}) +@Fork(value = 2, jvmArgs = {"-XX:LoopUnrollLimit=1"}) @Warmup(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) @State(Scope.Thread) diff --git a/test/micro/org/openjdk/bench/vm/fences/SafePublishing.java b/test/micro/org/openjdk/bench/vm/fences/SafePublishing.java index e18564c4c3a75..d5b1ae2487257 100644 --- a/test/micro/org/openjdk/bench/vm/fences/SafePublishing.java +++ b/test/micro/org/openjdk/bench/vm/fences/SafePublishing.java @@ -30,7 +30,7 @@ @Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) -@Fork(value = 3, jvmArgsAppend = {"-XX:+UseParallelGC", "-Xmx128m"}) +@Fork(value = 3, jvmArgs = {"-XX:+UseParallelGC", "-Xmx128m"}) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Thread) diff --git a/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java b/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java index 67702cfe60747..66044f8249d8b 100644 --- a/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java +++ b/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java @@ -29,7 +29,7 @@ @OutputTimeUnit(TimeUnit.MINUTES) @State(Scope.Thread) -@Fork(jvmArgsAppend = {"-Xmx256m", "-XX:+UseLargePages", "-XX:LargePageSizeInBytes=1g", "-Xlog:pagesize"}, value = 5) +@Fork(jvmArgs = {"-Xmx256m", "-XX:+UseLargePages", "-XX:LargePageSizeInBytes=1g", "-Xlog:pagesize"}, value = 5) public class MicroLargePages { diff --git a/test/micro/org/openjdk/bench/vm/gc/RawAllocationRate.java b/test/micro/org/openjdk/bench/vm/gc/RawAllocationRate.java index 4faf3e19535d4..a0987ddd8d83e 100644 --- a/test/micro/org/openjdk/bench/vm/gc/RawAllocationRate.java +++ b/test/micro/org/openjdk/bench/vm/gc/RawAllocationRate.java @@ -80,7 +80,7 @@ public Object[] arrayTest() { } @Benchmark - @Fork(jvmArgsAppend={"-XX:TieredStopAtLevel=1"}) + @Fork(jvmArgs={"-XX:TieredStopAtLevel=1"}) public Object[] arrayTest_C1() { return arrayTest(); } @@ -106,7 +106,7 @@ public Object[] instanceTest() { } @Benchmark - @Fork(jvmArgsAppend={"-XX:TieredStopAtLevel=1"}) + @Fork(jvmArgs={"-XX:TieredStopAtLevel=1"}) public Object[] instanceTest_C1() { return instanceTest(); } diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/AllDead.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/AllDead.java index 12e1ff25454e8..6e41ec0610e75 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/AllDead.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/AllDead.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class AllDead { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/AllLive.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/AllLive.java index ddd9f56cf6022..2a2bf06083339 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/AllLive.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/AllLive.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class AllLive { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesArray.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesArray.java index a4dcfdaaeb594..4de7c4a8f84de 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesArray.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesArray.java @@ -35,7 +35,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class DifferentObjectSizesArray { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesHashMap.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesHashMap.java index 839147251611a..960223f503591 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesHashMap.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesHashMap.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class DifferentObjectSizesHashMap { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesTreeMap.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesTreeMap.java index 66aaffff693a2..d1fea505ac058 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesTreeMap.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/DifferentObjectSizesTreeMap.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class DifferentObjectSizesTreeMap { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadFirstPart.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadFirstPart.java index 80cefbfe10f86..339e31d7032f0 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadFirstPart.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadFirstPart.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class HalfDeadFirstPart { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadInterleaved.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadInterleaved.java index bda9ccfa2135b..07eda82f2c98c 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadInterleaved.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadInterleaved.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class HalfDeadInterleaved { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadInterleavedChunks.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadInterleavedChunks.java index 06955381f5ca9..a5d6dce91a974 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadInterleavedChunks.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadInterleavedChunks.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class HalfDeadInterleavedChunks { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadSecondPart.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadSecondPart.java index 89606f5a07a99..838aeb4820b25 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadSecondPart.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfDeadSecondPart.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class HalfDeadSecondPart { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfHashedHalfDead.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfHashedHalfDead.java index 6692e02a13576..eaba46e04e96b 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfHashedHalfDead.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/HalfHashedHalfDead.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class HalfHashedHalfDead { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/NoObjects.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/NoObjects.java index a2e35e550611c..96461c8106cd3 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/NoObjects.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/NoObjects.java @@ -31,7 +31,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class NoObjects { diff --git a/test/micro/org/openjdk/bench/vm/gc/systemgc/OneBigObject.java b/test/micro/org/openjdk/bench/vm/gc/systemgc/OneBigObject.java index 5601abdcb709e..ef2c436efd705 100644 --- a/test/micro/org/openjdk/bench/vm/gc/systemgc/OneBigObject.java +++ b/test/micro/org/openjdk/bench/vm/gc/systemgc/OneBigObject.java @@ -35,7 +35,7 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.SingleShotTime) -@Fork(value=25, jvmArgsAppend={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) +@Fork(value=25, jvmArgs={"-Xmx5g", "-Xms5g", "-Xmn3g", "-XX:+AlwaysPreTouch"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class OneBigObject { diff --git a/test/micro/org/openjdk/bench/vm/lang/TypePollution.java b/test/micro/org/openjdk/bench/vm/lang/TypePollution.java index aa1a020758783..4994bcf9c2d87 100644 --- a/test/micro/org/openjdk/bench/vm/lang/TypePollution.java +++ b/test/micro/org/openjdk/bench/vm/lang/TypePollution.java @@ -105,28 +105,28 @@ public void setup() { int probe = 99; @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) + @Fork(jvmArgs={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) public long parallelInstanceOfInterfaceSwitchLinearNoSCC() { return parallelInstanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) + @Fork(jvmArgs={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) public long parallelInstanceOfInterfaceSwitchLinearSCC() { return parallelInstanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) + @Fork(jvmArgs={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) public long parallelInstanceOfInterfaceSwitchTableNoSCC() { return parallelInstanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) + @Fork(jvmArgs={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) public long parallelInstanceOfInterfaceSwitchTableSCC() { return parallelInstanceOfInterfaceSwitch(); @@ -149,25 +149,25 @@ long parallelInstanceOfInterfaceSwitch() { } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) + @Fork(jvmArgs={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) public int instanceOfInterfaceSwitchLinearNoSCC() { return instanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) + @Fork(jvmArgs={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) public int instanceOfInterfaceSwitchLinearSCC() { return instanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) + @Fork(jvmArgs={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) public int instanceOfInterfaceSwitchTableNoSCC() { return instanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) + @Fork(jvmArgs={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) public int instanceOfInterfaceSwitchTableSCC() { return instanceOfInterfaceSwitch(); } diff --git a/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark.java b/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark.java index 8d05d37792cdf..d88c66bd15f90 100644 --- a/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark.java +++ b/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark.java @@ -243,12 +243,12 @@ public void mixAllocateReallocateMemory() throws InterruptedException { public static final String ADD_EXPORTS = "--add-exports"; public static final String MISC_PACKAGE = "java.base/jdk.internal.misc=ALL-UNNAMED"; // used for Unsafe API - @Fork(value = 2, jvmArgsPrepend = { "-XX:NativeMemoryTracking=off", ADD_EXPORTS, MISC_PACKAGE}) + @Fork(value = 2, jvmArgs = { "-XX:NativeMemoryTracking=off", ADD_EXPORTS, MISC_PACKAGE}) public static class NMTOff extends NMTBenchmark { } - @Fork(value = 2, jvmArgsPrepend = { "-XX:NativeMemoryTracking=summary", ADD_EXPORTS, MISC_PACKAGE}) + @Fork(value = 2, jvmArgs = { "-XX:NativeMemoryTracking=summary", ADD_EXPORTS, MISC_PACKAGE}) public static class NMTSummary extends NMTBenchmark { } - @Fork(value = 2, jvmArgsPrepend = { "-XX:NativeMemoryTracking=detail", ADD_EXPORTS, MISC_PACKAGE}) + @Fork(value = 2, jvmArgs = { "-XX:NativeMemoryTracking=detail", ADD_EXPORTS, MISC_PACKAGE}) public static class NMTDetail extends NMTBenchmark { } } diff --git a/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark_wb.java b/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark_wb.java index 12e7a1140c8f5..059fff9f2ee21 100644 --- a/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark_wb.java +++ b/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark_wb.java @@ -137,13 +137,13 @@ public void virtualMemoryTests() { public static final String WB_JAR_APPEND = "-Xbootclasspath/a:lib-test/wb.jar"; - @Fork(value = 2, jvmArgsPrepend = { WB_JAR_APPEND, WB_UNLOCK_OPTION, WB_API, ADD_EXPORTS, MISC_PACKAGE, "-XX:NativeMemoryTracking=off"}) + @Fork(value = 2, jvmArgs = { WB_JAR_APPEND, WB_UNLOCK_OPTION, WB_API, ADD_EXPORTS, MISC_PACKAGE, "-XX:NativeMemoryTracking=off"}) public static class NMTOff extends NMTBenchmark_wb { } - @Fork(value = 2, jvmArgsPrepend = { WB_JAR_APPEND, WB_UNLOCK_OPTION, WB_API, ADD_EXPORTS, MISC_PACKAGE, "-XX:NativeMemoryTracking=summary"}) + @Fork(value = 2, jvmArgs = { WB_JAR_APPEND, WB_UNLOCK_OPTION, WB_API, ADD_EXPORTS, MISC_PACKAGE, "-XX:NativeMemoryTracking=summary"}) public static class NMTSummary extends NMTBenchmark_wb { } - // @Fork(value = 2, jvmArgsPrepend = { WB_JAR_APPEND, WB_UNLOCK_OPTION, WB_API, ADD_EXPORTS, MISC_PACKAGE, "-XX:NativeMemoryTracking=detail"}) + // @Fork(value = 2, jvmArgs = { WB_JAR_APPEND, WB_UNLOCK_OPTION, WB_API, ADD_EXPORTS, MISC_PACKAGE, "-XX:NativeMemoryTracking=detail"}) // public static class NMTDetail extends NMTBenchmark_wb { } } \ No newline at end of file

    Shows how FormatType and FormatStyle values map to Format instances